Skip to content

Commit

Permalink
fix: make default value be set only for explicitly marked editors
Browse files Browse the repository at this point in the history
  • Loading branch information
tpluscode committed Nov 16, 2022
1 parent c337f03 commit c7b4315
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 44 deletions.
5 changes: 5 additions & 0 deletions .changeset/shy-kiwis-wash.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@hydrofoil/shaperone-core": patch
---

It should be explicitly configurable which editors generate a default node without `sh:defaultValue` property. By default, only `dash:DetailsEditor` does
91 changes: 61 additions & 30 deletions packages/core-tests/models/resources/lib/objectValue.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { describe, it } from 'mocha'
import { expect } from 'chai'
import cf from 'clownface'
import cf, { AnyContext, AnyPointer } from 'clownface'
import $rdf from 'rdf-ext'
import { literal } from '@rdf-esm/data-model'
import { xsd, rdf, foaf, dash, sh } from '@tpluscode/rdf-ns-builders'
Expand All @@ -9,8 +9,17 @@ import { defaultValue } from '@hydrofoil/shaperone-core/models/resources/lib/obj
import { propertyShape } from '@shaperone/testing/util.js'
import { Term } from 'rdf-js'
import sh1 from '@hydrofoil/shaperone-core/ns.js'
import { ex } from '@shaperone/testing'
import DatasetExt from 'rdf-ext/lib/Dataset'
import CoreMetadata from '@hydrofoil/shaperone-core/metadata.js'

