@_linked/core 2.28.2 → 2.28.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # Changelog
2
2
 
3
+ ## 2.28.4
4
+
5
+ ### Patch Changes
6
+
7
+ - [#326](https://github.com/linked-fw/core/pull/326) [`4596a60`](https://github.com/linked-fw/core/commit/4596a6020e3caab7f4cad0b88ae9098ea3b1dce2) Thanks [@flyon](https://github.com/flyon)! - Lowering a create or update no longer deletes the `shape` key from the caller's nested values.
8
+ `LiveQueryStore` lowers an executed mutation a second time to derive its effects, and a nested value
9
+ of a property that declares no shape (a property shape's `sh:path` when it is not a plain IRI) could
10
+ then no longer be validated: it logged `could not derive the effects of a mutation; live queries were
11
+ not refetched ShapeValidationError: Cannot validate the value of 'path'` and skipped the live-query
12
+ refetch. `syncShape` / `syncShapes` hit this for every shape with an inverse, sequence or alternative path.
13
+
14
+ ## 2.28.3
15
+
16
+ ### Patch Changes
17
+
18
+ - [#322](https://github.com/linked-fw/core/pull/322) [`720e284`](https://github.com/linked-fw/core/commit/720e28438842cc8aa617a818c086b6279e87ade0) Thanks [@flyon](https://github.com/flyon)! - An update's WHERE, and a bulk delete's, no longer multiply their parts — the same fix [#318](https://github.com/linked-fw/core/issues/318) made for a delete by id. `update`, `upsert` and `updateWhere` chained the old value of every property and every owned-cleanup block as OPTIONALs, so the solutions were the product of all of them: updating two multi-valued properties gave one solution per pair of old values, and replacing a `contains` property gave the old node's own triples times every triple of its owned subtree. They are now one OPTIONAL over a UNION of those blocks, which deletes and inserts the same triples. Old values a computed field's BIND reads stay joined to it, as before. `deleteAll` and `deleteWhere` likewise join the root's triples and each blank-node subtree with a UNION instead of nested OPTIONALs.
19
+
20
+ Also fixes a data-loss bug: replacing a `contains` property that had no old value deleted the owned subtree of every other node in the graph, because the cascade block's `?old` variable was left unbound. Each cascade block now binds it through the owning edge.
21
+
3
22
  ## 2.28.2
4
23
 
5
24
  ### Patch Changes
@@ -1,3 +1,14 @@
1
+ var __rest = (this && this.__rest) || function (s, e) {
2
+ var t = {};
3
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
4
+ t[p] = s[p];
5
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
6
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
7
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
8
+ t[p[i]] = s[p[i]];
9
+ }
10
+ return t;
11
+ };
1
12
  import { QueryFactory, } from './QueryFactory.js';
2
13
  import { getPropertyShapes } from '../shapes/nodeShapeData.js';
3
14
  import { resolveShapeConstructor } from '../utils/ShapeClass.js';
@@ -228,7 +239,12 @@ export class MutationQueryFactory extends QueryFactory {
228
239
  if (value.shape.shape.id !== valueShape.id) {
229
240
  throw new Error(`The property 'shape' is reserved in LINCD and should not be used here in this way. The ${propShape.label} property already defines the shape of the value as ${propShape.label}. If you want to use a different shape, use the 'shape' key in the @objectProperty decorator.`);
230
241
  }
231
- delete value.shape;
242
+ // Drop it from a copy, never from the caller's object: the same data
243
+ // is lowered again after the mutation ran (LiveQueryStore derives the
244
+ // mutation's effects from it), and without its `shape` key the value
245
+ // can no longer be validated.
246
+ const { shape: _shape } = value, rest = __rest(value, ["shape"]);
247
+ value = rest;
232
248
  }
233
249
  if (this.isSetModification(value, propShape)) {
234
250
  return this.convertSetModification(value, propShape);
@@ -1 +1 @@
1
- {"version":3,"file":"MutationQuery.js","sourceRoot":"","sources":["../../../src/queries/MutationQuery.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type LiteralUpdateValue,\n type NodeDescriptionValue,\n NodeReferenceValue,\n type PropUpdateValue,\n QueryFactory,\n type SetModification,\n type SetModificationValue,\n type SinglePropertyUpdateValue,\n type UpdateNodePropertyValue,\n type UpdatePartial,\n} from './QueryFactory.js';\nimport {getPropertyShapes} from '../shapes/nodeShapeData.js';\nimport type {NodeShapeData, PropertyShapeData} from '../shapes/SHACL.js';\nimport {Shape, type ShapeConstructor} from '../shapes/Shape.js';\nimport {resolveShapeConstructor} from '../utils/ShapeClass.js';\nimport {isExpressionNode, ExpressionNode} from '../expressions/ExpressionNode.js';\nimport {createProxiedPathBuilder} from './ProxiedPathBuilder.js';\nimport {asContextRef} from './QueryContext.js';\nimport {\n assertValid,\n undeclaredPropertyMessage,\n type ValidationMode,\n} from '../shapes/validation.js';\n\nexport type NodeId = {id: string} | string;\n\n/** Options for {@link MutationQueryFactory.describe}. */\nexport interface DescribeOptions {\n /** Create data may carry a top-level `id`; update data may not. */\n allowTopLevelId?: boolean;\n /**\n * Validate the data against the shape before normalizing, throwing a\n * `ShapeValidationError` with every violation. Omit to skip validation\n * (normalization-only, e.g. when the caller has already validated).\n */\n validate?: ValidationMode;\n}\n\nexport class MutationQueryFactory extends QueryFactory {\n /**\n * Normalize raw create/update data into a {@link NodeDescriptionValue} — the\n * IR-free step shared by `toJSON()` and `lower()`. Kept on this base (which\n * imports no IR) so the builders can normalize for serialization without\n * pulling the canonical-IR pipeline.\n *\n * This is also the single validation gate: pass `validate` and the resolved\n * data is checked against the shape first, so `toJSON()`, `lower()` and\n * `exec()` reject exactly the same input. See `shapes/validation`.\n */\n describe(\n shape: NodeShapeData,\n data: unknown,\n options: DescribeOptions = {},\n ): NodeDescriptionValue {\n return this.convertUpdateObject(data as any, shape, options);\n }\n\n /** Normalize delete ids (strings / `{id}`) to `NodeReferenceValue[]` (IR-free). */\n normalizeNodeRefs(ids: NodeId[] | NodeId): NodeReferenceValue[] {\n return this.convertNodeReferences(ids);\n }\n\n protected convertUpdateObject(\n obj,\n shape: NodeShapeData,\n {allowTopLevelId = false, validate}: DescribeOptions = {},\n ): NodeDescriptionValue {\n let resolved;\n if (typeof obj === 'object' && !(obj instanceof Date) && obj !== null) {\n if (!allowTopLevelId && 'id' in obj) {\n throw new Error(\n 'You cannot use id in the top level of an update object',\n );\n }\n resolved = obj;\n } else if (typeof obj === 'function') {\n // A shape authored in a project exists only as metadata, so it has no authored\n // class. `getOrCreateShapeAdapter` derives a constructor from that metadata --\n // which is the documented return leg of the shape round trip (see\n // registerRuntimeShape). Resolving with `getShapeClass` alone made every runtime shape\n // fail here with \"Shape class not found\".\n const shapeClass = shape.id ? resolveShapeConstructor(shape.id) : undefined;\n if (!shapeClass) {\n throw new Error(`Shape class not found for ${shape.id || 'unknown'}`);\n }\n const proxy = createProxiedPathBuilder(shapeClass);\n const result = obj(proxy);\n if (typeof result !== 'object' || result === null) {\n throw new Error('Update function must return an object');\n }\n // Validate what the callback produced, not the callback itself.\n resolved = result;\n } else {\n throw new Error('Invalid update object');\n }\n if (validate) {\n assertValid(shape, resolved, {mode: validate});\n }\n return this.convertNodeDescription(resolved, shape);\n }\n\n protected isSetModification(obj, shape) {\n let hasAdd = obj.add;\n let hasRemove = obj.remove;\n let numKeysExpected = (hasAdd ? 1 : 0) + (hasRemove ? 1 : 0);\n let numKeys = Object.getOwnPropertyNames(obj).length;\n // A set modification is ONLY add/remove keys. Mixing them with other keys\n // (e.g. {add:[…], name:'x'}) must NOT be silently treated as a set mod —\n // that dropped the sibling fields. Require an exact key-count match for\n // both add and remove (mirrors isSetModificationValue).\n return (hasAdd || hasRemove) && numKeysExpected === numKeys;\n }\n\n protected convertSetModification(\n obj: SetModification<any>,\n shape: PropertyShapeData,\n ): SetModificationValue {\n if (!obj.add && !obj.remove) {\n throw new Error('Set modification should have either add or remove key');\n }\n const res: SetModificationValue = {};\n if (obj.add) {\n res.$add = this.convertSetAddValue(obj.add, shape);\n }\n if (obj.remove) {\n res.$remove = this.convertSetRemoveValue(obj.remove, shape);\n }\n return res;\n }\n\n protected convertSetRemoveValue(\n obj: UpdatePartial | UpdatePartial[],\n shape: PropertyShapeData,\n ): NodeReferenceValue[] {\n //the user can either pass an array of node references or a single node reference\n //either way we should return an array of node reference values\n if (Array.isArray(obj)) {\n return obj.map((o) => this.convertSingleRemoveValue(o, shape));\n } else {\n return [this.convertSingleRemoveValue(obj, shape)];\n }\n }\n\n protected convertSetAddValue(\n obj: UpdatePartial | UpdatePartial[],\n shape: PropertyShapeData,\n ): UpdatePartial[] {\n if (Array.isArray(obj)) {\n return obj.map((o) => this.convertUpdateValue(o, shape) as UpdatePartial);\n } else {\n return [this.convertUpdateValue(obj, shape) as UpdatePartial];\n }\n }\n\n protected convertSingleRemoveValue(\n value,\n shape: PropertyShapeData,\n ): NodeReferenceValue {\n const ctx = asContextRef(value);\n if (ctx) {\n return ctx as unknown as NodeReferenceValue;\n }\n if (this.isNodeReference(value)) {\n return this.convertNodeReference(value);\n } else {\n throw new Error(\n `Invalid value for ${shape.label}.$remove. Expected an object with an id as key: {id:string}`,\n );\n }\n }\n\n protected convertNodeDescription(\n inputObj: Record<string, unknown>,\n shape: NodeShapeData,\n ): NodeDescriptionValue {\n // Shallow-copy so we never mutate the caller's object\n const obj = {...inputObj};\n const props = getPropertyShapes(shape, true);\n const fields: UpdateNodePropertyValue[] = [];\n let id;\n if ('__id' in obj) {\n //if the object has a __id key, then we should use that in the result\n id = obj.__id.toString();\n //but we should not include it in the fields\n delete obj.__id;\n } else if ('id' in obj) {\n //if the object has an id key alongside other data properties,\n //treat it as a nested create with a predefined ID\n id = String(obj.id);\n delete obj.id;\n }\n for (var key in obj) {\n let propShape = props.find((p) => p.label === key);\n if (!propShape) {\n // Also reported as an `sh:ClosedConstraintComponent` violation when the\n // caller validates; kept here because normalization cannot build a field\n // without a property shape (`describe()` may run without validation).\n throw Error(undeclaredPropertyMessage(key, shape));\n } else {\n fields.push(this.createNodePropertyValue(obj[key], propShape));\n }\n }\n const res: NodeDescriptionValue = {\n fields,\n shape,\n };\n if (id) {\n res.__id = id;\n }\n\n return res;\n }\n\n protected createNodePropertyValue(\n value,\n propShape: PropertyShapeData,\n ): UpdateNodePropertyValue {\n return {\n prop: propShape,\n val: this.convertUpdateValue(value, propShape),\n } as UpdateNodePropertyValue;\n }\n\n protected convertUpdateValue(\n value,\n propShape?: PropertyShapeData,\n allowArrays: boolean = true,\n ): PropUpdateValue {\n // ExpressionNode → pass through as-is (will be converted to IRExpression by IRMutation)\n if (isExpressionNode(value)) {\n return value as unknown as PropUpdateValue;\n }\n\n // Query-context reference → preserve the live ref (do NOT collapse to {id},\n // which would read an unresolved `.id` as undefined). Handles both an unset\n // PendingQueryContext and a resolved context shape; both serialize as a {@ctx}\n // marker and are resolved — or throw — at lowering time.\n {\n const ctx = asContextRef(value);\n if (ctx) return ctx as unknown as PropUpdateValue;\n }\n\n //single value which will\n if (\n typeof value === 'string' ||\n typeof value === 'number' ||\n typeof value === 'boolean' ||\n value instanceof Date\n ) {\n return value as LiteralUpdateValue;\n }\n\n //if multiple items are given as value of this prop\n if (Array.isArray(value)) {\n if (!allowArrays) {\n throw new Error('Nested arrays are not allowed as values of keys');\n }\n //then convert each value, but disallow nested arrays moving forward\n return value.map((o) => {\n return this.convertUpdateValue(o, propShape, false);\n }) as SinglePropertyUpdateValue[];\n } else if (typeof value === 'undefined') {\n return value;\n } else if (value === null) {\n //unsetting a value with null is also possible. But we pass it as undefined in the query object\n return undefined;\n } else if (typeof value === 'object') {\n if (this.isNodeReference(value)) {\n return this.convertNodeReference(value);\n } else {\n let valueShape: NodeShapeData = null;\n if (propShape.valueShape) {\n const shapeClass = resolveShapeConstructor(propShape.valueShape);\n valueShape = shapeClass?.shape || null;\n if (!valueShape) {\n throw new Error(\n `Shape class not found for ${propShape.valueShape.id}`,\n );\n }\n }\n //pass the value shape of the property as the node shape of this value\n if (!propShape.valueShape) {\n //It's possible to define the shape of the value in the value itself for properties who do not define the shape in their objectProperty\n if (value.shape) {\n if (!value.shape.shape) {\n throw new Error(\n `The value of property \"shape\" is invalid and should be a class that extends Shape.`,\n );\n }\n valueShape = (value.shape as typeof Shape).shape;\n } else {\n //TODO: not sure if this should be an error. Does every @linkedObject need to define the shape of the values?\n // If not, then how do we continue? because currently we use the value shape to look up further property shapes\n throw new Error(\n `Cannot update properties with plain objects if the shape of the values is not known. Make sure get/set ${propShape.parentNodeShape.label}.${propShape.label} defines the 'shape' key in its @objectProperty decorator.`,\n );\n }\n }\n //never keep a shape key in the value object\n if (value.shape) {\n //double check that IF a shape value is provided, that it matches the shape from the @objectProperty decorator\n if ((value.shape as typeof Shape).shape.id !== valueShape.id) {\n throw new Error(\n `The property 'shape' is reserved in LINCD and should not be used here in this way. The ${propShape.label} property already defines the shape of the value as ${propShape.label}. If you want to use a different shape, use the 'shape' key in the @objectProperty decorator.`,\n );\n }\n delete value.shape;\n }\n\n if (this.isSetModification(value, propShape)) {\n return this.convertSetModification(value, propShape);\n } else {\n return this.convertNodeDescription(value, valueShape);\n }\n }\n }\n throw new Error(`Unsupported update value type: ${typeof value}`);\n }\n\n protected isNodeReference(obj): obj is NodeReferenceValue {\n //check if obj is an object with only an id property\n //if additional data properties are present, it's a nested create with predefined ID\n return typeof obj === 'object' && obj !== null && 'id' in obj && Object.keys(obj).length === 1;\n }\n\n protected convertNodeReferences(\n input: NodeId[] | NodeId,\n ): NodeReferenceValue[] {\n if (Array.isArray(input)) {\n return input.map((o) => {\n return this.convertNodeReferenceOrString(o);\n });\n } else {\n return [this.convertNodeReferenceOrString(input)];\n }\n }\n\n protected convertNodeReferenceOrString(\n o: {id: string} | string,\n ): NodeReferenceValue {\n if (typeof o === 'string') {\n return {id: o};\n } else if (this.isNodeReference(o)) {\n return this.convertNodeReference(o);\n } else {\n throw new Error(`Invalid node reference: ${JSON.stringify(o)}`);\n }\n }\n\n protected convertNodeReference(obj: {id: string}): NodeReferenceValue {\n return {id: obj.id};\n }\n}\n"]}
1
+ {"version":3,"file":"MutationQuery.js","sourceRoot":"","sources":["../../../src/queries/MutationQuery.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type LiteralUpdateValue,\n type NodeDescriptionValue,\n NodeReferenceValue,\n type PropUpdateValue,\n QueryFactory,\n type SetModification,\n type SetModificationValue,\n type SinglePropertyUpdateValue,\n type UpdateNodePropertyValue,\n type UpdatePartial,\n} from './QueryFactory.js';\nimport {getPropertyShapes} from '../shapes/nodeShapeData.js';\nimport type {NodeShapeData, PropertyShapeData} from '../shapes/SHACL.js';\nimport {Shape, type ShapeConstructor} from '../shapes/Shape.js';\nimport {resolveShapeConstructor} from '../utils/ShapeClass.js';\nimport {isExpressionNode, ExpressionNode} from '../expressions/ExpressionNode.js';\nimport {createProxiedPathBuilder} from './ProxiedPathBuilder.js';\nimport {asContextRef} from './QueryContext.js';\nimport {\n assertValid,\n undeclaredPropertyMessage,\n type ValidationMode,\n} from '../shapes/validation.js';\n\nexport type NodeId = {id: string} | string;\n\n/** Options for {@link MutationQueryFactory.describe}. */\nexport interface DescribeOptions {\n /** Create data may carry a top-level `id`; update data may not. */\n allowTopLevelId?: boolean;\n /**\n * Validate the data against the shape before normalizing, throwing a\n * `ShapeValidationError` with every violation. Omit to skip validation\n * (normalization-only, e.g. when the caller has already validated).\n */\n validate?: ValidationMode;\n}\n\nexport class MutationQueryFactory extends QueryFactory {\n /**\n * Normalize raw create/update data into a {@link NodeDescriptionValue} — the\n * IR-free step shared by `toJSON()` and `lower()`. Kept on this base (which\n * imports no IR) so the builders can normalize for serialization without\n * pulling the canonical-IR pipeline.\n *\n * This is also the single validation gate: pass `validate` and the resolved\n * data is checked against the shape first, so `toJSON()`, `lower()` and\n * `exec()` reject exactly the same input. See `shapes/validation`.\n */\n describe(\n shape: NodeShapeData,\n data: unknown,\n options: DescribeOptions = {},\n ): NodeDescriptionValue {\n return this.convertUpdateObject(data as any, shape, options);\n }\n\n /** Normalize delete ids (strings / `{id}`) to `NodeReferenceValue[]` (IR-free). */\n normalizeNodeRefs(ids: NodeId[] | NodeId): NodeReferenceValue[] {\n return this.convertNodeReferences(ids);\n }\n\n protected convertUpdateObject(\n obj,\n shape: NodeShapeData,\n {allowTopLevelId = false, validate}: DescribeOptions = {},\n ): NodeDescriptionValue {\n let resolved;\n if (typeof obj === 'object' && !(obj instanceof Date) && obj !== null) {\n if (!allowTopLevelId && 'id' in obj) {\n throw new Error(\n 'You cannot use id in the top level of an update object',\n );\n }\n resolved = obj;\n } else if (typeof obj === 'function') {\n // A shape authored in a project exists only as metadata, so it has no authored\n // class. `getOrCreateShapeAdapter` derives a constructor from that metadata --\n // which is the documented return leg of the shape round trip (see\n // registerRuntimeShape). Resolving with `getShapeClass` alone made every runtime shape\n // fail here with \"Shape class not found\".\n const shapeClass = shape.id ? resolveShapeConstructor(shape.id) : undefined;\n if (!shapeClass) {\n throw new Error(`Shape class not found for ${shape.id || 'unknown'}`);\n }\n const proxy = createProxiedPathBuilder(shapeClass);\n const result = obj(proxy);\n if (typeof result !== 'object' || result === null) {\n throw new Error('Update function must return an object');\n }\n // Validate what the callback produced, not the callback itself.\n resolved = result;\n } else {\n throw new Error('Invalid update object');\n }\n if (validate) {\n assertValid(shape, resolved, {mode: validate});\n }\n return this.convertNodeDescription(resolved, shape);\n }\n\n protected isSetModification(obj, shape) {\n let hasAdd = obj.add;\n let hasRemove = obj.remove;\n let numKeysExpected = (hasAdd ? 1 : 0) + (hasRemove ? 1 : 0);\n let numKeys = Object.getOwnPropertyNames(obj).length;\n // A set modification is ONLY add/remove keys. Mixing them with other keys\n // (e.g. {add:[…], name:'x'}) must NOT be silently treated as a set mod —\n // that dropped the sibling fields. Require an exact key-count match for\n // both add and remove (mirrors isSetModificationValue).\n return (hasAdd || hasRemove) && numKeysExpected === numKeys;\n }\n\n protected convertSetModification(\n obj: SetModification<any>,\n shape: PropertyShapeData,\n ): SetModificationValue {\n if (!obj.add && !obj.remove) {\n throw new Error('Set modification should have either add or remove key');\n }\n const res: SetModificationValue = {};\n if (obj.add) {\n res.$add = this.convertSetAddValue(obj.add, shape);\n }\n if (obj.remove) {\n res.$remove = this.convertSetRemoveValue(obj.remove, shape);\n }\n return res;\n }\n\n protected convertSetRemoveValue(\n obj: UpdatePartial | UpdatePartial[],\n shape: PropertyShapeData,\n ): NodeReferenceValue[] {\n //the user can either pass an array of node references or a single node reference\n //either way we should return an array of node reference values\n if (Array.isArray(obj)) {\n return obj.map((o) => this.convertSingleRemoveValue(o, shape));\n } else {\n return [this.convertSingleRemoveValue(obj, shape)];\n }\n }\n\n protected convertSetAddValue(\n obj: UpdatePartial | UpdatePartial[],\n shape: PropertyShapeData,\n ): UpdatePartial[] {\n if (Array.isArray(obj)) {\n return obj.map((o) => this.convertUpdateValue(o, shape) as UpdatePartial);\n } else {\n return [this.convertUpdateValue(obj, shape) as UpdatePartial];\n }\n }\n\n protected convertSingleRemoveValue(\n value,\n shape: PropertyShapeData,\n ): NodeReferenceValue {\n const ctx = asContextRef(value);\n if (ctx) {\n return ctx as unknown as NodeReferenceValue;\n }\n if (this.isNodeReference(value)) {\n return this.convertNodeReference(value);\n } else {\n throw new Error(\n `Invalid value for ${shape.label}.$remove. Expected an object with an id as key: {id:string}`,\n );\n }\n }\n\n protected convertNodeDescription(\n inputObj: Record<string, unknown>,\n shape: NodeShapeData,\n ): NodeDescriptionValue {\n // Shallow-copy so we never mutate the caller's object\n const obj = {...inputObj};\n const props = getPropertyShapes(shape, true);\n const fields: UpdateNodePropertyValue[] = [];\n let id;\n if ('__id' in obj) {\n //if the object has a __id key, then we should use that in the result\n id = obj.__id.toString();\n //but we should not include it in the fields\n delete obj.__id;\n } else if ('id' in obj) {\n //if the object has an id key alongside other data properties,\n //treat it as a nested create with a predefined ID\n id = String(obj.id);\n delete obj.id;\n }\n for (var key in obj) {\n let propShape = props.find((p) => p.label === key);\n if (!propShape) {\n // Also reported as an `sh:ClosedConstraintComponent` violation when the\n // caller validates; kept here because normalization cannot build a field\n // without a property shape (`describe()` may run without validation).\n throw Error(undeclaredPropertyMessage(key, shape));\n } else {\n fields.push(this.createNodePropertyValue(obj[key], propShape));\n }\n }\n const res: NodeDescriptionValue = {\n fields,\n shape,\n };\n if (id) {\n res.__id = id;\n }\n\n return res;\n }\n\n protected createNodePropertyValue(\n value,\n propShape: PropertyShapeData,\n ): UpdateNodePropertyValue {\n return {\n prop: propShape,\n val: this.convertUpdateValue(value, propShape),\n } as UpdateNodePropertyValue;\n }\n\n protected convertUpdateValue(\n value,\n propShape?: PropertyShapeData,\n allowArrays: boolean = true,\n ): PropUpdateValue {\n // ExpressionNode → pass through as-is (will be converted to IRExpression by IRMutation)\n if (isExpressionNode(value)) {\n return value as unknown as PropUpdateValue;\n }\n\n // Query-context reference → preserve the live ref (do NOT collapse to {id},\n // which would read an unresolved `.id` as undefined). Handles both an unset\n // PendingQueryContext and a resolved context shape; both serialize as a {@ctx}\n // marker and are resolved — or throw — at lowering time.\n {\n const ctx = asContextRef(value);\n if (ctx) return ctx as unknown as PropUpdateValue;\n }\n\n //single value which will\n if (\n typeof value === 'string' ||\n typeof value === 'number' ||\n typeof value === 'boolean' ||\n value instanceof Date\n ) {\n return value as LiteralUpdateValue;\n }\n\n //if multiple items are given as value of this prop\n if (Array.isArray(value)) {\n if (!allowArrays) {\n throw new Error('Nested arrays are not allowed as values of keys');\n }\n //then convert each value, but disallow nested arrays moving forward\n return value.map((o) => {\n return this.convertUpdateValue(o, propShape, false);\n }) as SinglePropertyUpdateValue[];\n } else if (typeof value === 'undefined') {\n return value;\n } else if (value === null) {\n //unsetting a value with null is also possible. But we pass it as undefined in the query object\n return undefined;\n } else if (typeof value === 'object') {\n if (this.isNodeReference(value)) {\n return this.convertNodeReference(value);\n } else {\n let valueShape: NodeShapeData = null;\n if (propShape.valueShape) {\n const shapeClass = resolveShapeConstructor(propShape.valueShape);\n valueShape = shapeClass?.shape || null;\n if (!valueShape) {\n throw new Error(\n `Shape class not found for ${propShape.valueShape.id}`,\n );\n }\n }\n //pass the value shape of the property as the node shape of this value\n if (!propShape.valueShape) {\n //It's possible to define the shape of the value in the value itself for properties who do not define the shape in their objectProperty\n if (value.shape) {\n if (!value.shape.shape) {\n throw new Error(\n `The value of property \"shape\" is invalid and should be a class that extends Shape.`,\n );\n }\n valueShape = (value.shape as typeof Shape).shape;\n } else {\n //TODO: not sure if this should be an error. Does every @linkedObject need to define the shape of the values?\n // If not, then how do we continue? because currently we use the value shape to look up further property shapes\n throw new Error(\n `Cannot update properties with plain objects if the shape of the values is not known. Make sure get/set ${propShape.parentNodeShape.label}.${propShape.label} defines the 'shape' key in its @objectProperty decorator.`,\n );\n }\n }\n //never keep a shape key in the value object\n if (value.shape) {\n //double check that IF a shape value is provided, that it matches the shape from the @objectProperty decorator\n if ((value.shape as typeof Shape).shape.id !== valueShape.id) {\n throw new Error(\n `The property 'shape' is reserved in LINCD and should not be used here in this way. The ${propShape.label} property already defines the shape of the value as ${propShape.label}. If you want to use a different shape, use the 'shape' key in the @objectProperty decorator.`,\n );\n }\n // Drop it from a copy, never from the caller's object: the same data\n // is lowered again after the mutation ran (LiveQueryStore derives the\n // mutation's effects from it), and without its `shape` key the value\n // can no longer be validated.\n const {shape: _shape, ...rest} = value;\n value = rest;\n }\n\n if (this.isSetModification(value, propShape)) {\n return this.convertSetModification(value, propShape);\n } else {\n return this.convertNodeDescription(value, valueShape);\n }\n }\n }\n throw new Error(`Unsupported update value type: ${typeof value}`);\n }\n\n protected isNodeReference(obj): obj is NodeReferenceValue {\n //check if obj is an object with only an id property\n //if additional data properties are present, it's a nested create with predefined ID\n return typeof obj === 'object' && obj !== null && 'id' in obj && Object.keys(obj).length === 1;\n }\n\n protected convertNodeReferences(\n input: NodeId[] | NodeId,\n ): NodeReferenceValue[] {\n if (Array.isArray(input)) {\n return input.map((o) => {\n return this.convertNodeReferenceOrString(o);\n });\n } else {\n return [this.convertNodeReferenceOrString(input)];\n }\n }\n\n protected convertNodeReferenceOrString(\n o: {id: string} | string,\n ): NodeReferenceValue {\n if (typeof o === 'string') {\n return {id: o};\n } else if (this.isNodeReference(o)) {\n return this.convertNodeReference(o);\n } else {\n throw new Error(`Invalid node reference: ${JSON.stringify(o)}`);\n }\n }\n\n protected convertNodeReference(obj: {id: string}): NodeReferenceValue {\n return {id: obj.id};\n }\n}\n"]}
@@ -131,8 +131,8 @@ function buildNodeShapeData(nodeShape, shapeIri) {
131
131
  */
132
132
  function buildSyncThunk(nodeShape, iri, ds) {
133
133
  return () => {
134
- // Build the data fresh on each invocation: the create pipeline mutates the node-data
135
- // (it strips nested `shape` keys), so a shared object can't be re-used across runs.
134
+ // Build the data fresh on each invocation, so every run writes from the current
135
+ // shape metadata.
136
136
  const data = buildNodeShapeData(nodeShape, iri);
137
137
  return DeleteBuilder.from(NodeShape, { id: iri }).exec(ds)
138
138
  .then(() => NodeShape.create(data).withId(iri).exec(ds))
@@ -1 +1 @@
1
- {"version":3,"file":"syncShapes.js","sourceRoot":"","sources":["../../../src/shapes/syncShapes.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * This Source Code Form is subject to the terms of the Mozilla Public\n * License, v. 2.0. If a copy of the MPL was not distributed with this\n * file, You can obtain one at https://mozilla.org/MPL/2.0/.\n */\nimport {getAllShapeClasses, getShapeClass} from '../utils/ShapeClass.js';\nimport {NodeShape} from './SHACL.js';\nimport {\n getUniquePropertyShapes,\n type NodeShapeData,\n type PropertyShapeData,\n} from './nodeShapeData.js';\nimport {Shape} from './Shape.js';\nimport {DeleteBuilder} from '../queries/DeleteBuilder.js';\nimport type {IDataset} from '../interfaces/IDataset.js';\nimport {rdfList} from './List.js';\nimport {serializePathToNodeData} from './serializePathToNodeData.js';\n\n/**\n * The npm scope of framework shapes (NodeShape/PropertyShape/List/PathNode/Shape) that\n * describe the meta-model itself and must never be synced as user data.\n */\nconst FRAMEWORK_PACKAGE = '@_linked/core';\n\n/**\n * Build the create-pipeline data object for a single PropertyShape (flattened under shapeIri).\n *\n * @internal Exported for tests only — not part of the public API.\n */\nexport function buildPropertyShapeData(ps: PropertyShapeData, shapeIri: string): Record<string, unknown> {\n const psIri = `${shapeIri}/${ps.label}`;\n const d: Record<string, unknown> = {\n __id: psIri,\n path: serializePathToNodeData(ps.path, psIri),\n };\n // `rdfs:label` — the DSL label, i.e. the accessor name the property is reached\n // by in code (`person.memberships`). It is NOT `sh:name`, written below, which\n // is a human-readable display string.\n //\n // Without this the label is only ever implied by `psIri`, and a reader has to\n // re-derive one from the path's local part. That works right up until the two\n // differ — `@_linked/org` declares `memberships` on the path `org:hasMembership`\n // — at which point the catalog reports `hasMembership`, the query proxy indexes\n // the shape with it, and the class (which only knows `memberships`) throws.\n // Readers already prefer a stored label and fall back to the path, so writing it\n // is the whole fix; old catalogs keep working via that fallback.\n if (ps.label) d.label = ps.label;\n if (ps.nodeKind) d.nodeKind = ps.nodeKind;\n if (ps.datatype) d.datatype = ps.datatype;\n if (typeof ps.minCount === 'number') d.minCount = ps.minCount;\n if (typeof ps.maxCount === 'number') d.maxCount = ps.maxCount;\n if (ps.name) d.name = ps.name;\n if (ps.description) d.description = ps.description;\n if (typeof ps.order === 'number') d.order = ps.order;\n if (ps.group) d.group = ps.group;\n if (typeof ps.displayRank === 'number') d.displayRank = ps.displayRank;\n if (ps.displayHidden !== undefined) d.displayHidden = ps.displayHidden;\n if (ps.class) d.class = ps.class;\n if (ps.in) d.in = rdfList(ps.in, {base: `${psIri}/in`});\n if (ps.equalsConstraint) d.equalsConstraint = ps.equalsConstraint;\n if (ps.disjoint) d.disjoint = ps.disjoint;\n if (ps.lessThan) d.lessThan = ps.lessThan;\n if (ps.lessThanOrEquals) d.lessThanOrEquals = ps.lessThanOrEquals;\n if (ps.minInclusive !== undefined) d.minInclusive = ps.minInclusive;\n if (ps.maxInclusive !== undefined) d.maxInclusive = ps.maxInclusive;\n if (ps.minExclusive !== undefined) d.minExclusive = ps.minExclusive;\n if (ps.maxExclusive !== undefined) d.maxExclusive = ps.maxExclusive;\n if (typeof ps.minLength === 'number') d.minLength = ps.minLength;\n if (typeof ps.maxLength === 'number') d.maxLength = ps.maxLength;\n // sh:pattern is serialized as its regex source string.\n if (ps.pattern) d.pattern = ps.pattern.source;\n if (ps.hasValueConstraint !== undefined) d.hasValue = ps.hasValueConstraint;\n if (ps.valueShape) d.valueShape = ps.valueShape;\n if (ps.contains) d.contains = true;\n return d;\n}\n\n/** Build the create-pipeline data object for a NodeShape and its (flattened) property shapes. */\nfunction buildNodeShapeData(nodeShape: NodeShapeData, shapeIri: string): Record<string, unknown> {\n const d: Record<string, unknown> = {};\n if (nodeShape.targetClass) d.targetClass = nodeShape.targetClass;\n if (nodeShape.description) d.description = nodeShape.description;\n if (nodeShape.extends) d.extends = nodeShape.extends;\n if (nodeShape.dependent) d.dependent = true;\n if (nodeShape.closed !== undefined) d.closed = nodeShape.closed;\n if (nodeShape.ignoredProperties && nodeShape.ignoredProperties.length) {\n d.ignoredProperties = nodeShape.ignoredProperties;\n }\n // Flatten: emit own + inherited property shapes (deduped by label) under this shape.\n d.properties = getUniquePropertyShapes(nodeShape).map((ps) =>\n buildPropertyShapeData(ps, shapeIri),\n );\n return d;\n}\n\n/**\n * The per-shape `delete → create` thunk shared by `syncShapes()` and `syncShape()`. The delete\n * cascade-cleans the shape's old property-shape / list / path subtrees; the create rebuilds them.\n *\n * `ds` (optional) targets an explicit dataset — both the delete and the create run against it\n * instead of the global router. Omitted → today's global behavior.\n */\nfunction buildSyncThunk(nodeShape: NodeShapeData, iri: string, ds?: IDataset): () => Promise<void> {\n return () => {\n // Build the data fresh on each invocation: the create pipeline mutates the node-data\n // (it strips nested `shape` keys), so a shared object can't be re-used across runs.\n const data = buildNodeShapeData(nodeShape, iri);\n return (DeleteBuilder.from(NodeShape, {id: iri}).exec(ds) as Promise<unknown>)\n .then(() =>\n (NodeShape.create(data as never).withId(iri) as unknown as {\n exec: (target?: IDataset) => Promise<unknown>;\n }).exec(ds),\n )\n .then(() => undefined);\n };\n}\n\n/** Options controlling how {@link syncShapes} treats store shapes that are not in code. */\nexport interface SyncShapesOptions {\n /**\n * How to treat NodeShapes present in the store but not in the current process's code:\n * - `'none'` (default) — never prune; purely additive (delete→recreate the code shapes, touch\n * nothing else). The only mode that is safe when the process has loaded a *subset* of the\n * shapes in the dataset, or when the dataset has more than one writer.\n * - `'all'` — prune every store-only shape as an orphan. Only correct when this process has\n * loaded **every** shape the dataset should hold and is its **only** writer; \"not registered\n * here\" is then taken to mean \"deleted from code\".\n * - `'ownedNamespaces'` — prune a store-only shape ONLY if its IRI falls within a namespace\n * this process actually writes (the package-namespace of one of its code-registered shapes,\n * i.e. the IRI prefix up to the last `/` or `#`). Protects other writers' packages (arch-04:\n * one app-data dataset, several writers), but NOT the rest of a package the process only\n * partially loaded — the namespace is the whole package, so a deep import of one shape file\n * still claims all of it.\n *\n * `'all'` and `'ownedNamespaces'` are destructive and must be requested explicitly.\n */\n orphanScope?: 'all' | 'ownedNamespaces' | 'none';\n}\n\n/** The owning namespace of a shape IRI — everything up to and including the last `/` or `#`. */\nfunction shapeNamespace(iri: string): string {\n const cut = Math.max(iri.lastIndexOf('/'), iri.lastIndexOf('#'));\n return cut >= 0 ? iri.slice(0, cut + 1) : iri;\n}\n\n/**\n * Plan an idempotent sync of all code-registered (non-framework) NodeShapes into the store as\n * SHACL data — the forward (code → graph) materialization of arch-05 \"code is canonical\".\n *\n * Returns built-but-unexecuted thunks; the caller controls execution and batching:\n * ```ts\n * await Promise.all((await syncShapes()).map((run) => run()));\n * ```\n * Each in-code shape's thunk runs `delete → create` in order (the delete cascade-cleans the old\n * property shapes / list / path subtrees via the containment cascade, the create rebuilds them).\n *\n * **Shapes in the store but not registered in this process are left alone by default**\n * (`orphanScope: 'none'`). The registry only holds what this process happened to import, and\n * that is routinely a subset of what the dataset holds: shapes are deep-importable one file at a\n * time, and an app-data dataset also holds shapes other writers materialized (CN's\n * `bindShape` / `enableCapability`). \"Not registered here\" therefore does not mean \"deleted from\n * code\". Measured against a dataset holding the 36 `@_linked/schema` shapes: a process that\n * imported only `@_linked/schema/shapes/Thing` (11 shapes registered) deleted the other 25 under\n * both `'all'` and `'ownedNamespaces'`, and a process that imported no shapes deleted all 36.\n *\n * Pruning is opt-in via `options.orphanScope` (see {@link SyncShapesOptions}): pass `'all'` only\n * from a process that has loaded every shape the dataset should hold and is its sole writer, and\n * `'ownedNamespaces'` only when it has loaded every shape of each package it registers. Pruned\n * orphans are deleted with their owned subtree. Pruning reads the existing shape IRIs first;\n * with `'none'` no read is made.\n *\n * `ds` (optional) targets an explicit dataset instead of the global router. It is a **plan-time**\n * parameter: it feeds both the orphan-detection read (so orphans are computed against the same\n * store they'll be pruned from) and every delete/create thunk. Omitted → the global router;\n * the returned thunks stay nullary either way.\n */\nexport async function syncShapes(\n ds?: IDataset,\n options?: SyncShapesOptions,\n): Promise<Array<() => Promise<void>>> {\n const orphanScope = options?.orphanScope ?? 'none';\n // 1. Enumerate code-registered user shapes (exclude framework/meta shapes).\n const userShapes: Array<{iri: string; nodeShape: NodeShapeData}> = [];\n for (const [iri, shapeClass] of getAllShapeClasses()) {\n if (!shapeClass?.shape) continue;\n const pkg = (shapeClass as {packageName?: string}).packageName;\n // Skip framework/meta shapes: the core package, and the base `Shape` which is registered\n // directly (no applyLinkedShape) and therefore carries no packageName.\n if (!pkg || pkg === FRAMEWORK_PACKAGE) continue;\n userShapes.push({iri, nodeShape: shapeClass.shape});\n }\n const localShapeIris = new Set(userShapes.map((s) => s.iri));\n // Namespaces this process actually writes — the ownership scope for `'ownedNamespaces'` pruning.\n const ownedNamespaces = new Set(userShapes.map((s) => shapeNamespace(s.iri)));\n\n const thunks: Array<() => Promise<void>> = [];\n\n // 2. Per in-code shape: delete (cascade) then recreate.\n for (const {iri, nodeShape} of userShapes) {\n thunks.push(buildSyncThunk(nodeShape, iri, ds));\n }\n\n // 3. Orphan sweep (unless disabled). Identity-read existing NodeShape IRIs (ids only). Must hit\n // the same `ds` the thunks target, or orphans get computed against the wrong store.\n if (orphanScope !== 'none') {\n const existingRows = (await (NodeShape as unknown as {\n select: () => {exec: (target?: IDataset) => Promise<Array<{id: string}>>};\n }).select().exec(ds)) as Array<{id: string}>;\n\n // Orphan shapes (in store, not in code) → delete (cascade cleans their owned subtree). In\n // `'ownedNamespaces'` mode, only shapes within a namespace this process writes are eligible —\n // other writers' shapes (different package namespace) are left untouched.\n for (const {id: iri} of existingRows) {\n if (localShapeIris.has(iri)) continue;\n if (orphanScope === 'ownedNamespaces' && !ownedNamespaces.has(shapeNamespace(iri))) {\n continue;\n }\n thunks.push(() =>\n (DeleteBuilder.from(NodeShape, {id: iri}).exec(ds) as Promise<unknown>).then(\n () => undefined,\n ),\n );\n }\n }\n\n return thunks;\n}\n\n/**\n * Plan an idempotent sync of ONE code-registered NodeShape into the store as SHACL data.\n *\n * Scoped counterpart to {@link syncShapes}: materializes a single shape (delete → recreate, so the\n * delete cascade-cleans the old property-shape / list / path subtrees and the create rebuilds them)\n * and does NOT run the store-wide orphan sweep — other shapes in the store are untouched.\n *\n * @param target a shape class (e.g. `Person`) or its NodeShape IRI string. An IRI is resolved to\n * its registered class via `getShapeClass`; the shape must be code-registered.\n * @param ds optional explicit dataset to materialize into (a store or a router) — both the delete\n * and the create run against it instead of the global router. Omitted → global behavior.\n * @returns a single unexecuted thunk (consistent with {@link syncShapes}), so callers can batch\n * several together — e.g. a shape plus its referenced object-property shapes:\n * `await Promise.all([syncShape(Person), syncShape(Address)].map((run) => run()))`.\n * @throws if `target` is a framework/meta shape, is not registered, or has no `.shape`.\n */\nexport function syncShape(target: typeof Shape | string, ds?: IDataset): () => Promise<void> {\n // Normalize target → its registered shape class.\n const cls =\n typeof target === 'string' ? getShapeClass(target) : (target as typeof Shape);\n if (typeof target === 'string' && !cls) {\n throw new Error(`syncShape: no registered shape for IRI ${target}`);\n }\n const nodeShape = cls?.shape;\n if (!nodeShape) {\n throw new Error(\n typeof target === 'string'\n ? `syncShape: no registered shape for IRI ${target}`\n : `syncShape: shape class has no static .shape`,\n );\n }\n const iri = nodeShape.id;\n\n // Never materialize a framework/meta shape as user data — same invariant syncShapes() enforces\n // by skipping (the base Shape carries no packageName).\n const pkg = (cls as {packageName?: string}).packageName;\n if (!pkg || pkg === FRAMEWORK_PACKAGE) {\n throw new Error(`syncShape: refusing to sync framework/meta shape ${iri}`);\n }\n\n return buildSyncThunk(nodeShape, iri, ds);\n}\n"]}
1
+ {"version":3,"file":"syncShapes.js","sourceRoot":"","sources":["../../../src/shapes/syncShapes.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * This Source Code Form is subject to the terms of the Mozilla Public\n * License, v. 2.0. If a copy of the MPL was not distributed with this\n * file, You can obtain one at https://mozilla.org/MPL/2.0/.\n */\nimport {getAllShapeClasses, getShapeClass} from '../utils/ShapeClass.js';\nimport {NodeShape} from './SHACL.js';\nimport {\n getUniquePropertyShapes,\n type NodeShapeData,\n type PropertyShapeData,\n} from './nodeShapeData.js';\nimport {Shape} from './Shape.js';\nimport {DeleteBuilder} from '../queries/DeleteBuilder.js';\nimport type {IDataset} from '../interfaces/IDataset.js';\nimport {rdfList} from './List.js';\nimport {serializePathToNodeData} from './serializePathToNodeData.js';\n\n/**\n * The npm scope of framework shapes (NodeShape/PropertyShape/List/PathNode/Shape) that\n * describe the meta-model itself and must never be synced as user data.\n */\nconst FRAMEWORK_PACKAGE = '@_linked/core';\n\n/**\n * Build the create-pipeline data object for a single PropertyShape (flattened under shapeIri).\n *\n * @internal Exported for tests only — not part of the public API.\n */\nexport function buildPropertyShapeData(ps: PropertyShapeData, shapeIri: string): Record<string, unknown> {\n const psIri = `${shapeIri}/${ps.label}`;\n const d: Record<string, unknown> = {\n __id: psIri,\n path: serializePathToNodeData(ps.path, psIri),\n };\n // `rdfs:label` — the DSL label, i.e. the accessor name the property is reached\n // by in code (`person.memberships`). It is NOT `sh:name`, written below, which\n // is a human-readable display string.\n //\n // Without this the label is only ever implied by `psIri`, and a reader has to\n // re-derive one from the path's local part. That works right up until the two\n // differ — `@_linked/org` declares `memberships` on the path `org:hasMembership`\n // — at which point the catalog reports `hasMembership`, the query proxy indexes\n // the shape with it, and the class (which only knows `memberships`) throws.\n // Readers already prefer a stored label and fall back to the path, so writing it\n // is the whole fix; old catalogs keep working via that fallback.\n if (ps.label) d.label = ps.label;\n if (ps.nodeKind) d.nodeKind = ps.nodeKind;\n if (ps.datatype) d.datatype = ps.datatype;\n if (typeof ps.minCount === 'number') d.minCount = ps.minCount;\n if (typeof ps.maxCount === 'number') d.maxCount = ps.maxCount;\n if (ps.name) d.name = ps.name;\n if (ps.description) d.description = ps.description;\n if (typeof ps.order === 'number') d.order = ps.order;\n if (ps.group) d.group = ps.group;\n if (typeof ps.displayRank === 'number') d.displayRank = ps.displayRank;\n if (ps.displayHidden !== undefined) d.displayHidden = ps.displayHidden;\n if (ps.class) d.class = ps.class;\n if (ps.in) d.in = rdfList(ps.in, {base: `${psIri}/in`});\n if (ps.equalsConstraint) d.equalsConstraint = ps.equalsConstraint;\n if (ps.disjoint) d.disjoint = ps.disjoint;\n if (ps.lessThan) d.lessThan = ps.lessThan;\n if (ps.lessThanOrEquals) d.lessThanOrEquals = ps.lessThanOrEquals;\n if (ps.minInclusive !== undefined) d.minInclusive = ps.minInclusive;\n if (ps.maxInclusive !== undefined) d.maxInclusive = ps.maxInclusive;\n if (ps.minExclusive !== undefined) d.minExclusive = ps.minExclusive;\n if (ps.maxExclusive !== undefined) d.maxExclusive = ps.maxExclusive;\n if (typeof ps.minLength === 'number') d.minLength = ps.minLength;\n if (typeof ps.maxLength === 'number') d.maxLength = ps.maxLength;\n // sh:pattern is serialized as its regex source string.\n if (ps.pattern) d.pattern = ps.pattern.source;\n if (ps.hasValueConstraint !== undefined) d.hasValue = ps.hasValueConstraint;\n if (ps.valueShape) d.valueShape = ps.valueShape;\n if (ps.contains) d.contains = true;\n return d;\n}\n\n/** Build the create-pipeline data object for a NodeShape and its (flattened) property shapes. */\nfunction buildNodeShapeData(nodeShape: NodeShapeData, shapeIri: string): Record<string, unknown> {\n const d: Record<string, unknown> = {};\n if (nodeShape.targetClass) d.targetClass = nodeShape.targetClass;\n if (nodeShape.description) d.description = nodeShape.description;\n if (nodeShape.extends) d.extends = nodeShape.extends;\n if (nodeShape.dependent) d.dependent = true;\n if (nodeShape.closed !== undefined) d.closed = nodeShape.closed;\n if (nodeShape.ignoredProperties && nodeShape.ignoredProperties.length) {\n d.ignoredProperties = nodeShape.ignoredProperties;\n }\n // Flatten: emit own + inherited property shapes (deduped by label) under this shape.\n d.properties = getUniquePropertyShapes(nodeShape).map((ps) =>\n buildPropertyShapeData(ps, shapeIri),\n );\n return d;\n}\n\n/**\n * The per-shape `delete → create` thunk shared by `syncShapes()` and `syncShape()`. The delete\n * cascade-cleans the shape's old property-shape / list / path subtrees; the create rebuilds them.\n *\n * `ds` (optional) targets an explicit dataset — both the delete and the create run against it\n * instead of the global router. Omitted → today's global behavior.\n */\nfunction buildSyncThunk(nodeShape: NodeShapeData, iri: string, ds?: IDataset): () => Promise<void> {\n return () => {\n // Build the data fresh on each invocation, so every run writes from the current\n // shape metadata.\n const data = buildNodeShapeData(nodeShape, iri);\n return (DeleteBuilder.from(NodeShape, {id: iri}).exec(ds) as Promise<unknown>)\n .then(() =>\n (NodeShape.create(data as never).withId(iri) as unknown as {\n exec: (target?: IDataset) => Promise<unknown>;\n }).exec(ds),\n )\n .then(() => undefined);\n };\n}\n\n/** Options controlling how {@link syncShapes} treats store shapes that are not in code. */\nexport interface SyncShapesOptions {\n /**\n * How to treat NodeShapes present in the store but not in the current process's code:\n * - `'none'` (default) — never prune; purely additive (delete→recreate the code shapes, touch\n * nothing else). The only mode that is safe when the process has loaded a *subset* of the\n * shapes in the dataset, or when the dataset has more than one writer.\n * - `'all'` — prune every store-only shape as an orphan. Only correct when this process has\n * loaded **every** shape the dataset should hold and is its **only** writer; \"not registered\n * here\" is then taken to mean \"deleted from code\".\n * - `'ownedNamespaces'` — prune a store-only shape ONLY if its IRI falls within a namespace\n * this process actually writes (the package-namespace of one of its code-registered shapes,\n * i.e. the IRI prefix up to the last `/` or `#`). Protects other writers' packages (arch-04:\n * one app-data dataset, several writers), but NOT the rest of a package the process only\n * partially loaded — the namespace is the whole package, so a deep import of one shape file\n * still claims all of it.\n *\n * `'all'` and `'ownedNamespaces'` are destructive and must be requested explicitly.\n */\n orphanScope?: 'all' | 'ownedNamespaces' | 'none';\n}\n\n/** The owning namespace of a shape IRI — everything up to and including the last `/` or `#`. */\nfunction shapeNamespace(iri: string): string {\n const cut = Math.max(iri.lastIndexOf('/'), iri.lastIndexOf('#'));\n return cut >= 0 ? iri.slice(0, cut + 1) : iri;\n}\n\n/**\n * Plan an idempotent sync of all code-registered (non-framework) NodeShapes into the store as\n * SHACL data — the forward (code → graph) materialization of arch-05 \"code is canonical\".\n *\n * Returns built-but-unexecuted thunks; the caller controls execution and batching:\n * ```ts\n * await Promise.all((await syncShapes()).map((run) => run()));\n * ```\n * Each in-code shape's thunk runs `delete → create` in order (the delete cascade-cleans the old\n * property shapes / list / path subtrees via the containment cascade, the create rebuilds them).\n *\n * **Shapes in the store but not registered in this process are left alone by default**\n * (`orphanScope: 'none'`). The registry only holds what this process happened to import, and\n * that is routinely a subset of what the dataset holds: shapes are deep-importable one file at a\n * time, and an app-data dataset also holds shapes other writers materialized (CN's\n * `bindShape` / `enableCapability`). \"Not registered here\" therefore does not mean \"deleted from\n * code\". Measured against a dataset holding the 36 `@_linked/schema` shapes: a process that\n * imported only `@_linked/schema/shapes/Thing` (11 shapes registered) deleted the other 25 under\n * both `'all'` and `'ownedNamespaces'`, and a process that imported no shapes deleted all 36.\n *\n * Pruning is opt-in via `options.orphanScope` (see {@link SyncShapesOptions}): pass `'all'` only\n * from a process that has loaded every shape the dataset should hold and is its sole writer, and\n * `'ownedNamespaces'` only when it has loaded every shape of each package it registers. Pruned\n * orphans are deleted with their owned subtree. Pruning reads the existing shape IRIs first;\n * with `'none'` no read is made.\n *\n * `ds` (optional) targets an explicit dataset instead of the global router. It is a **plan-time**\n * parameter: it feeds both the orphan-detection read (so orphans are computed against the same\n * store they'll be pruned from) and every delete/create thunk. Omitted → the global router;\n * the returned thunks stay nullary either way.\n */\nexport async function syncShapes(\n ds?: IDataset,\n options?: SyncShapesOptions,\n): Promise<Array<() => Promise<void>>> {\n const orphanScope = options?.orphanScope ?? 'none';\n // 1. Enumerate code-registered user shapes (exclude framework/meta shapes).\n const userShapes: Array<{iri: string; nodeShape: NodeShapeData}> = [];\n for (const [iri, shapeClass] of getAllShapeClasses()) {\n if (!shapeClass?.shape) continue;\n const pkg = (shapeClass as {packageName?: string}).packageName;\n // Skip framework/meta shapes: the core package, and the base `Shape` which is registered\n // directly (no applyLinkedShape) and therefore carries no packageName.\n if (!pkg || pkg === FRAMEWORK_PACKAGE) continue;\n userShapes.push({iri, nodeShape: shapeClass.shape});\n }\n const localShapeIris = new Set(userShapes.map((s) => s.iri));\n // Namespaces this process actually writes — the ownership scope for `'ownedNamespaces'` pruning.\n const ownedNamespaces = new Set(userShapes.map((s) => shapeNamespace(s.iri)));\n\n const thunks: Array<() => Promise<void>> = [];\n\n // 2. Per in-code shape: delete (cascade) then recreate.\n for (const {iri, nodeShape} of userShapes) {\n thunks.push(buildSyncThunk(nodeShape, iri, ds));\n }\n\n // 3. Orphan sweep (unless disabled). Identity-read existing NodeShape IRIs (ids only). Must hit\n // the same `ds` the thunks target, or orphans get computed against the wrong store.\n if (orphanScope !== 'none') {\n const existingRows = (await (NodeShape as unknown as {\n select: () => {exec: (target?: IDataset) => Promise<Array<{id: string}>>};\n }).select().exec(ds)) as Array<{id: string}>;\n\n // Orphan shapes (in store, not in code) → delete (cascade cleans their owned subtree). In\n // `'ownedNamespaces'` mode, only shapes within a namespace this process writes are eligible —\n // other writers' shapes (different package namespace) are left untouched.\n for (const {id: iri} of existingRows) {\n if (localShapeIris.has(iri)) continue;\n if (orphanScope === 'ownedNamespaces' && !ownedNamespaces.has(shapeNamespace(iri))) {\n continue;\n }\n thunks.push(() =>\n (DeleteBuilder.from(NodeShape, {id: iri}).exec(ds) as Promise<unknown>).then(\n () => undefined,\n ),\n );\n }\n }\n\n return thunks;\n}\n\n/**\n * Plan an idempotent sync of ONE code-registered NodeShape into the store as SHACL data.\n *\n * Scoped counterpart to {@link syncShapes}: materializes a single shape (delete → recreate, so the\n * delete cascade-cleans the old property-shape / list / path subtrees and the create rebuilds them)\n * and does NOT run the store-wide orphan sweep — other shapes in the store are untouched.\n *\n * @param target a shape class (e.g. `Person`) or its NodeShape IRI string. An IRI is resolved to\n * its registered class via `getShapeClass`; the shape must be code-registered.\n * @param ds optional explicit dataset to materialize into (a store or a router) — both the delete\n * and the create run against it instead of the global router. Omitted → global behavior.\n * @returns a single unexecuted thunk (consistent with {@link syncShapes}), so callers can batch\n * several together — e.g. a shape plus its referenced object-property shapes:\n * `await Promise.all([syncShape(Person), syncShape(Address)].map((run) => run()))`.\n * @throws if `target` is a framework/meta shape, is not registered, or has no `.shape`.\n */\nexport function syncShape(target: typeof Shape | string, ds?: IDataset): () => Promise<void> {\n // Normalize target → its registered shape class.\n const cls =\n typeof target === 'string' ? getShapeClass(target) : (target as typeof Shape);\n if (typeof target === 'string' && !cls) {\n throw new Error(`syncShape: no registered shape for IRI ${target}`);\n }\n const nodeShape = cls?.shape;\n if (!nodeShape) {\n throw new Error(\n typeof target === 'string'\n ? `syncShape: no registered shape for IRI ${target}`\n : `syncShape: shape class has no static .shape`,\n );\n }\n const iri = nodeShape.id;\n\n // Never materialize a framework/meta shape as user data — same invariant syncShapes() enforces\n // by skipping (the base Shape carries no packageName).\n const pkg = (cls as {packageName?: string}).packageName;\n if (!pkg || pkg === FRAMEWORK_PACKAGE) {\n throw new Error(`syncShape: refusing to sync framework/meta shape ${iri}`);\n }\n\n return buildSyncThunk(nodeShape, iri, ds);\n}\n"]}
@@ -27,8 +27,11 @@ export declare function upsertToAlgebra(query: IRUpsertMutation, options?: Sparq
27
27
  * Build DELETE patterns + WHERE OPTIONAL blocks that cascade-delete the owned subtree
28
28
  * reachable from `rootTerm` via `contains` edges. `varPrefix` keeps generated variables
29
29
  * unique across multiple roots in one query. Returns empty when nothing is owned.
30
+ *
31
+ * `anchor`, when given, leads every block: the triple that binds a variable root, so
32
+ * each block stays correct on its own (as a UNION branch) when no such root exists.
30
33
  */
31
- export declare function buildOwnedCascade(rootTerm: SparqlTerm, varPrefix: string): {
34
+ export declare function buildOwnedCascade(rootTerm: SparqlTerm, varPrefix: string, anchor?: SparqlTriple): {
32
35
  deletePatterns: SparqlTriple[];
33
36
  whereOptionals: SparqlAlgebraNode[];
34
37
  };