@_linked/core 2.25.0 → 2.27.0
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 +49 -0
- package/README.md +27 -0
- package/lib/esm/index.d.ts +9 -0
- package/lib/esm/index.js +8 -0
- package/lib/esm/index.js.map +1 -1
- package/lib/esm/interfaces/IDataset.d.ts +15 -0
- package/lib/esm/interfaces/IDataset.js.map +1 -1
- package/lib/esm/live/LiveQueryStore.d.ts +240 -0
- package/lib/esm/live/LiveQueryStore.js +729 -0
- package/lib/esm/live/LiveQueryStore.js.map +1 -0
- package/lib/esm/live/changes.d.ts +30 -0
- package/lib/esm/live/changes.js +30 -0
- package/lib/esm/live/changes.js.map +1 -0
- package/lib/esm/live/keys.d.ts +54 -0
- package/lib/esm/live/keys.js +112 -0
- package/lib/esm/live/keys.js.map +1 -0
- package/lib/esm/live/matcher.d.ts +43 -0
- package/lib/esm/live/matcher.js +115 -0
- package/lib/esm/live/matcher.js.map +1 -0
- package/lib/esm/live/registry.d.ts +24 -0
- package/lib/esm/live/registry.js +41 -0
- package/lib/esm/live/registry.js.map +1 -0
- package/lib/esm/live.d.ts +12 -0
- package/lib/esm/live.js +15 -0
- package/lib/esm/live.js.map +1 -0
- package/lib/esm/paths/normalizePropertyPath.js +3 -2
- package/lib/esm/paths/normalizePropertyPath.js.map +1 -1
- package/lib/esm/queries/AskBuilder.d.ts +10 -0
- package/lib/esm/queries/AskBuilder.js +14 -0
- package/lib/esm/queries/AskBuilder.js.map +1 -1
- package/lib/esm/queries/CountBuilder.d.ts +10 -0
- package/lib/esm/queries/CountBuilder.js +14 -0
- package/lib/esm/queries/CountBuilder.js.map +1 -1
- package/lib/esm/queries/QueryBuilder.d.ts +10 -0
- package/lib/esm/queries/QueryBuilder.js +14 -0
- package/lib/esm/queries/QueryBuilder.js.map +1 -1
- package/lib/esm/queries/QueryContext.js +9 -2
- package/lib/esm/queries/QueryContext.js.map +1 -1
- package/lib/esm/queries/queryDependencies.d.ts +58 -0
- package/lib/esm/queries/queryDependencies.js +494 -0
- package/lib/esm/queries/queryDependencies.js.map +1 -0
- package/lib/esm/queries/queryDispatch.d.ts +46 -0
- package/lib/esm/queries/queryDispatch.js +88 -3
- package/lib/esm/queries/queryDispatch.js.map +1 -1
- package/lib/esm/shapes/nodeShapeData.d.ts +16 -0
- package/lib/esm/shapes/nodeShapeData.js +41 -1
- package/lib/esm/shapes/nodeShapeData.js.map +1 -1
- package/lib/esm/shapes/relationShape.d.ts +35 -0
- package/lib/esm/shapes/relationShape.js +88 -0
- package/lib/esm/shapes/relationShape.js.map +1 -0
- package/lib/esm/shapes/validation.js +8 -4
- package/lib/esm/shapes/validation.js.map +1 -1
- package/lib/esm/sparql/irToAlgebra.js +5 -40
- package/lib/esm/sparql/irToAlgebra.js.map +1 -1
- package/lib/esm/utils/LinkedStorage.d.ts +6 -0
- package/lib/esm/utils/LinkedStorage.js +32 -6
- package/lib/esm/utils/LinkedStorage.js.map +1 -1
- package/lib/esm/utils/ShapeClass.d.ts +26 -0
- package/lib/esm/utils/ShapeClass.js +128 -0
- package/lib/esm/utils/ShapeClass.js.map +1 -1
- package/package.json +6 -2
|
@@ -14,6 +14,12 @@ export declare abstract class LinkedStorage {
|
|
|
14
14
|
static getDefaultDataset(): IDataset;
|
|
15
15
|
/** Set the default IDataset (catch-all for shapes with no explicit mapping). */
|
|
16
16
|
static setDefaultDataset(dataset: IDataset): void;
|
|
17
|
+
/**
|
|
18
|
+
* Be told whenever the set of datasets changes (`setDefaultDataset`,
|
|
19
|
+
* `setDatasetForShapes`, `unsetDatasetForShape`). The live-query store uses
|
|
20
|
+
* this to pick up a dataset's change feed. Returns the unsubscribe function.
|
|
21
|
+
*/
|
|
22
|
+
static onRoutingChanged(listener: () => void): () => void;
|
|
17
23
|
/** Pin one or more shape classes to a specific IDataset implementer. */
|
|
18
24
|
static setDatasetForShapes(dataset: IDataset, ...shapeClasses: Function[]): void;
|
|
19
25
|
/**
|
|
@@ -7,7 +7,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
7
7
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
|
-
var _a, _b;
|
|
10
|
+
var _a, _b, _c;
|
|
11
11
|
import { CoreSet } from '../collections/CoreSet.js';
|
|
12
12
|
import { setQueryDispatch, resolveExistence } from '../queries/queryDispatch.js';
|
|
13
13
|
import { getShapeClass } from './ShapeClass.js';
|
|
@@ -41,7 +41,21 @@ linkedStorageGlobal.__linkedStorageInstanceCount =
|
|
|
41
41
|
const routingState = ((_b = linkedStorageGlobal.__linkedStorageRouting) !== null && _b !== void 0 ? _b : (linkedStorageGlobal.__linkedStorageRouting = {
|
|
42
42
|
defaultDataset: undefined,
|
|
43
43
|
shapeToDataset: new Map(),
|
|
44
|
+
listeners: new Set(),
|
|
44
45
|
}));
|
|
46
|
+
// An older copy of this module may have created the record without listeners.
|
|
47
|
+
(_c = routingState.listeners) !== null && _c !== void 0 ? _c : (routingState.listeners = new Set());
|
|
48
|
+
/** Tell routing-change listeners that the set of datasets may have changed. */
|
|
49
|
+
function notifyRoutingChanged() {
|
|
50
|
+
for (const listener of [...routingState.listeners]) {
|
|
51
|
+
try {
|
|
52
|
+
listener();
|
|
53
|
+
}
|
|
54
|
+
catch (err) {
|
|
55
|
+
console.error('[linked] routing-change listener failed', err);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
45
59
|
/** A shape class's IRI, or undefined for anything that is not a registered shape. */
|
|
46
60
|
const shapeUriOf = (shapeClass) => {
|
|
47
61
|
var _a;
|
|
@@ -75,6 +89,16 @@ export class LinkedStorage {
|
|
|
75
89
|
updateQuery: (q) => this.updateQuery(q),
|
|
76
90
|
deleteQuery: (q) => this.deleteQuery(q),
|
|
77
91
|
});
|
|
92
|
+
notifyRoutingChanged();
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Be told whenever the set of datasets changes (`setDefaultDataset`,
|
|
96
|
+
* `setDatasetForShapes`, `unsetDatasetForShape`). The live-query store uses
|
|
97
|
+
* this to pick up a dataset's change feed. Returns the unsubscribe function.
|
|
98
|
+
*/
|
|
99
|
+
static onRoutingChanged(listener) {
|
|
100
|
+
routingState.listeners.add(listener);
|
|
101
|
+
return () => routingState.listeners.delete(listener);
|
|
78
102
|
}
|
|
79
103
|
/** Pin one or more shape classes to a specific IDataset implementer. */
|
|
80
104
|
static setDatasetForShapes(dataset, ...shapeClasses) {
|
|
@@ -95,6 +119,7 @@ export class LinkedStorage {
|
|
|
95
119
|
}
|
|
96
120
|
routingState.shapeToDataset.set(shapeClass, dataset);
|
|
97
121
|
});
|
|
122
|
+
notifyRoutingChanged();
|
|
98
123
|
}
|
|
99
124
|
/**
|
|
100
125
|
* Remove the pin for a shape, by class or by IRI.
|
|
@@ -107,13 +132,14 @@ export class LinkedStorage {
|
|
|
107
132
|
static unsetDatasetForShape(shape) {
|
|
108
133
|
const uri = typeof shape === 'string' ? shape : shapeUriOf(shape);
|
|
109
134
|
routingState.shapeToDataset.delete(shape);
|
|
110
|
-
if (
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
135
|
+
if (uri) {
|
|
136
|
+
for (const pinned of [...routingState.shapeToDataset.keys()]) {
|
|
137
|
+
if (shapeUriOf(pinned) === uri) {
|
|
138
|
+
routingState.shapeToDataset.delete(pinned);
|
|
139
|
+
}
|
|
115
140
|
}
|
|
116
141
|
}
|
|
142
|
+
notifyRoutingChanged();
|
|
117
143
|
}
|
|
118
144
|
/** Every IDataset known to the primary router (default + all pinned). */
|
|
119
145
|
static getDatasets() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LinkedStorage.js","sourceRoot":"","sources":["../../../src/utils/LinkedStorage.ts"],"names":[],"mappings":"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","sourcesContent":["import {CoreSet} from '../collections/CoreSet.js';\nimport type {IDataset} from '../interfaces/IDataset.js';\nimport type {SelectQuery} from '../queries/SelectQuery.js';\nimport type {AskQuery} from '../queries/AskQuery.js';\nimport type {CountQuery} from '../queries/CountQuery.js';\nimport type {CreateQuery} from '../queries/CreateQuery.js';\nimport type {UpdateQuery} from '../queries/UpdateQuery.js';\nimport type {DeleteQuery, DeleteResponse} from '../queries/DeleteQuery.js';\nimport {setQueryDispatch, resolveExistence} from '../queries/queryDispatch.js';\nimport {getShapeClass} from './ShapeClass.js';\nimport type {NodeShapeData} from '../shapes/SHACL.js';\n\n// plan-011 — count physical evaluations of THIS module on the one shared\n// global object. With the single-loader fix there should be exactly one copy;\n// the single-instance guard in backend.ts reports this count if storage config\n// ever lands on a different copy. Deliberately avoids Date/Math.random\n// (unavailable / non-deterministic per repo constraints).\nconst linkedStorageGlobal: any =\n typeof globalThis !== 'undefined' ? globalThis : ({} as any);\nlinkedStorageGlobal.__linkedStorageInstanceCount =\n (linkedStorageGlobal.__linkedStorageInstanceCount ?? 0) + 1;\n\n/**\n * Primary routing layer (arch-04 §The IDataset abstraction).\n *\n * Resolves an incoming Linked Query to the IDataset that should handle it,\n * based on the query's target shape. Composite IDatasets (gateways, routers,\n * forwarders, resolvers) plug in here just like storage IDatasets do.\n *\n * The \"Dataset\" naming aligns with the IDataset contract. Earlier \"Store\"\n * names were renamed in phase-1 — see docs/plans/002-phase-1-create-user-project-flow.md.\n */\n/**\n * The routing table lives on the shared global, beside the shape registries.\n *\n * It has to, for the same reason they do: a module can evaluate more than once in a\n * process, and a class static then exists once per copy. Leaving these two here while\n * the registries were shared was worse than either extreme — a second copy answered\n * `isInitialised()` with false and `getDatasetForShapeClass()` with the default, while\n * reporting a fully populated shape registry.\n */\nconst routingState: {\n defaultDataset?: IDataset;\n shapeToDataset: Map<Function, IDataset>;\n} = (linkedStorageGlobal.__linkedStorageRouting ??= {\n defaultDataset: undefined,\n shapeToDataset: new Map(),\n});\n\n/** A shape class's IRI, or undefined for anything that is not a registered shape. */\nconst shapeUriOf = (shapeClass?: Function | null): string | undefined => {\n const uri = (shapeClass as {shape?: {id?: unknown}} | null | undefined)?.shape?.id;\n return typeof uri === 'string' && uri ? uri : undefined;\n};\n\nexport abstract class LinkedStorage {\n\n /** plan-011 — how many physical copies of this module have evaluated. */\n static getLoadedInstanceCount(): number {\n return linkedStorageGlobal.__linkedStorageInstanceCount ?? 0;\n }\n\n static isInitialised() {\n return !!routingState.defaultDataset;\n }\n\n /** The catch-all IDataset for shapes with no explicit mapping. */\n static getDefaultDataset() {\n return routingState.defaultDataset;\n }\n\n /** Set the default IDataset (catch-all for shapes with no explicit mapping). */\n static setDefaultDataset(dataset: IDataset) {\n routingState.defaultDataset = dataset;\n if (routingState.defaultDataset?.init) {\n routingState.defaultDataset.init();\n }\n setQueryDispatch({\n selectQuery: (q) => this.selectQuery(q),\n askQuery: (q) => this.askQuery(q),\n createQuery: (q) => this.createQuery(q),\n updateQuery: (q) => this.updateQuery(q),\n deleteQuery: (q) => this.deleteQuery(q),\n });\n }\n\n /** Pin one or more shape classes to a specific IDataset implementer. */\n static setDatasetForShapes(dataset: IDataset, ...shapeClasses: Function[]) {\n shapeClasses.forEach((shapeClass) => {\n // A shape's IRI is its identity, so two classes claiming the same IRI are the\n // same shape and must not route to different datasets. That situation is a\n // duplicate-registration bug elsewhere; say so here rather than resolving it by\n // Map insertion order, which is silent and arbitrary.\n const uri = shapeUriOf(shapeClass);\n if (uri) {\n for (const [pinned, existing] of routingState.shapeToDataset) {\n if (pinned !== shapeClass && shapeUriOf(pinned) === uri && existing !== dataset) {\n console.warn(\n `[linked] Two different classes are pinned to '${uri}' with different ` +\n `datasets. They are the same shape by identity, so one of these pins ` +\n `will be ignored. This usually means the shape class was registered twice.`,\n );\n }\n }\n }\n routingState.shapeToDataset.set(shapeClass, dataset);\n });\n }\n\n /**\n * Remove the pin for a shape, by class or by IRI.\n *\n * Removes **every** entry sharing that IRI, not just the one class object handed in.\n * Deleting by class identity alone is not enough: resolution falls back to matching\n * on IRI, so another class claiming the same shape would silently resurrect the pin\n * the caller believed they had removed.\n */\n static unsetDatasetForShape(shape: Function | string): void {\n const uri = typeof shape === 'string' ? shape : shapeUriOf(shape);\n routingState.shapeToDataset.delete(shape as Function);\n if (!uri) return;\n for (const pinned of [...routingState.shapeToDataset.keys()]) {\n if (shapeUriOf(pinned) === uri) {\n routingState.shapeToDataset.delete(pinned);\n }\n }\n }\n\n /** Every IDataset known to the primary router (default + all pinned). */\n static getDatasets(): CoreSet<IDataset> {\n const datasets = new CoreSet<IDataset>();\n if (routingState.defaultDataset) {\n datasets.add(routingState.defaultDataset);\n }\n routingState.shapeToDataset.forEach((dataset) => datasets.add(dataset));\n return datasets;\n }\n\n /**\n * The live shape→IDataset map — not a copy.\n *\n * Mutating it works but is not the supported way to remove a pin: deleting a key\n * here removes one class object, and resolution falls back to matching on shape IRI,\n * so another class claiming the same shape resurrects the pin. Use\n * `unsetDatasetForShape`, which removes every entry for that identity.\n */\n static getShapeToDatasetMap(): Map<Function, IDataset> {\n return routingState.shapeToDataset;\n }\n\n /** Resolve the IDataset for a given shape class. Walks the prototype chain. */\n static getDatasetForShapeClass(shapeClass?: Function | null): IDataset | undefined {\n let current: Function | null = shapeClass ?? null;\n while (typeof current === 'function') {\n const dataset = routingState.shapeToDataset.get(current);\n if (dataset) {\n return dataset;\n }\n const parent = Object.getPrototypeOf(current);\n if (parent === Function.prototype || parent === null) break;\n current = parent;\n }\n // Only once the identity walk has failed. `static shape` is inherited, so running\n // this at every level of the chain repeated the same scan for the same IRI.\n return this.findPinByShapeUri(shapeClass) ?? routingState.defaultDataset;\n }\n\n /**\n * The same pins, matched on shape IRI rather than on class identity.\n *\n * A class object is only a usable key while exactly one copy of the module\n * that declares it has evaluated, and in a built app there is not: the\n * backend runs from `lib/`, while `linked.backend.storage` is loaded from the\n * app root and imports the app's shapes from `src/`. The pin lands on one\n * copy of a shape class and the query resolves the other. The two are `!==`,\n * the lookup misses, and the query silently falls through to the default\n * dataset — which is how a shape that IS pinned reaches the app-data router\n * and fails there. Dev loads both halves from `src`, so it only breaks in\n * production.\n *\n * A shape's IRI does not have that problem: it is the shape's identity, it is\n * what the query already carries on the wire, and every copy derives the same\n * one. So it is the key that survives duplication.\n *\n * Deliberately a scan of the one map rather than a second map kept alongside it:\n * one source of truth, over a map holding a few dozen entries, on a path only\n * reached after an identity lookup has already failed.\n */\n private static findPinByShapeUri(shapeClass?: Function | null): IDataset | undefined {\n const uri = shapeUriOf(shapeClass);\n if (!uri) return undefined;\n for (const [pinned, dataset] of routingState.shapeToDataset) {\n if (shapeUriOf(pinned) === uri) {\n return dataset;\n }\n }\n return undefined;\n }\n\n private static resolveDatasetForQueryShape(\n shape?: string | Function | NodeShapeData | null,\n ): IDataset | undefined {\n if (!shape) {\n return routingState.defaultDataset;\n }\n if (typeof shape === 'function') {\n return this.getDatasetForShapeClass(shape);\n }\n if (typeof shape === 'string') {\n const shapeClass = getShapeClass(shape);\n return this.getDatasetForShapeClass(shapeClass);\n }\n // NodeShapeData (the closed query's `shape` accessor) — resolve via its IRI.\n if (typeof shape === 'object' && 'id' in shape) {\n const shapeClass = getShapeClass((shape as {id: string}).id);\n return this.getDatasetForShapeClass(shapeClass);\n }\n return routingState.defaultDataset;\n }\n\n /**\n * Route a select query — **and a count**, which is a select.\n *\n * A count is not a separate query form (an ask is: `ASK WHERE { … }`); it is\n * `SELECT (COUNT(DISTINCT ?s) AS ?count) WHERE { … }`, routed by the same shape to\n * the same dataset and answered over the same channel. So it needs no arm of its\n * own here — which is the point: when it had one, this router was missing it, and\n * `.count()` failed on every path that went through the router while passing\n * against a store held directly.\n *\n * The count contract — a real, non-negative integer, a failure never flattened\n * into `0` — belongs to `resolveCount`, which the builder goes through. None of it\n * is re-implemented here, exactly as none of `resolveExistence` is.\n */\n static selectQuery<ResultType>(\n query: SelectQuery | CountQuery,\n ): Promise<ResultType> {\n if (!query?.shape) {\n return Promise.reject(\n new Error(\n 'Invalid select query passed to LinkedStorage.selectQuery(): missing shape.',\n ),\n );\n }\n const dataset = this.resolveDatasetForQueryShape(query.shape);\n if (!dataset?.selectQuery) {\n return Promise.reject(\n new Error('No query dataset configured. Call LinkedStorage.setDefaultDataset().'),\n );\n }\n return dataset.selectQuery(query) as Promise<ResultType>;\n }\n\n /**\n * Route an ask query.\n *\n * A **shaped** ask routes like every other query — by its shape, to one dataset.\n *\n * A **shapeless** ask (\"does a node with this IRI exist at all\") has no shape,\n * and therefore no routing key. Asking only the default dataset would answer\n * `false` for a node that exists in a pinned one — a wrong answer, quietly. So a\n * router must ask every dataset it knows and OR the results. That is cheap\n * precisely because the answers are booleans: the fan-out short-circuits on the\n * first `true`, where the same sweep for rows could not.\n *\n * Any other router implementing `IDataset` inherits this obligation: a shapeless\n * ask means \"anywhere I can reach\", not \"in my default store\".\n *\n * The contract itself — a real boolean, errors never flattened to `false` —\n * belongs to `resolveExistence`, which the builder also goes through. None of it\n * is re-implemented here.\n */\n static async askQuery(query: AskQuery): Promise<boolean> {\n if (!query?.shape) {\n return this.askAnyDataset(query);\n }\n const dataset = this.resolveDatasetForQueryShape(query.shape);\n if (!dataset) {\n throw new Error(\n 'No query dataset configured. Call LinkedStorage.setDefaultDataset().',\n );\n }\n return resolveExistence(dataset, query);\n }\n\n /**\n * Fan a shapeless ask out across every known dataset, resolving `true` as soon\n * as one answers `true`.\n *\n * Sequential rather than parallel: the common case is a single dataset, and an\n * early `true` should not have already cost a query against every other store.\n * A failure from any dataset propagates — an unreachable store makes the answer\n * unknown, and \"unknown\" is not `false`.\n */\n private static async askAnyDataset(query: AskQuery): Promise<boolean> {\n const datasets = this.getDatasets();\n if (datasets.size === 0) {\n throw new Error(\n 'No query dataset configured. Call LinkedStorage.setDefaultDataset().',\n );\n }\n for (const dataset of datasets) {\n if (await resolveExistence(dataset, query)) return true;\n }\n return false;\n }\n\n static updateQuery<ResponseType>(query: UpdateQuery): Promise<ResponseType> {\n if (!query?.shape) {\n return Promise.reject(\n new Error(\n 'Invalid update query passed to LinkedStorage.updateQuery(): missing shape.',\n ),\n );\n }\n const dataset = this.resolveDatasetForQueryShape(query.shape);\n if (!dataset?.updateQuery) {\n return Promise.reject(\n new Error('No update handler configured on the query dataset.'),\n );\n }\n return dataset.updateQuery(query) as Promise<ResponseType>;\n }\n\n static createQuery<ResponseType>(query: CreateQuery): Promise<ResponseType> {\n if (!query?.shape) {\n return Promise.reject(\n new Error(\n 'Invalid create query passed to LinkedStorage.createQuery(): missing shape.',\n ),\n );\n }\n const dataset = this.resolveDatasetForQueryShape(query.shape);\n if (!dataset?.createQuery) {\n return Promise.reject(\n new Error('No create handler configured on the query dataset.'),\n );\n }\n return dataset.createQuery(query) as Promise<ResponseType>;\n }\n\n static deleteQuery(query: DeleteQuery): Promise<DeleteResponse> {\n if (!query?.shape) {\n return Promise.reject(\n new Error(\n 'Invalid delete query passed to LinkedStorage.deleteQuery(): missing shape.',\n ),\n );\n }\n const dataset = this.resolveDatasetForQueryShape(query.shape);\n if (!dataset?.deleteQuery) {\n return Promise.reject(\n new Error('No delete handler configured on the query dataset.'),\n );\n }\n return dataset.deleteQuery(query);\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"LinkedStorage.js","sourceRoot":"","sources":["../../../src/utils/LinkedStorage.ts"],"names":[],"mappings":"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","sourcesContent":["import {CoreSet} from '../collections/CoreSet.js';\nimport type {IDataset} from '../interfaces/IDataset.js';\nimport type {SelectQuery} from '../queries/SelectQuery.js';\nimport type {AskQuery} from '../queries/AskQuery.js';\nimport type {CountQuery} from '../queries/CountQuery.js';\nimport type {CreateQuery} from '../queries/CreateQuery.js';\nimport type {UpdateQuery} from '../queries/UpdateQuery.js';\nimport type {DeleteQuery, DeleteResponse} from '../queries/DeleteQuery.js';\nimport {setQueryDispatch, resolveExistence} from '../queries/queryDispatch.js';\nimport {getShapeClass} from './ShapeClass.js';\nimport type {NodeShapeData} from '../shapes/SHACL.js';\n\n// plan-011 — count physical evaluations of THIS module on the one shared\n// global object. With the single-loader fix there should be exactly one copy;\n// the single-instance guard in backend.ts reports this count if storage config\n// ever lands on a different copy. Deliberately avoids Date/Math.random\n// (unavailable / non-deterministic per repo constraints).\nconst linkedStorageGlobal: any =\n typeof globalThis !== 'undefined' ? globalThis : ({} as any);\nlinkedStorageGlobal.__linkedStorageInstanceCount =\n (linkedStorageGlobal.__linkedStorageInstanceCount ?? 0) + 1;\n\n/**\n * Primary routing layer (arch-04 §The IDataset abstraction).\n *\n * Resolves an incoming Linked Query to the IDataset that should handle it,\n * based on the query's target shape. Composite IDatasets (gateways, routers,\n * forwarders, resolvers) plug in here just like storage IDatasets do.\n *\n * The \"Dataset\" naming aligns with the IDataset contract. Earlier \"Store\"\n * names were renamed in phase-1 — see docs/plans/002-phase-1-create-user-project-flow.md.\n */\n/**\n * The routing table lives on the shared global, beside the shape registries.\n *\n * It has to, for the same reason they do: a module can evaluate more than once in a\n * process, and a class static then exists once per copy. Leaving these two here while\n * the registries were shared was worse than either extreme — a second copy answered\n * `isInitialised()` with false and `getDatasetForShapeClass()` with the default, while\n * reporting a fully populated shape registry.\n */\nconst routingState: {\n defaultDataset?: IDataset;\n shapeToDataset: Map<Function, IDataset>;\n listeners?: Set<() => void>;\n} = (linkedStorageGlobal.__linkedStorageRouting ??= {\n defaultDataset: undefined,\n shapeToDataset: new Map(),\n listeners: new Set(),\n});\n// An older copy of this module may have created the record without listeners.\nroutingState.listeners ??= new Set();\n\n/** Tell routing-change listeners that the set of datasets may have changed. */\nfunction notifyRoutingChanged(): void {\n for (const listener of [...routingState.listeners!]) {\n try {\n listener();\n } catch (err) {\n console.error('[linked] routing-change listener failed', err);\n }\n }\n}\n\n/** A shape class's IRI, or undefined for anything that is not a registered shape. */\nconst shapeUriOf = (shapeClass?: Function | null): string | undefined => {\n const uri = (shapeClass as {shape?: {id?: unknown}} | null | undefined)?.shape?.id;\n return typeof uri === 'string' && uri ? uri : undefined;\n};\n\nexport abstract class LinkedStorage {\n\n /** plan-011 — how many physical copies of this module have evaluated. */\n static getLoadedInstanceCount(): number {\n return linkedStorageGlobal.__linkedStorageInstanceCount ?? 0;\n }\n\n static isInitialised() {\n return !!routingState.defaultDataset;\n }\n\n /** The catch-all IDataset for shapes with no explicit mapping. */\n static getDefaultDataset() {\n return routingState.defaultDataset;\n }\n\n /** Set the default IDataset (catch-all for shapes with no explicit mapping). */\n static setDefaultDataset(dataset: IDataset) {\n routingState.defaultDataset = dataset;\n if (routingState.defaultDataset?.init) {\n routingState.defaultDataset.init();\n }\n setQueryDispatch({\n selectQuery: (q) => this.selectQuery(q),\n askQuery: (q) => this.askQuery(q),\n createQuery: (q) => this.createQuery(q),\n updateQuery: (q) => this.updateQuery(q),\n deleteQuery: (q) => this.deleteQuery(q),\n });\n notifyRoutingChanged();\n }\n\n /**\n * Be told whenever the set of datasets changes (`setDefaultDataset`,\n * `setDatasetForShapes`, `unsetDatasetForShape`). The live-query store uses\n * this to pick up a dataset's change feed. Returns the unsubscribe function.\n */\n static onRoutingChanged(listener: () => void): () => void {\n routingState.listeners!.add(listener);\n return () => routingState.listeners!.delete(listener);\n }\n\n /** Pin one or more shape classes to a specific IDataset implementer. */\n static setDatasetForShapes(dataset: IDataset, ...shapeClasses: Function[]) {\n shapeClasses.forEach((shapeClass) => {\n // A shape's IRI is its identity, so two classes claiming the same IRI are the\n // same shape and must not route to different datasets. That situation is a\n // duplicate-registration bug elsewhere; say so here rather than resolving it by\n // Map insertion order, which is silent and arbitrary.\n const uri = shapeUriOf(shapeClass);\n if (uri) {\n for (const [pinned, existing] of routingState.shapeToDataset) {\n if (pinned !== shapeClass && shapeUriOf(pinned) === uri && existing !== dataset) {\n console.warn(\n `[linked] Two different classes are pinned to '${uri}' with different ` +\n `datasets. They are the same shape by identity, so one of these pins ` +\n `will be ignored. This usually means the shape class was registered twice.`,\n );\n }\n }\n }\n routingState.shapeToDataset.set(shapeClass, dataset);\n });\n notifyRoutingChanged();\n }\n\n /**\n * Remove the pin for a shape, by class or by IRI.\n *\n * Removes **every** entry sharing that IRI, not just the one class object handed in.\n * Deleting by class identity alone is not enough: resolution falls back to matching\n * on IRI, so another class claiming the same shape would silently resurrect the pin\n * the caller believed they had removed.\n */\n static unsetDatasetForShape(shape: Function | string): void {\n const uri = typeof shape === 'string' ? shape : shapeUriOf(shape);\n routingState.shapeToDataset.delete(shape as Function);\n if (uri) {\n for (const pinned of [...routingState.shapeToDataset.keys()]) {\n if (shapeUriOf(pinned) === uri) {\n routingState.shapeToDataset.delete(pinned);\n }\n }\n }\n notifyRoutingChanged();\n }\n\n /** Every IDataset known to the primary router (default + all pinned). */\n static getDatasets(): CoreSet<IDataset> {\n const datasets = new CoreSet<IDataset>();\n if (routingState.defaultDataset) {\n datasets.add(routingState.defaultDataset);\n }\n routingState.shapeToDataset.forEach((dataset) => datasets.add(dataset));\n return datasets;\n }\n\n /**\n * The live shape→IDataset map — not a copy.\n *\n * Mutating it works but is not the supported way to remove a pin: deleting a key\n * here removes one class object, and resolution falls back to matching on shape IRI,\n * so another class claiming the same shape resurrects the pin. Use\n * `unsetDatasetForShape`, which removes every entry for that identity.\n */\n static getShapeToDatasetMap(): Map<Function, IDataset> {\n return routingState.shapeToDataset;\n }\n\n /** Resolve the IDataset for a given shape class. Walks the prototype chain. */\n static getDatasetForShapeClass(shapeClass?: Function | null): IDataset | undefined {\n let current: Function | null = shapeClass ?? null;\n while (typeof current === 'function') {\n const dataset = routingState.shapeToDataset.get(current);\n if (dataset) {\n return dataset;\n }\n const parent = Object.getPrototypeOf(current);\n if (parent === Function.prototype || parent === null) break;\n current = parent;\n }\n // Only once the identity walk has failed. `static shape` is inherited, so running\n // this at every level of the chain repeated the same scan for the same IRI.\n return this.findPinByShapeUri(shapeClass) ?? routingState.defaultDataset;\n }\n\n /**\n * The same pins, matched on shape IRI rather than on class identity.\n *\n * A class object is only a usable key while exactly one copy of the module\n * that declares it has evaluated, and in a built app there is not: the\n * backend runs from `lib/`, while `linked.backend.storage` is loaded from the\n * app root and imports the app's shapes from `src/`. The pin lands on one\n * copy of a shape class and the query resolves the other. The two are `!==`,\n * the lookup misses, and the query silently falls through to the default\n * dataset — which is how a shape that IS pinned reaches the app-data router\n * and fails there. Dev loads both halves from `src`, so it only breaks in\n * production.\n *\n * A shape's IRI does not have that problem: it is the shape's identity, it is\n * what the query already carries on the wire, and every copy derives the same\n * one. So it is the key that survives duplication.\n *\n * Deliberately a scan of the one map rather than a second map kept alongside it:\n * one source of truth, over a map holding a few dozen entries, on a path only\n * reached after an identity lookup has already failed.\n */\n private static findPinByShapeUri(shapeClass?: Function | null): IDataset | undefined {\n const uri = shapeUriOf(shapeClass);\n if (!uri) return undefined;\n for (const [pinned, dataset] of routingState.shapeToDataset) {\n if (shapeUriOf(pinned) === uri) {\n return dataset;\n }\n }\n return undefined;\n }\n\n private static resolveDatasetForQueryShape(\n shape?: string | Function | NodeShapeData | null,\n ): IDataset | undefined {\n if (!shape) {\n return routingState.defaultDataset;\n }\n if (typeof shape === 'function') {\n return this.getDatasetForShapeClass(shape);\n }\n if (typeof shape === 'string') {\n const shapeClass = getShapeClass(shape);\n return this.getDatasetForShapeClass(shapeClass);\n }\n // NodeShapeData (the closed query's `shape` accessor) — resolve via its IRI.\n if (typeof shape === 'object' && 'id' in shape) {\n const shapeClass = getShapeClass((shape as {id: string}).id);\n return this.getDatasetForShapeClass(shapeClass);\n }\n return routingState.defaultDataset;\n }\n\n /**\n * Route a select query — **and a count**, which is a select.\n *\n * A count is not a separate query form (an ask is: `ASK WHERE { … }`); it is\n * `SELECT (COUNT(DISTINCT ?s) AS ?count) WHERE { … }`, routed by the same shape to\n * the same dataset and answered over the same channel. So it needs no arm of its\n * own here — which is the point: when it had one, this router was missing it, and\n * `.count()` failed on every path that went through the router while passing\n * against a store held directly.\n *\n * The count contract — a real, non-negative integer, a failure never flattened\n * into `0` — belongs to `resolveCount`, which the builder goes through. None of it\n * is re-implemented here, exactly as none of `resolveExistence` is.\n */\n static selectQuery<ResultType>(\n query: SelectQuery | CountQuery,\n ): Promise<ResultType> {\n if (!query?.shape) {\n return Promise.reject(\n new Error(\n 'Invalid select query passed to LinkedStorage.selectQuery(): missing shape.',\n ),\n );\n }\n const dataset = this.resolveDatasetForQueryShape(query.shape);\n if (!dataset?.selectQuery) {\n return Promise.reject(\n new Error('No query dataset configured. Call LinkedStorage.setDefaultDataset().'),\n );\n }\n return dataset.selectQuery(query) as Promise<ResultType>;\n }\n\n /**\n * Route an ask query.\n *\n * A **shaped** ask routes like every other query — by its shape, to one dataset.\n *\n * A **shapeless** ask (\"does a node with this IRI exist at all\") has no shape,\n * and therefore no routing key. Asking only the default dataset would answer\n * `false` for a node that exists in a pinned one — a wrong answer, quietly. So a\n * router must ask every dataset it knows and OR the results. That is cheap\n * precisely because the answers are booleans: the fan-out short-circuits on the\n * first `true`, where the same sweep for rows could not.\n *\n * Any other router implementing `IDataset` inherits this obligation: a shapeless\n * ask means \"anywhere I can reach\", not \"in my default store\".\n *\n * The contract itself — a real boolean, errors never flattened to `false` —\n * belongs to `resolveExistence`, which the builder also goes through. None of it\n * is re-implemented here.\n */\n static async askQuery(query: AskQuery): Promise<boolean> {\n if (!query?.shape) {\n return this.askAnyDataset(query);\n }\n const dataset = this.resolveDatasetForQueryShape(query.shape);\n if (!dataset) {\n throw new Error(\n 'No query dataset configured. Call LinkedStorage.setDefaultDataset().',\n );\n }\n return resolveExistence(dataset, query);\n }\n\n /**\n * Fan a shapeless ask out across every known dataset, resolving `true` as soon\n * as one answers `true`.\n *\n * Sequential rather than parallel: the common case is a single dataset, and an\n * early `true` should not have already cost a query against every other store.\n * A failure from any dataset propagates — an unreachable store makes the answer\n * unknown, and \"unknown\" is not `false`.\n */\n private static async askAnyDataset(query: AskQuery): Promise<boolean> {\n const datasets = this.getDatasets();\n if (datasets.size === 0) {\n throw new Error(\n 'No query dataset configured. Call LinkedStorage.setDefaultDataset().',\n );\n }\n for (const dataset of datasets) {\n if (await resolveExistence(dataset, query)) return true;\n }\n return false;\n }\n\n static updateQuery<ResponseType>(query: UpdateQuery): Promise<ResponseType> {\n if (!query?.shape) {\n return Promise.reject(\n new Error(\n 'Invalid update query passed to LinkedStorage.updateQuery(): missing shape.',\n ),\n );\n }\n const dataset = this.resolveDatasetForQueryShape(query.shape);\n if (!dataset?.updateQuery) {\n return Promise.reject(\n new Error('No update handler configured on the query dataset.'),\n );\n }\n return dataset.updateQuery(query) as Promise<ResponseType>;\n }\n\n static createQuery<ResponseType>(query: CreateQuery): Promise<ResponseType> {\n if (!query?.shape) {\n return Promise.reject(\n new Error(\n 'Invalid create query passed to LinkedStorage.createQuery(): missing shape.',\n ),\n );\n }\n const dataset = this.resolveDatasetForQueryShape(query.shape);\n if (!dataset?.createQuery) {\n return Promise.reject(\n new Error('No create handler configured on the query dataset.'),\n );\n }\n return dataset.createQuery(query) as Promise<ResponseType>;\n }\n\n static deleteQuery(query: DeleteQuery): Promise<DeleteResponse> {\n if (!query?.shape) {\n return Promise.reject(\n new Error(\n 'Invalid delete query passed to LinkedStorage.deleteQuery(): missing shape.',\n ),\n );\n }\n const dataset = this.resolveDatasetForQueryShape(query.shape);\n if (!dataset?.deleteQuery) {\n return Promise.reject(\n new Error('No delete handler configured on the query dataset.'),\n );\n }\n return dataset.deleteQuery(query);\n }\n}\n"]}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type Shape, type ShapeConstructor } from '../shapes/Shape.js';
|
|
2
2
|
import { type NodeShapeData, type PropertyShapeData } from '../shapes/nodeShapeData.js';
|
|
3
|
+
import type { NodeShapeWire } from '../shapes/nodeShapeWire.js';
|
|
3
4
|
import type { ICoreIterable } from '../interfaces/ICoreIterable.js';
|
|
4
5
|
import type { NodeReferenceValue } from './NodeReference.js';
|
|
5
6
|
/** How many distinct copies of this module are loaded. One is expected. */
|
|
@@ -72,6 +73,31 @@ export declare function getSuperShapes(shape: ShapeLike): NodeShapeData[];
|
|
|
72
73
|
export declare function getSubShapes(shape: ShapeLike): NodeShapeData[];
|
|
73
74
|
/** True when `a` extends `b` (strictly — a shape is not a sub-shape of itself). */
|
|
74
75
|
export declare function isSubShapeOf(a: ShapeLike, b: ShapeLike): boolean;
|
|
76
|
+
/**
|
|
77
|
+
* The class a shape's instances are typed with: its own `targetClass`, else the first one
|
|
78
|
+
* found through what it extends. `undefined` when there is none anywhere in the chain.
|
|
79
|
+
*
|
|
80
|
+
* Accepts a shape IRI, a `{id}` reference, a shape's metadata (data or wire form) or a shape
|
|
81
|
+
* class. Pass `shapes` to resolve the shape — and what it extends — in that set before the
|
|
82
|
+
* registry; a project's catalog may hold shapes the registry does not.
|
|
83
|
+
*/
|
|
84
|
+
export declare function getTargetClassId(shape: ShapeLike | NodeShapeWire | {
|
|
85
|
+
id: string;
|
|
86
|
+
}, shapes?: Iterable<NodeShapeData | NodeShapeWire>): string | undefined;
|
|
87
|
+
/**
|
|
88
|
+
* The least specific shapes whose effective targetClass (own, or inherited through
|
|
89
|
+
* `extends`) is exactly `classIri`, sorted by id. A matching shape that extends another
|
|
90
|
+
* match is left out, so one entry means the class has one root shape and more than one
|
|
91
|
+
* means unrelated roots compete for it. Sub-shapes are never chosen for a class alone.
|
|
92
|
+
*
|
|
93
|
+
* With no `shapes`, the candidates are the registered shapes. Pass `shapes` to choose among
|
|
94
|
+
* that set only — the registry also holds compiled framework shapes, and a project's
|
|
95
|
+
* `schema:Person` relation should resolve to the project's shape, not to one a framework
|
|
96
|
+
* package happens to register for the same class. Inheritance is still resolved through
|
|
97
|
+
* the registry when a candidate extends a shape outside the set.
|
|
98
|
+
*/
|
|
99
|
+
export declare function getShapesForTargetClass(classIri: string): NodeShapeData[];
|
|
100
|
+
export declare function getShapesForTargetClass<S extends NodeShapeData | NodeShapeWire>(classIri: string, shapes: Iterable<S>): S[];
|
|
75
101
|
export declare function addNodeShapeToShapeClass(nodeShape: NodeShapeData, shapeClass: typeof Shape): void;
|
|
76
102
|
/**
|
|
77
103
|
* The constructor for a shape IRI — an authored class if there is one, otherwise one
|
|
@@ -136,6 +136,7 @@ function invalidateRegistryCaches() {
|
|
|
136
136
|
subShapesCache.clear();
|
|
137
137
|
mostSpecificSubShapesCache.clear();
|
|
138
138
|
childIndex = null;
|
|
139
|
+
targetClassIndex = null;
|
|
139
140
|
}
|
|
140
141
|
/** Drop the adapter for a shape whose metadata was replaced. */
|
|
141
142
|
function invalidateShapeAdapter(id) {
|
|
@@ -332,6 +333,133 @@ export function isSubShapeOf(a, b) {
|
|
|
332
333
|
return false;
|
|
333
334
|
return getSuperShapes(a).some((superShape) => superShape.id === target.id);
|
|
334
335
|
}
|
|
336
|
+
/**
|
|
337
|
+
* Every shape `shape` extends, most specific first — resolving each parent in `local`
|
|
338
|
+
* before the registry.
|
|
339
|
+
*
|
|
340
|
+
* `local` is a caller's own set of shapes (a project's catalog), which may hold shapes the
|
|
341
|
+
* registry has never seen, or newer versions of ones it has. The catalog is the authority
|
|
342
|
+
* for what it holds; once the chain leaves it, the registry knows the rest.
|
|
343
|
+
*/
|
|
344
|
+
function superShapesWithin(shape, local) {
|
|
345
|
+
var _a;
|
|
346
|
+
if (!local)
|
|
347
|
+
return getSuperShapes(shape);
|
|
348
|
+
const chain = [];
|
|
349
|
+
const seen = new Set([shape.id]);
|
|
350
|
+
let current = shape;
|
|
351
|
+
while ((_a = current.extends) === null || _a === void 0 ? void 0 : _a.id) {
|
|
352
|
+
const parentId = current.extends.id;
|
|
353
|
+
if (seen.has(parentId))
|
|
354
|
+
break; // cycle guard — malformed data must not hang a read
|
|
355
|
+
seen.add(parentId);
|
|
356
|
+
const parent = local.get(parentId);
|
|
357
|
+
if (!parent) {
|
|
358
|
+
const registered = nodeShapeRegistry.get(parentId);
|
|
359
|
+
if (registered)
|
|
360
|
+
chain.push(registered, ...getSuperShapes(registered));
|
|
361
|
+
break;
|
|
362
|
+
}
|
|
363
|
+
chain.push(parent);
|
|
364
|
+
current = parent;
|
|
365
|
+
}
|
|
366
|
+
return chain;
|
|
367
|
+
}
|
|
368
|
+
function indexShapes(shapes) {
|
|
369
|
+
const index = new Map();
|
|
370
|
+
for (const shape of shapes)
|
|
371
|
+
if (shape === null || shape === void 0 ? void 0 : shape.id)
|
|
372
|
+
index.set(shape.id, shape);
|
|
373
|
+
return index;
|
|
374
|
+
}
|
|
375
|
+
function targetClassIdWithin(shape, local) {
|
|
376
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
|
|
377
|
+
if (!shape)
|
|
378
|
+
return undefined;
|
|
379
|
+
if (typeof shape === 'function') {
|
|
380
|
+
// A class's static targetClass is inherited through the prototype chain for free.
|
|
381
|
+
const asClass = shape;
|
|
382
|
+
if ((_a = asClass.targetClass) === null || _a === void 0 ? void 0 : _a.id)
|
|
383
|
+
return asClass.targetClass.id;
|
|
384
|
+
if (!((_b = asClass.shape) === null || _b === void 0 ? void 0 : _b.id))
|
|
385
|
+
return undefined;
|
|
386
|
+
shape = asClass.shape;
|
|
387
|
+
}
|
|
388
|
+
const id = typeof shape === 'string' ? shape : shape.id;
|
|
389
|
+
if (!id)
|
|
390
|
+
return undefined;
|
|
391
|
+
const given = typeof shape === 'string' ? undefined : shape;
|
|
392
|
+
const own = (_k = (_g = (_d = (_c = given === null || given === void 0 ? void 0 : given.targetClass) === null || _c === void 0 ? void 0 : _c.id) !== null && _d !== void 0 ? _d : (_f = (_e = local === null || local === void 0 ? void 0 : local.get(id)) === null || _e === void 0 ? void 0 : _e.targetClass) === null || _f === void 0 ? void 0 : _f.id) !== null && _g !== void 0 ? _g : (_j = (_h = getShapeClass(id)) === null || _h === void 0 ? void 0 : _h.targetClass) === null || _j === void 0 ? void 0 : _j.id) !== null && _k !== void 0 ? _k : (_m = (_l = nodeShapeRegistry.get(id)) === null || _l === void 0 ? void 0 : _l.targetClass) === null || _m === void 0 ? void 0 : _m.id;
|
|
393
|
+
if (own)
|
|
394
|
+
return own;
|
|
395
|
+
// A data-only shape's targetClass is not inherited for free, so walk `extends`.
|
|
396
|
+
const start = (_o = local === null || local === void 0 ? void 0 : local.get(id)) !== null && _o !== void 0 ? _o : ((given === null || given === void 0 ? void 0 : given.extends) ? given : (_p = nodeShapeRegistry.get(id)) !== null && _p !== void 0 ? _p : given);
|
|
397
|
+
if (!start)
|
|
398
|
+
return undefined;
|
|
399
|
+
return (_r = (_q = superShapesWithin(start, local).find((s) => { var _a; return (_a = s.targetClass) === null || _a === void 0 ? void 0 : _a.id; })) === null || _q === void 0 ? void 0 : _q.targetClass) === null || _r === void 0 ? void 0 : _r.id;
|
|
400
|
+
}
|
|
401
|
+
/**
|
|
402
|
+
* The class a shape's instances are typed with: its own `targetClass`, else the first one
|
|
403
|
+
* found through what it extends. `undefined` when there is none anywhere in the chain.
|
|
404
|
+
*
|
|
405
|
+
* Accepts a shape IRI, a `{id}` reference, a shape's metadata (data or wire form) or a shape
|
|
406
|
+
* class. Pass `shapes` to resolve the shape — and what it extends — in that set before the
|
|
407
|
+
* registry; a project's catalog may hold shapes the registry does not.
|
|
408
|
+
*/
|
|
409
|
+
export function getTargetClassId(shape, shapes) {
|
|
410
|
+
return targetClassIdWithin(shape, shapes ? indexShapes(shapes) : undefined);
|
|
411
|
+
}
|
|
412
|
+
/**
|
|
413
|
+
* The least specific candidates (the roots), by id. A candidate that extends another
|
|
414
|
+
* candidate (directly or further up) is dropped: a relation to `Person` with `Person` and
|
|
415
|
+
* `Employee extends Person` both targeting it means `Person` — a relation never upgrades
|
|
416
|
+
* itself to a sub-shape; declare `sh:node` to ask for one. What remains are unrelated roots
|
|
417
|
+
* the data does not choose between; they sort by id alone — never by depth or by
|
|
418
|
+
* registration or catalog order — so the choice is stable and visibly arbitrary. If that
|
|
419
|
+
* would drop every candidate (an `extends` cycle), all of them are kept, by id.
|
|
420
|
+
*/
|
|
421
|
+
function leastSpecific(candidates, local) {
|
|
422
|
+
const ids = new Set(candidates.map((c) => c.id));
|
|
423
|
+
const byId = (a, b) => (a.id < b.id ? -1 : a.id > b.id ? 1 : 0);
|
|
424
|
+
const roots = candidates.filter((candidate) => !superShapesWithin(candidate, local).some((parent) => ids.has(parent.id)));
|
|
425
|
+
// An `extends` cycle makes each member extend another, so the filter can leave nothing.
|
|
426
|
+
// Malformed data must not turn a relation into "no shape" silently: keep every candidate
|
|
427
|
+
// instead, by id, and let the caller's ambiguity handling (warn) apply.
|
|
428
|
+
return (roots.length ? roots : [...candidates]).sort(byId);
|
|
429
|
+
}
|
|
430
|
+
/** targetClass IRI → registered shapes targeting it, ordered. Rebuilt when the registry changes. */
|
|
431
|
+
let targetClassIndex = null;
|
|
432
|
+
let targetClassIndexVersion = -1;
|
|
433
|
+
function getTargetClassIndex() {
|
|
434
|
+
if (targetClassIndex && targetClassIndexVersion === registryState.registryVersion) {
|
|
435
|
+
return targetClassIndex;
|
|
436
|
+
}
|
|
437
|
+
const index = new Map();
|
|
438
|
+
nodeShapeRegistry.forEach((shape) => {
|
|
439
|
+
const classId = targetClassIdWithin(shape);
|
|
440
|
+
if (!classId)
|
|
441
|
+
return;
|
|
442
|
+
const shapes = index.get(classId);
|
|
443
|
+
if (shapes)
|
|
444
|
+
shapes.push(shape);
|
|
445
|
+
else
|
|
446
|
+
index.set(classId, [shape]);
|
|
447
|
+
});
|
|
448
|
+
index.forEach((shapes, classId) => index.set(classId, leastSpecific(shapes)));
|
|
449
|
+
targetClassIndex = index;
|
|
450
|
+
targetClassIndexVersion = registryState.registryVersion;
|
|
451
|
+
return index;
|
|
452
|
+
}
|
|
453
|
+
export function getShapesForTargetClass(classIri, shapes) {
|
|
454
|
+
var _a;
|
|
455
|
+
if (!classIri)
|
|
456
|
+
return [];
|
|
457
|
+
if (!shapes)
|
|
458
|
+
return [...((_a = getTargetClassIndex().get(classIri)) !== null && _a !== void 0 ? _a : [])];
|
|
459
|
+
const local = indexShapes(shapes);
|
|
460
|
+
const candidates = [...local.values()].filter((shape) => targetClassIdWithin(shape, local) === classIri);
|
|
461
|
+
return leastSpecific(candidates, local);
|
|
462
|
+
}
|
|
335
463
|
export function addNodeShapeToShapeClass(nodeShape, shapeClass) {
|
|
336
464
|
var _a, _b;
|
|
337
465
|
if (!(nodeShape === null || nodeShape === void 0 ? void 0 : nodeShape.id)) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ShapeClass.js","sourceRoot":"","sources":["../../../src/utils/ShapeClass.ts"],"names":[],"mappings":"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","sourcesContent":["import {type Shape, type ShapeConstructor} from '../shapes/Shape.js';\n// Namespace import, read at CALL time rather than captured at module-evaluation time.\n// `getOrCreateShapeAdapter` subclasses `Shape` at runtime, and under some import orders this\n// module finishes evaluating before `Shape.js` does — a named import captured then is\n// permanently `undefined`, and the subclass fails with \"Class extends value undefined\".\nimport * as ShapeModule from '../shapes/Shape.js';\nimport {\n getPropertyShape,\n type NodeShapeData,\n type PropertyShapeData,\n} from '../shapes/nodeShapeData.js';\nimport type {ICoreIterable} from '../interfaces/ICoreIterable.js';\nimport type {NodeReferenceValue} from './NodeReference.js';\n\nconst resolveTargetClassId = (\n targetClass?: NodeReferenceValue | null,\n): string | null => {\n if (!targetClass) return null;\n return targetClass.id ?? null;\n};\n\n/**\n * The shape registries live on `globalThis`, not in module scope.\n *\n * A module can evaluate more than once in one process, and in a built app it does: an\n * app's backend is assembled from two graphs, one loaded by the bundler from `src/` and\n * one resolved by Node to `lib/esm/`. A module-scope `Map` then exists twice — shapes\n * register into one copy and every lookup reads the other, which finds nothing.\n *\n * The symptom never mentions module identity. It is `Invalid property key: projectSlug.\n * The shape Project does not have a registered property with this name` for a property\n * that is declared correctly two files away, because validation ran on the copy the\n * decorators never reached. See docs/reports/043-module-identity-in-the-backend.md.\n *\n * Sharing the state makes duplication harmless rather than merely absent: the graphs\n * still hold two copies of this module, but only one registry. `LinkedStorage` already\n * keeps its instance counter here; this keeps the data itself.\n */\nconst shapeRegistryGlobal: any =\n typeof globalThis !== 'undefined' ? globalThis : ({} as any);\n\n/**\n * Counts DISTINCT physical copies of this module, not evaluations of it.\n *\n * The difference matters. A bare `count++` here is incremented by Vite's HMR every time\n * the module is re-evaluated in the same process, against the same `globalThis` — so a\n * developer who edits a file a few times sees a count of 4 and goes hunting a\n * dual-resolution problem that does not exist. Recording a token per copy and counting\n * the tokens survives re-evaluation: HMR replaces the module, and its token with it.\n */\nconst copyToken: object = {};\nconst copies: Set<object> = (shapeRegistryGlobal.__linkedShapeRegistryCopies ??= new Set());\ncopies.add(copyToken);\n\n/**\n * More than one copy of this module means shapes register into one registry and are\n * looked up in another, and the resulting failures never mention module identity — they\n * say a declared property is not declared, or that a pinned shape has no pin.\n *\n * Reported rather than thrown. A throw from a library module at import time breaks\n * tooling that legitimately loads a module twice, and the shared state above means a\n * second copy is survivable: it is a correctness hazard for anything holding a class\n * reference, not an immediate failure. So this says so, once, as loudly as a log can.\n */\nif (copies.size > 1) {\n console.error(\n `[linked] ${copies.size} copies of @_linked/core's shape registry have loaded in ` +\n `this process. They share one registry, so lookups still resolve — but each copy ` +\n `has its own \\`Shape\\` base class, so \\`instanceof\\` comparisons across them are ` +\n `false and adapters built by one copy do not satisfy the other. This is a module ` +\n `resolution problem: part of the app is reaching this package by a path that ` +\n `resolves to its source and part by one that resolves to its build output.`,\n );\n}\n\n/**\n * One shared container, created by whichever copy evaluates first.\n *\n * `registryVersion` belongs here too: every derived cache in this module is keyed on it,\n * so a version that is not shared would let one copy's writes leave another copy's caches\n * looking valid. The caches themselves stay per-copy — they are rebuilt whenever the\n * shared version moves past them.\n */\nconst registryState: {\n nodeShapeToShapeClass: Map<string, typeof Shape>;\n nodeShapeRegistry: Map<string, NodeShapeData>;\n shapeAdapters: Map<string, typeof Shape>;\n registryVersion: number;\n} = (shapeRegistryGlobal.__linkedShapeRegistry ??= {\n nodeShapeToShapeClass: new Map(),\n nodeShapeRegistry: new Map(),\n shapeAdapters: new Map(),\n registryVersion: 0,\n});\n\n/** How many distinct copies of this module are loaded. One is expected. */\nexport function getShapeRegistryInstanceCount(): number {\n return copies.size;\n}\n\nlet subShapesCache: Map<string, (typeof Shape)[]> = new Map();\nlet mostSpecificSubShapesCache: Map<string, (typeof Shape)[]> = new Map();\nconst nodeShapeToShapeClass = registryState.nodeShapeToShapeClass;\nconst warnedDuplicateBases = new Set<string>();\n\n/**\n * The PRIMARY shape registry: node-shape IRI → its metadata.\n *\n * Every shape is here — those declared by a `@linkedShape` class and those known only\n * as data (a project-authored shape read from the graph). `nodeShapeToShapeClass` above\n * is the SECONDARY registry, holding only the shapes that have a TypeScript class, and\n * exists for the few callers that genuinely need a class (a `ShapeProvider` lookup, a\n * typed accessor). Query lowering, predicate resolution and containment all read\n * metadata, so they use this map and work identically for both kinds of shape.\n */\nconst nodeShapeRegistry = registryState.nodeShapeRegistry;\n\n/** Version the sub-shape caches above were filled at. */\nlet subShapesCacheVersion = -1;\n\n/**\n * The current registration version — a monotonic counter, bumped on every write.\n *\n * Every derived cache in this module, and in `irToAlgebra`, is keyed on it. It replaces\n * two earlier invalidation strategies that were both unsound: a `setTimeout(…, 0)` cache\n * clear (which missed anything registered later in the same session) and comparing the\n * registry SIZE (which silently reuses a stale cache when a registration and a removal\n * coincide, or when a shape is re-registered in place).\n *\n * It lives on the shared state, not in module scope: a cache keyed on a per-copy version\n * would look valid after another copy had written.\n */\nexport function getRegistryVersion(): number {\n return registryState.registryVersion;\n}\n\n/** Reverse index parentIri → direct child IRIs, rebuilt when the registry changes. */\nlet childIndex: Map<string, string[]> | null = null;\nlet childIndexVersion = -1;\n\nfunction getChildIndex(): Map<string, string[]> {\n if (childIndex && childIndexVersion === registryState.registryVersion) return childIndex;\n const index = new Map<string, string[]>();\n nodeShapeRegistry.forEach((shape, id) => {\n const parent = shape.extends?.id;\n if (!parent) return;\n const siblings = index.get(parent);\n if (siblings) siblings.push(id);\n else index.set(parent, [id]);\n });\n childIndex = index;\n childIndexVersion = registryState.registryVersion;\n return index;\n}\n\nfunction invalidateRegistryCaches() {\n registryState.registryVersion++;\n subShapesCache.clear();\n mostSpecificSubShapesCache.clear();\n childIndex = null;\n}\n\n/** Drop the adapter for a shape whose metadata was replaced. */\nfunction invalidateShapeAdapter(id: string) {\n shapeAdapters.delete(id);\n}\n\n/**\n * Register a shape known only as data — no TypeScript class is created.\n *\n * This is the return leg of the round trip: `@linkedShape` is class → metadata,\n * `syncShapes` is metadata → RDF, and this is RDF → metadata. Idempotent: re-registering\n * the same IRI replaces the metadata (a shape edited in the builder), which is why cache\n * invalidation cannot be keyed on registry size.\n */\nexport function registerNodeShape(nodeShape: NodeShapeData): void {\n if (!nodeShape?.id) return;\n nodeShapeRegistry.set(nodeShape.id, nodeShape);\n invalidateShapeAdapter(nodeShape.id);\n invalidateRegistryCaches();\n}\n\n/** The metadata for a node-shape IRI, whether or not it has a TypeScript class. */\nexport function getNodeShape(\n nodeShape: NodeReferenceValue | {id: string} | string,\n): NodeShapeData | undefined {\n const id = typeof nodeShape === 'string' ? nodeShape : nodeShape?.id;\n if (!id) return undefined;\n return nodeShapeRegistry.get(id);\n}\n\n/** Every registered shape's metadata, keyed by node-shape IRI. */\nexport function getAllNodeShapes(): ReadonlyMap<string, NodeShapeData> {\n return nodeShapeRegistry;\n}\n\n/**\n * Lazily-built constructors for shapes that exist only as data.\n *\n * The builder entry points (`QueryBuilder`, `CreateBuilder`, `UpdateBuilder`,\n * `DeleteBuilder` via `resolveShape`) take a `ShapeConstructor` and instantiate result\n * proxies from it, so they need *a* class. Rather than have every caller hand-roll one —\n * which is what `create-now-js`'s `registerRuntimeShape` used to do, losing `extends` and\n * every value constraint on the way — core derives one on demand from the registered\n * metadata and caches it.\n *\n * These adapters are deliberately NOT in `nodeShapeToShapeClass`: `getShapeClass` keeps\n * telling the truth about which shapes have a real, authored class. An adapter carries\n * the metadata verbatim, so nothing is lost, and inheritance is read from\n * `nodeShape.extends` (not from the adapter's prototype, which is always `Shape`).\n */\nconst shapeAdapters = registryState.shapeAdapters;\n\n/**\n * A constructor for a shape known only as data, created on first use.\n *\n * Returns undefined when the IRI is not registered at all. Prefer `getShapeClass` when\n * you specifically need an authored class; use this when you need *something*\n * constructor-shaped to drive the query builders.\n */\nexport function getOrCreateShapeAdapter(\n nodeShape: NodeShapeData | string,\n): typeof Shape | undefined {\n const data =\n typeof nodeShape === 'string' ? nodeShapeRegistry.get(nodeShape) : nodeShape;\n if (!data?.id) return undefined;\n\n const authored = nodeShapeToShapeClass.get(data.id);\n if (authored) return authored;\n\n const cached = shapeAdapters.get(data.id);\n // Re-registering a shape replaces its metadata, so an adapter built from the old\n // object must not be reused.\n if (cached && cached.shape === data) return cached;\n\n class RuntimeShape extends ShapeModule.Shape {\n static shape = data as NodeShapeData;\n static targetClass = (data as NodeShapeData).targetClass ?? null;\n }\n Object.defineProperty(RuntimeShape, 'name', {\n value: (data as NodeShapeData).label || 'RuntimeShape',\n });\n shapeAdapters.set(data.id, RuntimeShape);\n return RuntimeShape;\n}\n\n/** Anything that can identify a shape: its metadata, its class, or its IRI. */\nexport type ShapeLike = NodeShapeData | typeof Shape | Function | string;\n\n/** Resolve a ShapeLike to node-shape metadata, or undefined if it isn't a shape. */\nfunction toNodeShapeData(shape: ShapeLike): NodeShapeData | undefined {\n if (!shape) return undefined;\n if (typeof shape === 'string') return nodeShapeRegistry.get(shape);\n const asData = shape as NodeShapeData;\n // NodeShapeData is a plain object with an id; a Shape class is a function.\n if (typeof shape === 'object' && typeof asData.id === 'string') {\n return nodeShapeRegistry.get(asData.id) ?? asData;\n }\n const asClass = shape as typeof Shape;\n const shapeData = asClass?.shape;\n if (shapeData?.id) return nodeShapeRegistry.get(shapeData.id) ?? shapeData;\n return undefined;\n}\n\nconst warnedUnresolvedExtends = new Set<string>();\n\n/**\n * Every shape the given shape extends, most specific first.\n *\n * THE canonical inheritance walk — `getPropertyShapes(shape, true)` delegates to it, so\n * there is exactly one answer to \"what does this shape extend\". Two earlier walks\n * disagreed (one over the prototype chain, one over `extends`) and that divergence, not\n * either strategy, was the bug: `selectAll` listed labels from one and resolved them\n * through the other, so an inherited property became unresolvable and the query proxy\n * threw.\n *\n * Strategy is chosen by what is available:\n *\n * - **A class-backed shape walks its prototype chain.** This is authoritative and\n * includes the framework `Shape` root, whose own property shapes (`label`, `type`) are\n * genuinely inherited. `applyLinkedShape` deliberately does NOT record `extends` for\n * that root — it is not a domain shape and must not appear as an `extends` triple in\n * materialized SHACL — so the data alone cannot see it.\n * - **A shape known only as data walks `extends` through the registry.** This is what\n * makes inheritance work for a project-authored shape with no class, which the\n * prototype chain cannot express.\n *\n * `extends` is a REFERENCE, so a parent that was never registered ends the walk. The\n * prototype chain has no such failure mode, so it warns once per shape rather than\n * throwing — this runs on read paths.\n */\nexport function getSuperShapes(shape: ShapeLike): NodeShapeData[] {\n const start = toNodeShapeData(shape);\n const chain: NodeShapeData[] = [];\n if (!start) return chain;\n\n // Class-backed: the prototype chain is the authority.\n const startClass = nodeShapeToShapeClass.get(start.id);\n if (startClass) {\n let current: typeof Shape | undefined = startClass;\n while (current) {\n const parent = Object.getPrototypeOf(current) as typeof Shape | undefined;\n if (!parent?.shape) break;\n chain.push(parent.shape);\n if ((parent as unknown) === (ShapeModule.Shape as unknown)) break;\n current = parent;\n }\n return chain;\n }\n\n const seen = new Set<string>([start.id]);\n let current: NodeShapeData | undefined = start;\n while (current?.extends?.id) {\n const parentId = current.extends.id;\n if (seen.has(parentId)) break; // cycle guard — malformed data must not hang a read\n seen.add(parentId);\n const parent = nodeShapeRegistry.get(parentId);\n if (!parent) {\n if (!warnedUnresolvedExtends.has(current.id)) {\n warnedUnresolvedExtends.add(current.id);\n console.warn(\n `[linked] Shape '${current.id}' extends '${parentId}', which is not registered. ` +\n `Inherited properties from it are unavailable. Register the parent shape first ` +\n `(import its module, or register its metadata before the child).`,\n );\n }\n break;\n }\n chain.push(parent);\n current = parent;\n }\n return chain;\n}\n\n/** Every shape that extends the given shape, transitively. Most specific last. */\nexport function getSubShapes(shape: ShapeLike): NodeShapeData[] {\n const start = toNodeShapeData(shape);\n if (!start) return [];\n const index = getChildIndex();\n const out: NodeShapeData[] = [];\n const seen = new Set<string>([start.id]);\n const queue = [start.id];\n while (queue.length) {\n const current = queue.shift()!;\n for (const childId of index.get(current) ?? []) {\n if (seen.has(childId)) continue;\n seen.add(childId);\n const child = nodeShapeRegistry.get(childId);\n if (child) {\n out.push(child);\n queue.push(childId);\n }\n }\n }\n return out;\n}\n\n/** True when `a` extends `b` (strictly — a shape is not a sub-shape of itself). */\nexport function isSubShapeOf(a: ShapeLike, b: ShapeLike): boolean {\n const target = toNodeShapeData(b);\n if (!target) return false;\n return getSuperShapes(a).some((superShape) => superShape.id === target.id);\n}\n\nexport function addNodeShapeToShapeClass(\n nodeShape: NodeShapeData,\n shapeClass: typeof Shape,\n) {\n if (!nodeShape?.id) {\n return;\n }\n // Dev guardrail for IDENTITY duplication. Shape URIs embed `constructor.name`\n // (getNodeShapeUri). If a bundler emits >1 copy of a framework package, the copies\n // are renamed `Person`→`Person2`/`3`, so a mangled URI registers alongside the clean\n // one — the exact failure that silently breaks cross-runtime shape lookup (`Person3`\n // on the FE ≠ `Person` on the backend). Warn ONCE per base so a build-config\n // regression (e.g. a dropped `optimizeDeps.exclude`) surfaces loudly instead of\n // no-op'ing a query at forward time.\n //\n // This used to be dev-only, on the reasoning that production is minified and\n // the check would false-fire. It does not: full minification renames a class\n // to something like `za`, so `base === id` and nothing fires. What DOES fire\n // is the case worth catching — a bundler appending a digit to disambiguate\n // `BackendAPIStore` from the ontology term of the same name, which is exactly\n // the collision that breaks shape lookup, and it only happens in a production\n // build. Suppressing the warning there hid it from the one place it occurs.\n {\n const id = nodeShape.id;\n const base = id.replace(/\\d+$/, '');\n const existing = nodeShapeToShapeClass.get(base);\n if (base !== id && existing && !warnedDuplicateBases.has(base)) {\n // A real duplicate is the SAME logical shape (same targetClass) registered under\n // a mangled name; a legit digit-suffixed sibling (e.g. `OAuth2` vs `OAuth`)\n // targets a different class. Warn only when they match (or targetClass is absent).\n const newTarget = (shapeClass as any).targetClass?.id;\n const existingTarget = (existing as any).targetClass?.id;\n if (!newTarget || !existingTarget || newTarget === existingTarget) {\n warnedDuplicateBases.add(base);\n console.warn(\n `[linked] Shape identity duplication: '${id}' registered alongside '${base}'. ` +\n `A bundler emitted >1 copy of this package — cross-runtime shape lookup will ` +\n `break. Check the cli vite-config single-instance levers (optimizeDeps.exclude ` +\n `/ ssr.noExternal).`,\n );\n }\n }\n }\n nodeShapeToShapeClass.set(nodeShape.id, shapeClass);\n // The class-backed shape goes into the primary registry too, so metadata consumers\n // see one map regardless of how a shape was declared. This also bumps the version,\n // which invalidates every derived cache immediately rather than on a next-tick timer.\n registerNodeShape(nodeShape);\n}\n\n/**\n * The constructor for a shape IRI — an authored class if there is one, otherwise one\n * derived from the registered metadata.\n *\n * This is what the query layer wants in every case, and `getShapeClass` alone is not:\n * it answers `undefined` for a shape that exists only as data, which is every shape\n * authored in a project. Five call sites used to spell this fallback out by hand, in\n * four different ways.\n *\n * `getShapeClass` is NOT consulted first. `getOrCreateShapeAdapter` already returns the\n * authored class when one exists, and a class-backed shape is always mirrored into the\n * primary registry, so the adapter path cannot miss a shape `getShapeClass` would find.\n */\nexport function resolveShapeConstructor(\n nodeShape: NodeReferenceValue | {id: string} | string,\n): ShapeConstructor | undefined {\n const id = typeof nodeShape === 'string' ? nodeShape : nodeShape?.id;\n if (!id) return undefined;\n // SAFETY: both paths yield a concrete subclass of Shape with a static .shape —\n // i.e. a ShapeConstructor. Same cast getShapeClass documents.\n return getOrCreateShapeAdapter(id) as unknown as ShapeConstructor | undefined;\n}\n\nexport function getShapeClass(\n nodeShape: NodeReferenceValue | {id: string} | string,\n): ShapeConstructor | undefined {\n const id = typeof nodeShape === 'string' ? nodeShape : nodeShape?.id;\n if (!id) {\n return undefined;\n }\n // SAFETY: The map stores `typeof Shape` (abstract), but registered shapes are always\n // concrete subclasses with a constructor and static .shape — i.e. ShapeConstructor.\n return nodeShapeToShapeClass.get(id) as unknown as ShapeConstructor | undefined;\n}\n\n/**\n * Returns all registered shape classes (keyed by NodeShape URI).\n */\nexport function getAllShapeClasses(): Map<string, typeof Shape> {\n return nodeShapeToShapeClass;\n}\n\n/**\n * Returns all the sub shapes of the given shape\n * That is all the shapes that extend this shape\n * @param shape\n */\n\nexport function getSubShapesClasses(\n shape: typeof Shape | (typeof Shape)[],\n _internalKey?: string,\n): (typeof Shape)[] {\n let key = _internalKey || getKey(shape);\n if (subShapesCacheVersion !== registryState.registryVersion) {\n subShapesCache.clear();\n mostSpecificSubShapesCache.clear();\n subShapesCacheVersion = registryState.registryVersion;\n }\n if (!subShapesCache.has(key)) {\n //apply the hasSuperclass function to the shape\n let filterFunction = applyFnToShapeOrArray(shape, hasSubClass);\n //filter and then sort the results based on their inheritance (most specific classes first, so we use hasSuperClass for the sorting)\n subShapesCache.set(\n key,\n filterShapeClasses(filterFunction).sort((a, b) => {\n return hasSubClass(a, b) ? 1 : -1;\n }),\n );\n }\n //return a copy of the array to prevent it from being modified\n return [...subShapesCache.get(key)];\n}\n\n/**\n * Returns all the superclasses of the given shape\n * That is all the shapes that it extends.\n * Results are sorted from most specific to least specific\n * @param shape\n */\nexport function getSuperShapesClasses(\n shape: typeof Shape | (typeof Shape)[],\n): (typeof Shape)[] {\n //apply the hasSuperclass function to the shape\n let filterFunction = applyFnToShapeOrArray(shape, hasSuperClass);\n //filter and then sort the results based on their inheritance\n return filterShapeClasses(filterFunction).sort((a, b) => {\n return hasSubClass(a, b) ? 1 : -1;\n });\n}\n\nexport function getPropertyShapeByLabel(\n shapeClass: typeof Shape,\n label: string,\n): PropertyShapeData | undefined {\n if (!shapeClass.shape) return undefined;\n return getPropertyShape(shapeClass.shape, label, true);\n}\n\n/**\n * True when `a` extends `b`.\n *\n * Inheritance is read from `nodeShape.extends` (data), not from the JS prototype chain.\n * `applyLinkedShape` derives `extends` FROM the prototype chain, so for a class-backed\n * shape the two agree — but only the data form also works for a shape that has no\n * class, which is the whole point. The prototype comparison is kept as a fallback for\n * classes that are not registered as shapes at all (an abstract intermediate class).\n */\nexport function hasSuperClass(a: ShapeLike, b: ShapeLike) {\n if (!a || !b) return false;\n const aData = toNodeShapeData(a);\n const bData = toNodeShapeData(b);\n if (aData && bData) return isSubShapeOf(aData, bData);\n return typeof a === 'function' && typeof b === 'function'\n ? (a as Function).prototype instanceof (b as Function)\n : false;\n}\n\n/** True when `b` extends `a` — the mirror of {@link hasSuperClass}. */\nexport function hasSubClass(a: ShapeLike, b: ShapeLike) {\n return hasSuperClass(b, a);\n}\n\nfunction applyFnToShapeOrArray(shape, filterFn) {\n if (Array.isArray(shape)) {\n return (shapeClass) => {\n //returns true if one of the given shapes extends the shapeClass passed as argument\n return (shape as Function[]).some((s) => filterFn(s, shapeClass));\n };\n } else {\n //first argument will be the given shape class, second argument will be each stored shape class in the map\n //will filter down where the given shape extends the stored shape\n return filterFn.bind(null, shape);\n }\n}\n\nfunction filterShapeClasses(filterFn) {\n let result = [];\n nodeShapeToShapeClass.forEach((shapeClass) => {\n if (filterFn(shapeClass)) {\n result.push(shapeClass);\n }\n });\n return result;\n}\n\nexport function getLeastSpecificShapeClasses(shapes: ICoreIterable<Shape>) {\n let shapeClasses = shapes.map((shape) =>\n getShapeClass(shape.nodeShape.id),\n );\n return filterShapesToLeastSpecific(shapeClasses);\n}\n\nexport function getMostSpecificSubShapes(\n shape: typeof Shape | (typeof Shape)[],\n): (typeof Shape)[] {\n if (!Array.isArray(shape)) {\n shape = [shape];\n }\n //get the subshapes of the given shapes\n let key = shape.map((s) => s.name).join(',');\n if (subShapesCacheVersion !== registryState.registryVersion) {\n subShapesCache.clear();\n mostSpecificSubShapesCache.clear();\n subShapesCacheVersion = registryState.registryVersion;\n }\n if (!mostSpecificSubShapesCache.has(key)) {\n //get the subshapes of the given shapes\n let subShapes: (typeof Shape)[] = getSubShapesClasses(shape, key);\n //filter them down to the most specific ones (that are not extended by any other shape)\n mostSpecificSubShapesCache.set(key, filterShapesToMostSpecific(subShapes));\n }\n return mostSpecificSubShapesCache.get(key);\n}\n\n/**\n * Filters out all shapes that are extended by any other shape in the given set/array\n * @param subShapes\n */\nfunction filterShapesToMostSpecific(subShapes) {\n return subShapes.filter((subShape) => {\n return !subShapes.some((otherSubShape) => {\n return otherSubShape.prototype instanceof subShape;\n });\n });\n}\n\n/**\n * Filters out all shapes that extend any other shape in the given set/array\n * @param shapeClasses\n */\nfunction filterShapesToLeastSpecific(shapeClasses) {\n return shapeClasses.filter((shapeClass) => {\n return !shapeClasses.some((otherShapeClass) => {\n return (\n otherShapeClass !== shapeClass &&\n shapeClass.prototype instanceof otherShapeClass\n );\n });\n });\n}\n\nfunction getKey(shape: typeof Shape | (typeof Shape)[]) {\n return Array.isArray(shape)\n ? shape.map((s) => getShapeKey(s)).join(',')\n : getShapeKey(shape);\n}\n\nfunction getShapeKey(shape: typeof Shape) {\n //return a unique string for each shape\n return (\n resolveTargetClassId(shape.targetClass) ||\n shape.name + shape.prototype.constructor.toString().substring(0, 80)\n );\n}\n"]}
|
|
1
|
+
{"version":3,"file":"ShapeClass.js","sourceRoot":"","sources":["../../../src/utils/ShapeClass.ts"],"names":[],"mappings":"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","sourcesContent":["import {type Shape, type ShapeConstructor} from '../shapes/Shape.js';\n// Namespace import, read at CALL time rather than captured at module-evaluation time.\n// `getOrCreateShapeAdapter` subclasses `Shape` at runtime, and under some import orders this\n// module finishes evaluating before `Shape.js` does — a named import captured then is\n// permanently `undefined`, and the subclass fails with \"Class extends value undefined\".\nimport * as ShapeModule from '../shapes/Shape.js';\nimport {\n getPropertyShape,\n type NodeShapeData,\n type PropertyShapeData,\n} from '../shapes/nodeShapeData.js';\nimport type {NodeShapeWire} from '../shapes/nodeShapeWire.js';\nimport type {ICoreIterable} from '../interfaces/ICoreIterable.js';\nimport type {NodeReferenceValue} from './NodeReference.js';\n\nconst resolveTargetClassId = (\n targetClass?: NodeReferenceValue | null,\n): string | null => {\n if (!targetClass) return null;\n return targetClass.id ?? null;\n};\n\n/**\n * The shape registries live on `globalThis`, not in module scope.\n *\n * A module can evaluate more than once in one process, and in a built app it does: an\n * app's backend is assembled from two graphs, one loaded by the bundler from `src/` and\n * one resolved by Node to `lib/esm/`. A module-scope `Map` then exists twice — shapes\n * register into one copy and every lookup reads the other, which finds nothing.\n *\n * The symptom never mentions module identity. It is `Invalid property key: projectSlug.\n * The shape Project does not have a registered property with this name` for a property\n * that is declared correctly two files away, because validation ran on the copy the\n * decorators never reached. See docs/reports/043-module-identity-in-the-backend.md.\n *\n * Sharing the state makes duplication harmless rather than merely absent: the graphs\n * still hold two copies of this module, but only one registry. `LinkedStorage` already\n * keeps its instance counter here; this keeps the data itself.\n */\nconst shapeRegistryGlobal: any =\n typeof globalThis !== 'undefined' ? globalThis : ({} as any);\n\n/**\n * Counts DISTINCT physical copies of this module, not evaluations of it.\n *\n * The difference matters. A bare `count++` here is incremented by Vite's HMR every time\n * the module is re-evaluated in the same process, against the same `globalThis` — so a\n * developer who edits a file a few times sees a count of 4 and goes hunting a\n * dual-resolution problem that does not exist. Recording a token per copy and counting\n * the tokens survives re-evaluation: HMR replaces the module, and its token with it.\n */\nconst copyToken: object = {};\nconst copies: Set<object> = (shapeRegistryGlobal.__linkedShapeRegistryCopies ??= new Set());\ncopies.add(copyToken);\n\n/**\n * More than one copy of this module means shapes register into one registry and are\n * looked up in another, and the resulting failures never mention module identity — they\n * say a declared property is not declared, or that a pinned shape has no pin.\n *\n * Reported rather than thrown. A throw from a library module at import time breaks\n * tooling that legitimately loads a module twice, and the shared state above means a\n * second copy is survivable: it is a correctness hazard for anything holding a class\n * reference, not an immediate failure. So this says so, once, as loudly as a log can.\n */\nif (copies.size > 1) {\n console.error(\n `[linked] ${copies.size} copies of @_linked/core's shape registry have loaded in ` +\n `this process. They share one registry, so lookups still resolve — but each copy ` +\n `has its own \\`Shape\\` base class, so \\`instanceof\\` comparisons across them are ` +\n `false and adapters built by one copy do not satisfy the other. This is a module ` +\n `resolution problem: part of the app is reaching this package by a path that ` +\n `resolves to its source and part by one that resolves to its build output.`,\n );\n}\n\n/**\n * One shared container, created by whichever copy evaluates first.\n *\n * `registryVersion` belongs here too: every derived cache in this module is keyed on it,\n * so a version that is not shared would let one copy's writes leave another copy's caches\n * looking valid. The caches themselves stay per-copy — they are rebuilt whenever the\n * shared version moves past them.\n */\nconst registryState: {\n nodeShapeToShapeClass: Map<string, typeof Shape>;\n nodeShapeRegistry: Map<string, NodeShapeData>;\n shapeAdapters: Map<string, typeof Shape>;\n registryVersion: number;\n} = (shapeRegistryGlobal.__linkedShapeRegistry ??= {\n nodeShapeToShapeClass: new Map(),\n nodeShapeRegistry: new Map(),\n shapeAdapters: new Map(),\n registryVersion: 0,\n});\n\n/** How many distinct copies of this module are loaded. One is expected. */\nexport function getShapeRegistryInstanceCount(): number {\n return copies.size;\n}\n\nlet subShapesCache: Map<string, (typeof Shape)[]> = new Map();\nlet mostSpecificSubShapesCache: Map<string, (typeof Shape)[]> = new Map();\nconst nodeShapeToShapeClass = registryState.nodeShapeToShapeClass;\nconst warnedDuplicateBases = new Set<string>();\n\n/**\n * The PRIMARY shape registry: node-shape IRI → its metadata.\n *\n * Every shape is here — those declared by a `@linkedShape` class and those known only\n * as data (a project-authored shape read from the graph). `nodeShapeToShapeClass` above\n * is the SECONDARY registry, holding only the shapes that have a TypeScript class, and\n * exists for the few callers that genuinely need a class (a `ShapeProvider` lookup, a\n * typed accessor). Query lowering, predicate resolution and containment all read\n * metadata, so they use this map and work identically for both kinds of shape.\n */\nconst nodeShapeRegistry = registryState.nodeShapeRegistry;\n\n/** Version the sub-shape caches above were filled at. */\nlet subShapesCacheVersion = -1;\n\n/**\n * The current registration version — a monotonic counter, bumped on every write.\n *\n * Every derived cache in this module, and in `irToAlgebra`, is keyed on it. It replaces\n * two earlier invalidation strategies that were both unsound: a `setTimeout(…, 0)` cache\n * clear (which missed anything registered later in the same session) and comparing the\n * registry SIZE (which silently reuses a stale cache when a registration and a removal\n * coincide, or when a shape is re-registered in place).\n *\n * It lives on the shared state, not in module scope: a cache keyed on a per-copy version\n * would look valid after another copy had written.\n */\nexport function getRegistryVersion(): number {\n return registryState.registryVersion;\n}\n\n/** Reverse index parentIri → direct child IRIs, rebuilt when the registry changes. */\nlet childIndex: Map<string, string[]> | null = null;\nlet childIndexVersion = -1;\n\nfunction getChildIndex(): Map<string, string[]> {\n if (childIndex && childIndexVersion === registryState.registryVersion) return childIndex;\n const index = new Map<string, string[]>();\n nodeShapeRegistry.forEach((shape, id) => {\n const parent = shape.extends?.id;\n if (!parent) return;\n const siblings = index.get(parent);\n if (siblings) siblings.push(id);\n else index.set(parent, [id]);\n });\n childIndex = index;\n childIndexVersion = registryState.registryVersion;\n return index;\n}\n\nfunction invalidateRegistryCaches() {\n registryState.registryVersion++;\n subShapesCache.clear();\n mostSpecificSubShapesCache.clear();\n childIndex = null;\n targetClassIndex = null;\n}\n\n/** Drop the adapter for a shape whose metadata was replaced. */\nfunction invalidateShapeAdapter(id: string) {\n shapeAdapters.delete(id);\n}\n\n/**\n * Register a shape known only as data — no TypeScript class is created.\n *\n * This is the return leg of the round trip: `@linkedShape` is class → metadata,\n * `syncShapes` is metadata → RDF, and this is RDF → metadata. Idempotent: re-registering\n * the same IRI replaces the metadata (a shape edited in the builder), which is why cache\n * invalidation cannot be keyed on registry size.\n */\nexport function registerNodeShape(nodeShape: NodeShapeData): void {\n if (!nodeShape?.id) return;\n nodeShapeRegistry.set(nodeShape.id, nodeShape);\n invalidateShapeAdapter(nodeShape.id);\n invalidateRegistryCaches();\n}\n\n/** The metadata for a node-shape IRI, whether or not it has a TypeScript class. */\nexport function getNodeShape(\n nodeShape: NodeReferenceValue | {id: string} | string,\n): NodeShapeData | undefined {\n const id = typeof nodeShape === 'string' ? nodeShape : nodeShape?.id;\n if (!id) return undefined;\n return nodeShapeRegistry.get(id);\n}\n\n/** Every registered shape's metadata, keyed by node-shape IRI. */\nexport function getAllNodeShapes(): ReadonlyMap<string, NodeShapeData> {\n return nodeShapeRegistry;\n}\n\n/**\n * Lazily-built constructors for shapes that exist only as data.\n *\n * The builder entry points (`QueryBuilder`, `CreateBuilder`, `UpdateBuilder`,\n * `DeleteBuilder` via `resolveShape`) take a `ShapeConstructor` and instantiate result\n * proxies from it, so they need *a* class. Rather than have every caller hand-roll one —\n * which is what `create-now-js`'s `registerRuntimeShape` used to do, losing `extends` and\n * every value constraint on the way — core derives one on demand from the registered\n * metadata and caches it.\n *\n * These adapters are deliberately NOT in `nodeShapeToShapeClass`: `getShapeClass` keeps\n * telling the truth about which shapes have a real, authored class. An adapter carries\n * the metadata verbatim, so nothing is lost, and inheritance is read from\n * `nodeShape.extends` (not from the adapter's prototype, which is always `Shape`).\n */\nconst shapeAdapters = registryState.shapeAdapters;\n\n/**\n * A constructor for a shape known only as data, created on first use.\n *\n * Returns undefined when the IRI is not registered at all. Prefer `getShapeClass` when\n * you specifically need an authored class; use this when you need *something*\n * constructor-shaped to drive the query builders.\n */\nexport function getOrCreateShapeAdapter(\n nodeShape: NodeShapeData | string,\n): typeof Shape | undefined {\n const data =\n typeof nodeShape === 'string' ? nodeShapeRegistry.get(nodeShape) : nodeShape;\n if (!data?.id) return undefined;\n\n const authored = nodeShapeToShapeClass.get(data.id);\n if (authored) return authored;\n\n const cached = shapeAdapters.get(data.id);\n // Re-registering a shape replaces its metadata, so an adapter built from the old\n // object must not be reused.\n if (cached && cached.shape === data) return cached;\n\n class RuntimeShape extends ShapeModule.Shape {\n static shape = data as NodeShapeData;\n static targetClass = (data as NodeShapeData).targetClass ?? null;\n }\n Object.defineProperty(RuntimeShape, 'name', {\n value: (data as NodeShapeData).label || 'RuntimeShape',\n });\n shapeAdapters.set(data.id, RuntimeShape);\n return RuntimeShape;\n}\n\n/** Anything that can identify a shape: its metadata, its class, or its IRI. */\nexport type ShapeLike = NodeShapeData | typeof Shape | Function | string;\n\n/** Resolve a ShapeLike to node-shape metadata, or undefined if it isn't a shape. */\nfunction toNodeShapeData(shape: ShapeLike): NodeShapeData | undefined {\n if (!shape) return undefined;\n if (typeof shape === 'string') return nodeShapeRegistry.get(shape);\n const asData = shape as NodeShapeData;\n // NodeShapeData is a plain object with an id; a Shape class is a function.\n if (typeof shape === 'object' && typeof asData.id === 'string') {\n return nodeShapeRegistry.get(asData.id) ?? asData;\n }\n const asClass = shape as typeof Shape;\n const shapeData = asClass?.shape;\n if (shapeData?.id) return nodeShapeRegistry.get(shapeData.id) ?? shapeData;\n return undefined;\n}\n\nconst warnedUnresolvedExtends = new Set<string>();\n\n/**\n * Every shape the given shape extends, most specific first.\n *\n * THE canonical inheritance walk — `getPropertyShapes(shape, true)` delegates to it, so\n * there is exactly one answer to \"what does this shape extend\". Two earlier walks\n * disagreed (one over the prototype chain, one over `extends`) and that divergence, not\n * either strategy, was the bug: `selectAll` listed labels from one and resolved them\n * through the other, so an inherited property became unresolvable and the query proxy\n * threw.\n *\n * Strategy is chosen by what is available:\n *\n * - **A class-backed shape walks its prototype chain.** This is authoritative and\n * includes the framework `Shape` root, whose own property shapes (`label`, `type`) are\n * genuinely inherited. `applyLinkedShape` deliberately does NOT record `extends` for\n * that root — it is not a domain shape and must not appear as an `extends` triple in\n * materialized SHACL — so the data alone cannot see it.\n * - **A shape known only as data walks `extends` through the registry.** This is what\n * makes inheritance work for a project-authored shape with no class, which the\n * prototype chain cannot express.\n *\n * `extends` is a REFERENCE, so a parent that was never registered ends the walk. The\n * prototype chain has no such failure mode, so it warns once per shape rather than\n * throwing — this runs on read paths.\n */\nexport function getSuperShapes(shape: ShapeLike): NodeShapeData[] {\n const start = toNodeShapeData(shape);\n const chain: NodeShapeData[] = [];\n if (!start) return chain;\n\n // Class-backed: the prototype chain is the authority.\n const startClass = nodeShapeToShapeClass.get(start.id);\n if (startClass) {\n let current: typeof Shape | undefined = startClass;\n while (current) {\n const parent = Object.getPrototypeOf(current) as typeof Shape | undefined;\n if (!parent?.shape) break;\n chain.push(parent.shape);\n if ((parent as unknown) === (ShapeModule.Shape as unknown)) break;\n current = parent;\n }\n return chain;\n }\n\n const seen = new Set<string>([start.id]);\n let current: NodeShapeData | undefined = start;\n while (current?.extends?.id) {\n const parentId = current.extends.id;\n if (seen.has(parentId)) break; // cycle guard — malformed data must not hang a read\n seen.add(parentId);\n const parent = nodeShapeRegistry.get(parentId);\n if (!parent) {\n if (!warnedUnresolvedExtends.has(current.id)) {\n warnedUnresolvedExtends.add(current.id);\n console.warn(\n `[linked] Shape '${current.id}' extends '${parentId}', which is not registered. ` +\n `Inherited properties from it are unavailable. Register the parent shape first ` +\n `(import its module, or register its metadata before the child).`,\n );\n }\n break;\n }\n chain.push(parent);\n current = parent;\n }\n return chain;\n}\n\n/** Every shape that extends the given shape, transitively. Most specific last. */\nexport function getSubShapes(shape: ShapeLike): NodeShapeData[] {\n const start = toNodeShapeData(shape);\n if (!start) return [];\n const index = getChildIndex();\n const out: NodeShapeData[] = [];\n const seen = new Set<string>([start.id]);\n const queue = [start.id];\n while (queue.length) {\n const current = queue.shift()!;\n for (const childId of index.get(current) ?? []) {\n if (seen.has(childId)) continue;\n seen.add(childId);\n const child = nodeShapeRegistry.get(childId);\n if (child) {\n out.push(child);\n queue.push(childId);\n }\n }\n }\n return out;\n}\n\n/** True when `a` extends `b` (strictly — a shape is not a sub-shape of itself). */\nexport function isSubShapeOf(a: ShapeLike, b: ShapeLike): boolean {\n const target = toNodeShapeData(b);\n if (!target) return false;\n return getSuperShapes(a).some((superShape) => superShape.id === target.id);\n}\n\n/**\n * The fields of a shape the targetClass lookups read. Both `NodeShapeData` and its wire\n * form satisfy it, so a caller holding a shape catalog never has to convert it first.\n */\ntype ShapeHeader = Pick<NodeShapeData, 'id' | 'targetClass' | 'extends'>;\n\n/**\n * Every shape `shape` extends, most specific first — resolving each parent in `local`\n * before the registry.\n *\n * `local` is a caller's own set of shapes (a project's catalog), which may hold shapes the\n * registry has never seen, or newer versions of ones it has. The catalog is the authority\n * for what it holds; once the chain leaves it, the registry knows the rest.\n */\nfunction superShapesWithin(\n shape: ShapeHeader,\n local?: ReadonlyMap<string, ShapeHeader>,\n): ShapeHeader[] {\n if (!local) return getSuperShapes(shape as NodeShapeData);\n const chain: ShapeHeader[] = [];\n const seen = new Set<string>([shape.id]);\n let current: ShapeHeader = shape;\n while (current.extends?.id) {\n const parentId = current.extends.id;\n if (seen.has(parentId)) break; // cycle guard — malformed data must not hang a read\n seen.add(parentId);\n const parent = local.get(parentId);\n if (!parent) {\n const registered = nodeShapeRegistry.get(parentId);\n if (registered) chain.push(registered, ...getSuperShapes(registered));\n break;\n }\n chain.push(parent);\n current = parent;\n }\n return chain;\n}\n\nfunction indexShapes<S extends ShapeHeader>(shapes: Iterable<S>): Map<string, S> {\n const index = new Map<string, S>();\n for (const shape of shapes) if (shape?.id) index.set(shape.id, shape);\n return index;\n}\n\nfunction targetClassIdWithin(\n shape: ShapeLike | NodeShapeWire | {id: string},\n local?: ReadonlyMap<string, ShapeHeader>,\n): string | undefined {\n if (!shape) return undefined;\n if (typeof shape === 'function') {\n // A class's static targetClass is inherited through the prototype chain for free.\n const asClass = shape as typeof Shape;\n if (asClass.targetClass?.id) return asClass.targetClass.id;\n if (!asClass.shape?.id) return undefined;\n shape = asClass.shape;\n }\n const id = typeof shape === 'string' ? shape : shape.id;\n if (!id) return undefined;\n const given = typeof shape === 'string' ? undefined : (shape as ShapeHeader);\n const own =\n given?.targetClass?.id ??\n local?.get(id)?.targetClass?.id ??\n getShapeClass(id)?.targetClass?.id ??\n nodeShapeRegistry.get(id)?.targetClass?.id;\n if (own) return own;\n // A data-only shape's targetClass is not inherited for free, so walk `extends`.\n const start = local?.get(id) ?? (given?.extends ? given : nodeShapeRegistry.get(id) ?? given);\n if (!start) return undefined;\n return superShapesWithin(start, local).find((s) => s.targetClass?.id)?.targetClass?.id;\n}\n\n/**\n * The class a shape's instances are typed with: its own `targetClass`, else the first one\n * found through what it extends. `undefined` when there is none anywhere in the chain.\n *\n * Accepts a shape IRI, a `{id}` reference, a shape's metadata (data or wire form) or a shape\n * class. Pass `shapes` to resolve the shape — and what it extends — in that set before the\n * registry; a project's catalog may hold shapes the registry does not.\n */\nexport function getTargetClassId(\n shape: ShapeLike | NodeShapeWire | {id: string},\n shapes?: Iterable<NodeShapeData | NodeShapeWire>,\n): string | undefined {\n return targetClassIdWithin(shape, shapes ? indexShapes(shapes) : undefined);\n}\n\n/**\n * The least specific candidates (the roots), by id. A candidate that extends another\n * candidate (directly or further up) is dropped: a relation to `Person` with `Person` and\n * `Employee extends Person` both targeting it means `Person` — a relation never upgrades\n * itself to a sub-shape; declare `sh:node` to ask for one. What remains are unrelated roots\n * the data does not choose between; they sort by id alone — never by depth or by\n * registration or catalog order — so the choice is stable and visibly arbitrary. If that\n * would drop every candidate (an `extends` cycle), all of them are kept, by id.\n */\nfunction leastSpecific<S extends ShapeHeader>(\n candidates: S[],\n local?: ReadonlyMap<string, ShapeHeader>,\n): S[] {\n const ids = new Set(candidates.map((c) => c.id));\n const byId = (a: S, b: S) => (a.id < b.id ? -1 : a.id > b.id ? 1 : 0);\n const roots = candidates.filter(\n (candidate) => !superShapesWithin(candidate, local).some((parent) => ids.has(parent.id)),\n );\n // An `extends` cycle makes each member extend another, so the filter can leave nothing.\n // Malformed data must not turn a relation into \"no shape\" silently: keep every candidate\n // instead, by id, and let the caller's ambiguity handling (warn) apply.\n return (roots.length ? roots : [...candidates]).sort(byId);\n}\n\n/** targetClass IRI → registered shapes targeting it, ordered. Rebuilt when the registry changes. */\nlet targetClassIndex: Map<string, NodeShapeData[]> | null = null;\nlet targetClassIndexVersion = -1;\n\nfunction getTargetClassIndex(): Map<string, NodeShapeData[]> {\n if (targetClassIndex && targetClassIndexVersion === registryState.registryVersion) {\n return targetClassIndex;\n }\n const index = new Map<string, NodeShapeData[]>();\n nodeShapeRegistry.forEach((shape) => {\n const classId = targetClassIdWithin(shape);\n if (!classId) return;\n const shapes = index.get(classId);\n if (shapes) shapes.push(shape);\n else index.set(classId, [shape]);\n });\n index.forEach((shapes, classId) => index.set(classId, leastSpecific(shapes)));\n targetClassIndex = index;\n targetClassIndexVersion = registryState.registryVersion;\n return index;\n}\n\n/**\n * The least specific shapes whose effective targetClass (own, or inherited through\n * `extends`) is exactly `classIri`, sorted by id. A matching shape that extends another\n * match is left out, so one entry means the class has one root shape and more than one\n * means unrelated roots compete for it. Sub-shapes are never chosen for a class alone.\n *\n * With no `shapes`, the candidates are the registered shapes. Pass `shapes` to choose among\n * that set only — the registry also holds compiled framework shapes, and a project's\n * `schema:Person` relation should resolve to the project's shape, not to one a framework\n * package happens to register for the same class. Inheritance is still resolved through\n * the registry when a candidate extends a shape outside the set.\n */\nexport function getShapesForTargetClass(classIri: string): NodeShapeData[];\nexport function getShapesForTargetClass<S extends NodeShapeData | NodeShapeWire>(\n classIri: string,\n shapes: Iterable<S>,\n): S[];\nexport function getShapesForTargetClass(\n classIri: string,\n shapes?: Iterable<NodeShapeData | NodeShapeWire>,\n): (NodeShapeData | NodeShapeWire)[] {\n if (!classIri) return [];\n if (!shapes) return [...(getTargetClassIndex().get(classIri) ?? [])];\n const local = indexShapes(shapes);\n const candidates = [...local.values()].filter(\n (shape) => targetClassIdWithin(shape, local) === classIri,\n );\n return leastSpecific(candidates, local);\n}\n\nexport function addNodeShapeToShapeClass(\n nodeShape: NodeShapeData,\n shapeClass: typeof Shape,\n) {\n if (!nodeShape?.id) {\n return;\n }\n // Dev guardrail for IDENTITY duplication. Shape URIs embed `constructor.name`\n // (getNodeShapeUri). If a bundler emits >1 copy of a framework package, the copies\n // are renamed `Person`→`Person2`/`3`, so a mangled URI registers alongside the clean\n // one — the exact failure that silently breaks cross-runtime shape lookup (`Person3`\n // on the FE ≠ `Person` on the backend). Warn ONCE per base so a build-config\n // regression (e.g. a dropped `optimizeDeps.exclude`) surfaces loudly instead of\n // no-op'ing a query at forward time.\n //\n // This used to be dev-only, on the reasoning that production is minified and\n // the check would false-fire. It does not: full minification renames a class\n // to something like `za`, so `base === id` and nothing fires. What DOES fire\n // is the case worth catching — a bundler appending a digit to disambiguate\n // `BackendAPIStore` from the ontology term of the same name, which is exactly\n // the collision that breaks shape lookup, and it only happens in a production\n // build. Suppressing the warning there hid it from the one place it occurs.\n {\n const id = nodeShape.id;\n const base = id.replace(/\\d+$/, '');\n const existing = nodeShapeToShapeClass.get(base);\n if (base !== id && existing && !warnedDuplicateBases.has(base)) {\n // A real duplicate is the SAME logical shape (same targetClass) registered under\n // a mangled name; a legit digit-suffixed sibling (e.g. `OAuth2` vs `OAuth`)\n // targets a different class. Warn only when they match (or targetClass is absent).\n const newTarget = (shapeClass as any).targetClass?.id;\n const existingTarget = (existing as any).targetClass?.id;\n if (!newTarget || !existingTarget || newTarget === existingTarget) {\n warnedDuplicateBases.add(base);\n console.warn(\n `[linked] Shape identity duplication: '${id}' registered alongside '${base}'. ` +\n `A bundler emitted >1 copy of this package — cross-runtime shape lookup will ` +\n `break. Check the cli vite-config single-instance levers (optimizeDeps.exclude ` +\n `/ ssr.noExternal).`,\n );\n }\n }\n }\n nodeShapeToShapeClass.set(nodeShape.id, shapeClass);\n // The class-backed shape goes into the primary registry too, so metadata consumers\n // see one map regardless of how a shape was declared. This also bumps the version,\n // which invalidates every derived cache immediately rather than on a next-tick timer.\n registerNodeShape(nodeShape);\n}\n\n/**\n * The constructor for a shape IRI — an authored class if there is one, otherwise one\n * derived from the registered metadata.\n *\n * This is what the query layer wants in every case, and `getShapeClass` alone is not:\n * it answers `undefined` for a shape that exists only as data, which is every shape\n * authored in a project. Five call sites used to spell this fallback out by hand, in\n * four different ways.\n *\n * `getShapeClass` is NOT consulted first. `getOrCreateShapeAdapter` already returns the\n * authored class when one exists, and a class-backed shape is always mirrored into the\n * primary registry, so the adapter path cannot miss a shape `getShapeClass` would find.\n */\nexport function resolveShapeConstructor(\n nodeShape: NodeReferenceValue | {id: string} | string,\n): ShapeConstructor | undefined {\n const id = typeof nodeShape === 'string' ? nodeShape : nodeShape?.id;\n if (!id) return undefined;\n // SAFETY: both paths yield a concrete subclass of Shape with a static .shape —\n // i.e. a ShapeConstructor. Same cast getShapeClass documents.\n return getOrCreateShapeAdapter(id) as unknown as ShapeConstructor | undefined;\n}\n\nexport function getShapeClass(\n nodeShape: NodeReferenceValue | {id: string} | string,\n): ShapeConstructor | undefined {\n const id = typeof nodeShape === 'string' ? nodeShape : nodeShape?.id;\n if (!id) {\n return undefined;\n }\n // SAFETY: The map stores `typeof Shape` (abstract), but registered shapes are always\n // concrete subclasses with a constructor and static .shape — i.e. ShapeConstructor.\n return nodeShapeToShapeClass.get(id) as unknown as ShapeConstructor | undefined;\n}\n\n/**\n * Returns all registered shape classes (keyed by NodeShape URI).\n */\nexport function getAllShapeClasses(): Map<string, typeof Shape> {\n return nodeShapeToShapeClass;\n}\n\n/**\n * Returns all the sub shapes of the given shape\n * That is all the shapes that extend this shape\n * @param shape\n */\n\nexport function getSubShapesClasses(\n shape: typeof Shape | (typeof Shape)[],\n _internalKey?: string,\n): (typeof Shape)[] {\n let key = _internalKey || getKey(shape);\n if (subShapesCacheVersion !== registryState.registryVersion) {\n subShapesCache.clear();\n mostSpecificSubShapesCache.clear();\n subShapesCacheVersion = registryState.registryVersion;\n }\n if (!subShapesCache.has(key)) {\n //apply the hasSuperclass function to the shape\n let filterFunction = applyFnToShapeOrArray(shape, hasSubClass);\n //filter and then sort the results based on their inheritance (most specific classes first, so we use hasSuperClass for the sorting)\n subShapesCache.set(\n key,\n filterShapeClasses(filterFunction).sort((a, b) => {\n return hasSubClass(a, b) ? 1 : -1;\n }),\n );\n }\n //return a copy of the array to prevent it from being modified\n return [...subShapesCache.get(key)];\n}\n\n/**\n * Returns all the superclasses of the given shape\n * That is all the shapes that it extends.\n * Results are sorted from most specific to least specific\n * @param shape\n */\nexport function getSuperShapesClasses(\n shape: typeof Shape | (typeof Shape)[],\n): (typeof Shape)[] {\n //apply the hasSuperclass function to the shape\n let filterFunction = applyFnToShapeOrArray(shape, hasSuperClass);\n //filter and then sort the results based on their inheritance\n return filterShapeClasses(filterFunction).sort((a, b) => {\n return hasSubClass(a, b) ? 1 : -1;\n });\n}\n\nexport function getPropertyShapeByLabel(\n shapeClass: typeof Shape,\n label: string,\n): PropertyShapeData | undefined {\n if (!shapeClass.shape) return undefined;\n return getPropertyShape(shapeClass.shape, label, true);\n}\n\n/**\n * True when `a` extends `b`.\n *\n * Inheritance is read from `nodeShape.extends` (data), not from the JS prototype chain.\n * `applyLinkedShape` derives `extends` FROM the prototype chain, so for a class-backed\n * shape the two agree — but only the data form also works for a shape that has no\n * class, which is the whole point. The prototype comparison is kept as a fallback for\n * classes that are not registered as shapes at all (an abstract intermediate class).\n */\nexport function hasSuperClass(a: ShapeLike, b: ShapeLike) {\n if (!a || !b) return false;\n const aData = toNodeShapeData(a);\n const bData = toNodeShapeData(b);\n if (aData && bData) return isSubShapeOf(aData, bData);\n return typeof a === 'function' && typeof b === 'function'\n ? (a as Function).prototype instanceof (b as Function)\n : false;\n}\n\n/** True when `b` extends `a` — the mirror of {@link hasSuperClass}. */\nexport function hasSubClass(a: ShapeLike, b: ShapeLike) {\n return hasSuperClass(b, a);\n}\n\nfunction applyFnToShapeOrArray(shape, filterFn) {\n if (Array.isArray(shape)) {\n return (shapeClass) => {\n //returns true if one of the given shapes extends the shapeClass passed as argument\n return (shape as Function[]).some((s) => filterFn(s, shapeClass));\n };\n } else {\n //first argument will be the given shape class, second argument will be each stored shape class in the map\n //will filter down where the given shape extends the stored shape\n return filterFn.bind(null, shape);\n }\n}\n\nfunction filterShapeClasses(filterFn) {\n let result = [];\n nodeShapeToShapeClass.forEach((shapeClass) => {\n if (filterFn(shapeClass)) {\n result.push(shapeClass);\n }\n });\n return result;\n}\n\nexport function getLeastSpecificShapeClasses(shapes: ICoreIterable<Shape>) {\n let shapeClasses = shapes.map((shape) =>\n getShapeClass(shape.nodeShape.id),\n );\n return filterShapesToLeastSpecific(shapeClasses);\n}\n\nexport function getMostSpecificSubShapes(\n shape: typeof Shape | (typeof Shape)[],\n): (typeof Shape)[] {\n if (!Array.isArray(shape)) {\n shape = [shape];\n }\n //get the subshapes of the given shapes\n let key = shape.map((s) => s.name).join(',');\n if (subShapesCacheVersion !== registryState.registryVersion) {\n subShapesCache.clear();\n mostSpecificSubShapesCache.clear();\n subShapesCacheVersion = registryState.registryVersion;\n }\n if (!mostSpecificSubShapesCache.has(key)) {\n //get the subshapes of the given shapes\n let subShapes: (typeof Shape)[] = getSubShapesClasses(shape, key);\n //filter them down to the most specific ones (that are not extended by any other shape)\n mostSpecificSubShapesCache.set(key, filterShapesToMostSpecific(subShapes));\n }\n return mostSpecificSubShapesCache.get(key);\n}\n\n/**\n * Filters out all shapes that are extended by any other shape in the given set/array\n * @param subShapes\n */\nfunction filterShapesToMostSpecific(subShapes) {\n return subShapes.filter((subShape) => {\n return !subShapes.some((otherSubShape) => {\n return otherSubShape.prototype instanceof subShape;\n });\n });\n}\n\n/**\n * Filters out all shapes that extend any other shape in the given set/array\n * @param shapeClasses\n */\nfunction filterShapesToLeastSpecific(shapeClasses) {\n return shapeClasses.filter((shapeClass) => {\n return !shapeClasses.some((otherShapeClass) => {\n return (\n otherShapeClass !== shapeClass &&\n shapeClass.prototype instanceof otherShapeClass\n );\n });\n });\n}\n\nfunction getKey(shape: typeof Shape | (typeof Shape)[]) {\n return Array.isArray(shape)\n ? shape.map((s) => getShapeKey(s)).join(',')\n : getShapeKey(shape);\n}\n\nfunction getShapeKey(shape: typeof Shape) {\n //return a unique string for each shape\n return (\n resolveTargetClassId(shape.targetClass) ||\n shape.name + shape.prototype.constructor.toString().substring(0, 80)\n );\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@_linked/core",
|
|
3
|
-
"version": "2.
|
|
4
|
-
"packageManager": "npm@
|
|
3
|
+
"version": "2.27.0",
|
|
4
|
+
"packageManager": "npm@12.1.0",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"linkedPackage": true,
|
|
7
7
|
"type": "module",
|
|
@@ -19,6 +19,10 @@
|
|
|
19
19
|
"**/utils/Package.ts",
|
|
20
20
|
"**/lib/esm/index.js",
|
|
21
21
|
"**/src/index.ts",
|
|
22
|
+
"**/lib/esm/live.js",
|
|
23
|
+
"**/src/live.ts",
|
|
24
|
+
"**/lib/esm/live/LiveQueryStore.js",
|
|
25
|
+
"**/src/live/LiveQueryStore.ts",
|
|
22
26
|
"**/shapes/index.js",
|
|
23
27
|
"**/shapes/index.ts",
|
|
24
28
|
"**/shapes/*.js",
|