describe('core/models/resources/lib/defaultValue', () => {
let editorMeta: AnyPointer<AnyContext, DatasetExt>

beforeEach(() => {
editorMeta = cf({ dataset: $rdf.dataset() })
})

it('returns default value from property', () => {
// given
const graph = cf({ dataset: $rdf.dataset() })
Expand All @@ -20,7 +29,7 @@ describe('core/models/resources/lib/defaultValue', () => {
const focusNode = graph.blankNode()

// when
const pointer = defaultValue({ property, focusNode, nodeKind: undefined })
const pointer = defaultValue({ property, focusNode, nodeKind: undefined, editorMeta })

// then
expect(pointer?.term).to.deep.eq(literal('foo', xsd.anySimpleType))
Expand All @@ -34,7 +43,7 @@ describe('core/models/resources/lib/defaultValue', () => {
const focusNode = graph.blankNode()

// when
const pointer = defaultValue({ property, focusNode, nodeKind: undefined })
const pointer = defaultValue({ property, focusNode, nodeKind: undefined, editorMeta })

// then
expect(pointer).to.be.null
Expand All @@ -49,7 +58,7 @@ describe('core/models/resources/lib/defaultValue', () => {
const focusNode = graph.blankNode()

// when
const pointer = defaultValue({ property, focusNode, nodeKind: undefined })
const pointer = defaultValue({ property, focusNode, nodeKind: undefined, editorMeta })

// then
expect(pointer?.term?.termType).to.eq('BlankNode')
Expand All @@ -65,7 +74,7 @@ describe('core/models/resources/lib/defaultValue', () => {
const focusNode = graph.blankNode()

// when
const pointer = defaultValue({ property, focusNode, nodeKind: undefined })
const pointer = defaultValue({ property, focusNode, nodeKind: undefined, editorMeta })

// then
expect(pointer).to.be.null
Expand All @@ -80,8 +89,8 @@ describe('core/models/resources/lib/defaultValue', () => {
const focusNode = graph.blankNode()

// when
const first = defaultValue({ property, focusNode, nodeKind: undefined })
const second = defaultValue({ property, focusNode, nodeKind: undefined })
const first = defaultValue({ property, focusNode, nodeKind: undefined, editorMeta })
const second = defaultValue({ property, focusNode, nodeKind: undefined, editorMeta })

// then
expect(first?.term).not.to.deep.eq(second)
Expand All @@ -97,7 +106,7 @@ describe('core/models/resources/lib/defaultValue', () => {
const focusNode = graph.blankNode()

// when
const term = defaultValue({ property, focusNode, nodeKind: undefined })?.term
const term = defaultValue({ property, focusNode, nodeKind: undefined, editorMeta })?.term

// then
expect(term?.termType).to.eq('NamedNode')
Expand All @@ -114,7 +123,7 @@ describe('core/models/resources/lib/defaultValue', () => {
const focusNode = graph.blankNode()

// when
const term = defaultValue({ property, focusNode, nodeKind: undefined })?.term
const term = defaultValue({ property, focusNode, nodeKind: undefined, editorMeta })?.term

// then
expect(term?.termType).to.eq('NamedNode')
Expand All @@ -131,7 +140,7 @@ describe('core/models/resources/lib/defaultValue', () => {
const focusNode = graph.blankNode()

// when
const term = defaultValue({ property, focusNode, nodeKind: undefined })?.term
const term = defaultValue({ property, focusNode, nodeKind: undefined, editorMeta })?.term

// then
expect(term?.termType).to.eq('NamedNode')
Expand All @@ -148,7 +157,7 @@ describe('core/models/resources/lib/defaultValue', () => {
const focusNode = graph.blankNode()

// when
const term = defaultValue({ property, focusNode, nodeKind: sh.BlankNode })?.term
const term = defaultValue({ property, focusNode, nodeKind: sh.BlankNode, editorMeta })?.term

// then
expect(term?.termType).to.eq('BlankNode')
Expand All @@ -171,7 +180,7 @@ describe('core/models/resources/lib/defaultValue', () => {
const focusNode = graph.blankNode()

// when
const pointer = defaultValue({ property, focusNode, nodeKind: undefined })
const pointer = defaultValue({ property, focusNode, nodeKind: undefined, editorMeta })

// then
expect(pointer?.term?.termType).to.eq(termType)
Expand All @@ -188,7 +197,7 @@ describe('core/models/resources/lib/defaultValue', () => {
const focusNode = graph.blankNode()

// when
const pointer = defaultValue({ property, focusNode, nodeKind: undefined })
const pointer = defaultValue({ property, focusNode, nodeKind: undefined, editorMeta })

// then
expect(pointer?.out(rdf.type).term).to.deep.eq(foaf.Agent)
Expand All @@ -206,31 +215,53 @@ describe('core/models/resources/lib/defaultValue', () => {
const focusNode = graph.blankNode()

// when
const pointer = defaultValue({ property, focusNode, nodeKind: undefined })
const pointer = defaultValue({ property, focusNode, nodeKind: undefined, editorMeta })

// then
expect(pointer?.out(rdf.type).term).to.be.undefined
})
})

const selectEditors = [
dash.EnumSelectEditor,
dash.InstancesSelectEditor,
dash.AutoCompleteEditor,
dash.URIEditor,
]
it('does not create a node when editor is not annotated', () => {
// given
const editor = ex.Editor
const graph = cf({ dataset: $rdf.dataset() })
const property = propertyShape(graph.blankNode(), {
nodeKind: sh.IRI,
})
const focusNode = graph.blankNode()

selectEditors.forEach((editor) => {
it(`does not create a node when editor is ${editor.value}`, () => {
// given
const graph = cf({ dataset: $rdf.dataset() })
const property = propertyShape(graph.blankNode(), {
nodeKind: sh.IRI,
})
const focusNode = graph.blankNode()
// then
expect(defaultValue({ property, focusNode, editor, nodeKind: undefined, editorMeta })).to.be.null
})

// then
expect(defaultValue({ property, focusNode, editor, nodeKind: undefined })).to.be.null
it('creates a node when editor is annotated', () => {
// given
const editor = ex.Editor
const graph = cf({ dataset: $rdf.dataset() })
const property = propertyShape(graph.blankNode(), {
nodeKind: sh.IRI,
})
const focusNode = graph.blankNode()
editorMeta
.node(editor)
.addOut(sh1.implicitDefaultValue, true)

// then
expect(defaultValue({ property, focusNode, editor, nodeKind: undefined, editorMeta })).not.to.be.null
})

it('by default, creates a node for dash:DetailsEditor', () => {
// given
const editor = dash.DetailsEditor
const graph = cf({ dataset: $rdf.dataset() })
const property = propertyShape(graph.blankNode(), {
nodeKind: sh.IRI,
})
const focusNode = graph.blankNode()
editorMeta.dataset.addAll(CoreMetadata)

// then
expect(defaultValue({ property, focusNode, editor, nodeKind: undefined, editorMeta })).not.to.be.null
})
})
5 changes: 3 additions & 2 deletions packages/core/metadata.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import $rdf from '@rdf-esm/data-model'
import { dash, rdf } from '@tpluscode/rdf-ns-builders'
import sh1 from './ns'
import { dash, rdf, xsd } from '@tpluscode/rdf-ns-builders'
import sh1 from './ns.js'

export default [
$rdf.quad(sh1.InstancesMultiSelectEditor, rdf.type, dash.MultiEditor),
$rdf.quad(dash.DetailsEditor, sh1.implicitDefaultValue, $rdf.literal('true', xsd.boolean)),
]
3 changes: 2 additions & 1 deletion packages/core/models/resources/effects/forms/addFormField.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ export default function (store: Store) {
return
}

const pointer = defaultValue({ property, focusNode, editor: selectedEditor, nodeKind })
const editorMeta = editors.metadata
const pointer = defaultValue({ property, focusNode, editor: selectedEditor, nodeKind, editorMeta })
const predicate = property.getPathProperty(true).id
if (!pointer || focusNode.has(predicate, pointer).terms.length) {
return
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export default function createFocusNodeState(store: Store) {
focusNode,
editor: object.selectedEditor,
nodeKind: object.nodeKind,
editorMeta: editors.metadata,
})?.toArray() || []
if (!value) {
return { shouldNotify: false }
Expand Down
22 changes: 11 additions & 11 deletions packages/core/models/resources/lib/objectValue.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import type { NodeKind, PropertyShape } from '@rdfine/shacl'
import type { GraphPointer, MultiPointer } from 'clownface'
import { dash, rdf, sh } from '@tpluscode/rdf-ns-builders'
import type { AnyPointer, GraphPointer, MultiPointer } from 'clownface'
import { dash, rdf, sh, xsd } from '@tpluscode/rdf-ns-builders'
import type { ResourceIdentifier } from '@tpluscode/rdfine'
import $rdf from '@rdf-esm/data-model'
import type { NamedNode } from 'rdf-js'
import { nanoid } from 'nanoid'
import TermSet from '@rdf-esm/term-set'
import sh1 from '../../../ns.js'
import type { FocusNode } from '../../../index'

Expand All @@ -13,16 +13,12 @@ interface DefaultValue {
editor?: NamedNode
focusNode: FocusNode
nodeKind: NodeKind | undefined
editorMeta: AnyPointer
}

const excludedEditors = new TermSet<NamedNode>([
dash.EnumSelectEditor,
dash.InstancesSelectEditor,
dash.AutoCompleteEditor,
dash.URIEditor,
])
const TRUE = $rdf.literal('true', xsd.boolean)

export function defaultValue({ property, focusNode, editor, nodeKind = property.nodeKind }: DefaultValue): MultiPointer | null {
export function defaultValue({ property, focusNode, editor, nodeKind = property.nodeKind, editorMeta }: DefaultValue): MultiPointer | null {
if (property.defaultValue) {
return focusNode.node(property.defaultValue)
}
Expand All @@ -32,7 +28,7 @@ export function defaultValue({ property, focusNode, editor, nodeKind = property.
nodeKind = sh.BlankNode
}

if (editor && excludedEditors.has(editor)) {
if (editor && !allowsImplicitDefault(editorMeta.node(editor))) {
return null
}

Expand All @@ -48,6 +44,10 @@ export function defaultValue({ property, focusNode, editor, nodeKind = property.
}
}

function allowsImplicitDefault(editor: GraphPointer) {
return editor.out(sh1.implicitDefaultValue).term?.equals(TRUE)
}

function createResourceNode(property: PropertyShape, nodeKind: NodeKind, focusNode: FocusNode) {
const uriStart = property.pointer.out(sh1.iriPrefix).value
let resourceNode: GraphPointer<ResourceIdentifier> = focusNode.blankNode()
Expand Down

0 comments on commit c7b4315

Please sign in to comment.