@_linked/core 2.34.0 → 2.35.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 +10 -0
- package/README.md +24 -0
- package/lib/esm/index.d.ts +2 -1
- package/lib/esm/index.js +2 -0
- package/lib/esm/index.js.map +1 -1
- package/lib/esm/live/LiveQueryStore.d.ts +22 -0
- package/lib/esm/live/LiveQueryStore.js +86 -19
- package/lib/esm/live/LiveQueryStore.js.map +1 -1
- package/lib/esm/live/changes.d.ts +9 -1
- package/lib/esm/live/changes.js +7 -2
- package/lib/esm/live/changes.js.map +1 -1
- package/lib/esm/live/keys.d.ts +6 -0
- package/lib/esm/live/keys.js +10 -1
- package/lib/esm/live/keys.js.map +1 -1
- package/lib/esm/live/matcher.d.ts +4 -1
- package/lib/esm/live/matcher.js +10 -5
- package/lib/esm/live/matcher.js.map +1 -1
- package/lib/esm/queries/AskBuilder.d.ts +6 -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 +6 -0
- package/lib/esm/queries/CountBuilder.js +14 -0
- package/lib/esm/queries/CountBuilder.js.map +1 -1
- package/lib/esm/queries/CreateBuilder.d.ts +4 -0
- package/lib/esm/queries/CreateBuilder.js +15 -1
- package/lib/esm/queries/CreateBuilder.js.map +1 -1
- package/lib/esm/queries/DeleteBuilder.d.ts +4 -0
- package/lib/esm/queries/DeleteBuilder.js +15 -1
- package/lib/esm/queries/DeleteBuilder.js.map +1 -1
- package/lib/esm/queries/FieldSet.d.ts +10 -0
- package/lib/esm/queries/FieldSet.js +85 -18
- package/lib/esm/queries/FieldSet.js.map +1 -1
- package/lib/esm/queries/IRLower.js +3 -2
- package/lib/esm/queries/IRLower.js.map +1 -1
- package/lib/esm/queries/IRMutation.js +15 -14
- package/lib/esm/queries/IRMutation.js.map +1 -1
- package/lib/esm/queries/MutationSerialization.js +2 -2
- package/lib/esm/queries/MutationSerialization.js.map +1 -1
- package/lib/esm/queries/PropertyPath.js +2 -2
- package/lib/esm/queries/PropertyPath.js.map +1 -1
- package/lib/esm/queries/QueryBuilder.d.ts +7 -0
- package/lib/esm/queries/QueryBuilder.js +40 -3
- package/lib/esm/queries/QueryBuilder.js.map +1 -1
- package/lib/esm/queries/SelectQuery.js +2 -2
- package/lib/esm/queries/SelectQuery.js.map +1 -1
- package/lib/esm/queries/UpdateBuilder.d.ts +4 -0
- package/lib/esm/queries/UpdateBuilder.js +15 -1
- package/lib/esm/queries/UpdateBuilder.js.map +1 -1
- package/lib/esm/queries/fromJSON.d.ts +12 -1
- package/lib/esm/queries/fromJSON.js +5 -1
- package/lib/esm/queries/fromJSON.js.map +1 -1
- package/lib/esm/queries/lower.js +12 -5
- package/lib/esm/queries/lower.js.map +1 -1
- package/lib/esm/queries/queryDependencies.js +14 -10
- package/lib/esm/queries/queryDependencies.js.map +1 -1
- package/lib/esm/queries/resolveShape.js +14 -2
- package/lib/esm/queries/resolveShape.js.map +1 -1
- package/lib/esm/shapes/Shape.js +2 -1
- package/lib/esm/shapes/Shape.js.map +1 -1
- package/lib/esm/shapes/nodeShapeData.js +7 -10
- package/lib/esm/shapes/nodeShapeData.js.map +1 -1
- package/lib/esm/shapes/registerRuntimeShape.js +3 -1
- package/lib/esm/shapes/registerRuntimeShape.js.map +1 -1
- package/lib/esm/shapes/syncShapes.d.ts +6 -2
- package/lib/esm/shapes/syncShapes.js +16 -9
- package/lib/esm/shapes/syncShapes.js.map +1 -1
- package/lib/esm/shapes/validation.js +2 -2
- package/lib/esm/shapes/validation.js.map +1 -1
- package/lib/esm/sparql/irToAlgebra.js +117 -52
- package/lib/esm/sparql/irToAlgebra.js.map +1 -1
- package/lib/esm/sparql/ownedLinkCheck.js +6 -1
- package/lib/esm/sparql/ownedLinkCheck.js.map +1 -1
- package/lib/esm/utils/LinkedStorage.d.ts +7 -0
- package/lib/esm/utils/LinkedStorage.js +39 -12
- package/lib/esm/utils/LinkedStorage.js.map +1 -1
- package/lib/esm/utils/ShapeCatalog.d.ts +57 -0
- package/lib/esm/utils/ShapeCatalog.js +86 -0
- package/lib/esm/utils/ShapeCatalog.js.map +1 -0
- package/lib/esm/utils/ShapeClass.d.ts +73 -8
- package/lib/esm/utils/ShapeClass.js +245 -66
- package/lib/esm/utils/ShapeClass.js.map +1 -1
- package/lib/esm/utils/registryCache.d.ts +15 -0
- package/lib/esm/utils/registryCache.js +50 -0
- package/lib/esm/utils/registryCache.js.map +1 -0
- package/package.json +1 -1
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
var _a, _b;
|
|
1
|
+
var _a, _b, _c;
|
|
2
2
|
// Namespace import, read at CALL time rather than captured at module-evaluation time.
|
|
3
3
|
// `getOrCreateShapeAdapter` subclasses `Shape` at runtime, and under some import orders this
|
|
4
4
|
// module finishes evaluating before `Shape.js` does — a named import captured then is
|
|
5
5
|
// permanently `undefined`, and the subclass fails with "Class extends value undefined".
|
|
6
6
|
import * as ShapeModule from '../shapes/Shape.js';
|
|
7
7
|
import { getPropertyShape, } from '../shapes/nodeShapeData.js';
|
|
8
|
+
import { RegistryCache } from './registryCache.js';
|
|
9
|
+
export { RegistryCache };
|
|
8
10
|
const resolveTargetClassId = (targetClass) => {
|
|
9
11
|
var _a;
|
|
10
12
|
if (!targetClass)
|
|
@@ -72,13 +74,163 @@ const registryState = ((_b = shapeRegistryGlobal.__linkedShapeRegistry) !== null
|
|
|
72
74
|
nodeShapeRegistry: new Map(),
|
|
73
75
|
shapeAdapters: new Map(),
|
|
74
76
|
registryVersion: 0,
|
|
77
|
+
activeCatalog: undefined,
|
|
75
78
|
}));
|
|
79
|
+
// A container created by an older copy has no slot yet; give it one so every read below
|
|
80
|
+
// sees the same object layout.
|
|
81
|
+
if (!('activeCatalog' in registryState))
|
|
82
|
+
registryState.activeCatalog = undefined;
|
|
76
83
|
/** How many distinct copies of this module are loaded. One is expected. */
|
|
77
84
|
export function getShapeRegistryInstanceCount() {
|
|
78
85
|
return copies.size;
|
|
79
86
|
}
|
|
80
|
-
|
|
81
|
-
|
|
87
|
+
// ---------------------------------------------------------------------------
|
|
88
|
+
// The active shape catalog
|
|
89
|
+
// ---------------------------------------------------------------------------
|
|
90
|
+
/**
|
|
91
|
+
* Run `fn` with `catalog` as the shapes every registry accessor reads; `undefined` means
|
|
92
|
+
* the global registry (explicitly — it does not inherit an outer catalog).
|
|
93
|
+
*
|
|
94
|
+
* Synchronous on purpose: it works the same in the browser and in Node, with no
|
|
95
|
+
* AsyncLocalStorage. Scopes nest, the previous catalog is restored in `finally`, and fn's
|
|
96
|
+
* value is returned unchanged. A promise returned by fn is not awaited, so its
|
|
97
|
+
* continuation runs outside the scope. That is why builders and IRs capture their catalog
|
|
98
|
+
* and every place that picks one up later re-enters it (see docs/architecture/runtime-instances.md).
|
|
99
|
+
*/
|
|
100
|
+
export function withShapeCatalog(catalog, fn) {
|
|
101
|
+
const previous = registryState.activeCatalog;
|
|
102
|
+
if (previous === catalog)
|
|
103
|
+
return fn();
|
|
104
|
+
registryState.activeCatalog = catalog;
|
|
105
|
+
try {
|
|
106
|
+
const result = fn();
|
|
107
|
+
if (result instanceof Promise)
|
|
108
|
+
warnPromiseInScope();
|
|
109
|
+
return result;
|
|
110
|
+
}
|
|
111
|
+
finally {
|
|
112
|
+
registryState.activeCatalog = previous;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Run `fn` with no catalog active, without the promise warning: for core's own calls into a
|
|
117
|
+
* dataset, whose asynchronous continuation is meant to run outside any catalog. @internal
|
|
118
|
+
*/
|
|
119
|
+
export function outsideShapeCatalog(fn) {
|
|
120
|
+
const previous = registryState.activeCatalog;
|
|
121
|
+
if (previous === undefined)
|
|
122
|
+
return fn();
|
|
123
|
+
registryState.activeCatalog = undefined;
|
|
124
|
+
try {
|
|
125
|
+
return fn();
|
|
126
|
+
}
|
|
127
|
+
finally {
|
|
128
|
+
registryState.activeCatalog = previous;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
let warnedPromiseInScope = false;
|
|
132
|
+
/**
|
|
133
|
+
* A scope ends when `fn` returns, so the continuation of a promise `fn` returns runs outside
|
|
134
|
+
* it. Said once, outside production. A builder (a thenable, not a Promise) is the intended
|
|
135
|
+
* return value: it captured the catalog and re-enters it.
|
|
136
|
+
*/
|
|
137
|
+
function warnPromiseInScope() {
|
|
138
|
+
var _a;
|
|
139
|
+
if (warnedPromiseInScope)
|
|
140
|
+
return;
|
|
141
|
+
const env = (_a = globalThis.process) === null || _a === void 0 ? void 0 : _a.env;
|
|
142
|
+
if ((env === null || env === void 0 ? void 0 : env.NODE_ENV) === 'production')
|
|
143
|
+
return;
|
|
144
|
+
warnedPromiseInScope = true;
|
|
145
|
+
console.warn('[linked] withShapeCatalog(catalog, fn): fn returned a promise. The scope ended when fn ' +
|
|
146
|
+
'returned, so code after its first await runs outside the catalog. Build the query inside ' +
|
|
147
|
+
'the scope and await it outside — a builder keeps its catalog.');
|
|
148
|
+
}
|
|
149
|
+
/** The catalog of the current `withShapeCatalog` scope, or undefined for the global registry. */
|
|
150
|
+
export function getActiveShapeCatalog() {
|
|
151
|
+
return registryState.activeCatalog;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* The catalog a builder, a FieldSet or an IR captured — undefined means the global registry.
|
|
155
|
+
* Reads the object's `catalog` field, which builders keep as a getter and IRs as a
|
|
156
|
+
* non-enumerable property, so neither appears in `toJSON` or a JSON round trip.
|
|
157
|
+
*/
|
|
158
|
+
export function catalogOf(queryOrIr) {
|
|
159
|
+
return queryOrIr === null || queryOrIr === void 0 ? void 0 : queryOrIr.catalog;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Record `catalog` on an IR object as a non-enumerable `catalog` field, so the code that
|
|
163
|
+
* compiles it later (often after an `await`) re-enters the catalog it was lowered in.
|
|
164
|
+
* Nothing is written for the global registry: an IR without the field compiles globally.
|
|
165
|
+
* @internal
|
|
166
|
+
*/
|
|
167
|
+
export function attachCatalog(ir, catalog = registryState.activeCatalog) {
|
|
168
|
+
if (catalog !== undefined) {
|
|
169
|
+
Object.defineProperty(ir, 'catalog', {
|
|
170
|
+
value: catalog,
|
|
171
|
+
enumerable: false,
|
|
172
|
+
configurable: true,
|
|
173
|
+
writable: true,
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
return ir;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Process-unique ids for catalogs, for live-query template keys. On `globalThis`, like the
|
|
180
|
+
* registry, so two copies of core give one catalog the same id.
|
|
181
|
+
*/
|
|
182
|
+
const keyState = ((_c = shapeRegistryGlobal.__linkedShapeCatalogKeys) !== null && _c !== void 0 ? _c : (shapeRegistryGlobal.__linkedShapeCatalogKeys = { keys: new WeakMap(), next: 1 }));
|
|
183
|
+
/** 0 for the global registry, else a process-unique id for the catalog. */
|
|
184
|
+
export function shapeCatalogKey(catalog) {
|
|
185
|
+
if (catalog === undefined)
|
|
186
|
+
return 0;
|
|
187
|
+
let key = keyState.keys.get(catalog);
|
|
188
|
+
if (key === undefined) {
|
|
189
|
+
key = keyState.next++;
|
|
190
|
+
keyState.keys.set(catalog, key);
|
|
191
|
+
}
|
|
192
|
+
return key;
|
|
193
|
+
}
|
|
194
|
+
/** The catalog of an adapter class a catalog built, keyed on the class. */
|
|
195
|
+
const adapterCatalogs = new WeakMap();
|
|
196
|
+
/**
|
|
197
|
+
* The catalog a builder made from `shape` captures.
|
|
198
|
+
*
|
|
199
|
+
* Inside a scope: the active catalog when the root is an IRI (`shape` undefined) or a
|
|
200
|
+
* shape the catalog holds; otherwise none. A class the active catalog does not hold is
|
|
201
|
+
* authored code (CN's own shapes, built by CN code while a project scope is active) and
|
|
202
|
+
* must lower against the global registry. Outside a scope: the catalog that built the
|
|
203
|
+
* adapter class, if it is one, else none.
|
|
204
|
+
* @internal
|
|
205
|
+
*/
|
|
206
|
+
export function captureCatalog(shape) {
|
|
207
|
+
var _a;
|
|
208
|
+
const active = registryState.activeCatalog;
|
|
209
|
+
if (shape === undefined || shape === null)
|
|
210
|
+
return active;
|
|
211
|
+
if (active !== undefined) {
|
|
212
|
+
const id = (_a = shape.shape) === null || _a === void 0 ? void 0 : _a.id;
|
|
213
|
+
if (id && active.has(id))
|
|
214
|
+
return active;
|
|
215
|
+
}
|
|
216
|
+
return typeof shape === 'function' ? adapterCatalogs.get(shape) : undefined;
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Throw when a registry write is attempted inside a catalog scope. A catalog is
|
|
220
|
+
* immutable, and a write meant for it would land in the global registry instead.
|
|
221
|
+
* @internal
|
|
222
|
+
*/
|
|
223
|
+
export function assertNoActiveCatalog() {
|
|
224
|
+
if (registryState.activeCatalog !== undefined) {
|
|
225
|
+
throw new Error('Cannot register shapes while a ShapeCatalog is active. Register outside ' +
|
|
226
|
+
'withShapeCatalog, or build a new catalog with ShapeCatalog.from().');
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
function contentsOf(catalog) {
|
|
230
|
+
return catalog;
|
|
231
|
+
}
|
|
232
|
+
const subShapesCache = new RegistryCache();
|
|
233
|
+
const mostSpecificSubShapesCache = new RegistryCache();
|
|
82
234
|
const nodeShapeToShapeClass = registryState.nodeShapeToShapeClass;
|
|
83
235
|
const warnedDuplicateBases = new Set();
|
|
84
236
|
/**
|
|
@@ -92,8 +244,19 @@ const warnedDuplicateBases = new Set();
|
|
|
92
244
|
* metadata, so they use this map and work identically for both kinds of shape.
|
|
93
245
|
*/
|
|
94
246
|
const nodeShapeRegistry = registryState.nodeShapeRegistry;
|
|
95
|
-
/**
|
|
96
|
-
|
|
247
|
+
/**
|
|
248
|
+
* The shapes the accessors read: the active catalog's (its shapes plus core's built-ins),
|
|
249
|
+
* else the global registry. One shared read and a null check on the global path.
|
|
250
|
+
*/
|
|
251
|
+
function activeNodeShapes() {
|
|
252
|
+
const catalog = registryState.activeCatalog;
|
|
253
|
+
return catalog === undefined ? nodeShapeRegistry : contentsOf(catalog).nodeShapes;
|
|
254
|
+
}
|
|
255
|
+
/** The authored classes the accessors read: the catalog's built-ins, else every registered class. */
|
|
256
|
+
function activeShapeClasses() {
|
|
257
|
+
const catalog = registryState.activeCatalog;
|
|
258
|
+
return catalog === undefined ? nodeShapeToShapeClass : contentsOf(catalog).shapeClasses;
|
|
259
|
+
}
|
|
97
260
|
/**
|
|
98
261
|
* The current registration version — a monotonic counter, bumped on every write.
|
|
99
262
|
*
|
|
@@ -110,13 +273,8 @@ export function getRegistryVersion() {
|
|
|
110
273
|
return registryState.registryVersion;
|
|
111
274
|
}
|
|
112
275
|
/** Reverse index parentIri → direct child IRIs, rebuilt when the registry changes. */
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
function getChildIndex() {
|
|
116
|
-
if (childIndex && childIndexVersion === registryState.registryVersion)
|
|
117
|
-
return childIndex;
|
|
118
|
-
const index = new Map();
|
|
119
|
-
nodeShapeRegistry.forEach((shape, id) => {
|
|
276
|
+
const childIndex = new RegistryCache((index) => {
|
|
277
|
+
activeNodeShapes().forEach((shape, id) => {
|
|
120
278
|
var _a;
|
|
121
279
|
const parent = (_a = shape.extends) === null || _a === void 0 ? void 0 : _a.id;
|
|
122
280
|
if (!parent)
|
|
@@ -127,16 +285,14 @@ function getChildIndex() {
|
|
|
127
285
|
else
|
|
128
286
|
index.set(parent, [id]);
|
|
129
287
|
});
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
return
|
|
288
|
+
});
|
|
289
|
+
function getChildIndex() {
|
|
290
|
+
return childIndex.get();
|
|
133
291
|
}
|
|
292
|
+
// Every derived cache is a RegistryCache keyed on this version, so bumping it is the
|
|
293
|
+
// whole invalidation.
|
|
134
294
|
function invalidateRegistryCaches() {
|
|
135
295
|
registryState.registryVersion++;
|
|
136
|
-
subShapesCache.clear();
|
|
137
|
-
mostSpecificSubShapesCache.clear();
|
|
138
|
-
childIndex = null;
|
|
139
|
-
targetClassIndex = null;
|
|
140
296
|
}
|
|
141
297
|
/** Drop the adapter for a shape whose metadata was replaced. */
|
|
142
298
|
function invalidateShapeAdapter(id) {
|
|
@@ -151,6 +307,7 @@ function invalidateShapeAdapter(id) {
|
|
|
151
307
|
* invalidation cannot be keyed on registry size.
|
|
152
308
|
*/
|
|
153
309
|
export function registerNodeShape(nodeShape) {
|
|
310
|
+
assertNoActiveCatalog();
|
|
154
311
|
if (!(nodeShape === null || nodeShape === void 0 ? void 0 : nodeShape.id))
|
|
155
312
|
return;
|
|
156
313
|
nodeShapeRegistry.set(nodeShape.id, nodeShape);
|
|
@@ -162,11 +319,14 @@ export function getNodeShape(nodeShape) {
|
|
|
162
319
|
const id = typeof nodeShape === 'string' ? nodeShape : nodeShape === null || nodeShape === void 0 ? void 0 : nodeShape.id;
|
|
163
320
|
if (!id)
|
|
164
321
|
return undefined;
|
|
165
|
-
return
|
|
322
|
+
return activeNodeShapes().get(id);
|
|
166
323
|
}
|
|
167
|
-
/**
|
|
324
|
+
/**
|
|
325
|
+
* Every registered shape's metadata, keyed by node-shape IRI. Inside a catalog scope:
|
|
326
|
+
* exactly the catalog's shapes plus core's built-ins.
|
|
327
|
+
*/
|
|
168
328
|
export function getAllNodeShapes() {
|
|
169
|
-
return
|
|
329
|
+
return activeNodeShapes();
|
|
170
330
|
}
|
|
171
331
|
/**
|
|
172
332
|
* Lazily-built constructors for shapes that exist only as data.
|
|
@@ -191,15 +351,25 @@ const shapeAdapters = registryState.shapeAdapters;
|
|
|
191
351
|
* you specifically need an authored class; use this when you need *something*
|
|
192
352
|
* constructor-shaped to drive the query builders.
|
|
193
353
|
*/
|
|
354
|
+
/** Adapters built inside a catalog: one map per catalog, keyed by IRI. */
|
|
355
|
+
const catalogAdapters = new WeakMap();
|
|
194
356
|
export function getOrCreateShapeAdapter(nodeShape) {
|
|
195
357
|
var _a;
|
|
196
|
-
const
|
|
358
|
+
const catalog = registryState.activeCatalog;
|
|
359
|
+
const shapes = catalog === undefined ? nodeShapeRegistry : contentsOf(catalog).nodeShapes;
|
|
360
|
+
const data = typeof nodeShape === 'string' ? shapes.get(nodeShape) : nodeShape;
|
|
197
361
|
if (!(data === null || data === void 0 ? void 0 : data.id))
|
|
198
362
|
return undefined;
|
|
199
|
-
const authored = nodeShapeToShapeClass.get(data.id);
|
|
363
|
+
const authored = (catalog === undefined ? nodeShapeToShapeClass : contentsOf(catalog).shapeClasses).get(data.id);
|
|
200
364
|
if (authored)
|
|
201
365
|
return authored;
|
|
202
|
-
|
|
366
|
+
let adapters = shapeAdapters;
|
|
367
|
+
if (catalog !== undefined) {
|
|
368
|
+
adapters = catalogAdapters.get(catalog);
|
|
369
|
+
if (!adapters)
|
|
370
|
+
catalogAdapters.set(catalog, (adapters = new Map()));
|
|
371
|
+
}
|
|
372
|
+
const cached = adapters.get(data.id);
|
|
203
373
|
// Re-registering a shape replaces its metadata, so an adapter built from the old
|
|
204
374
|
// object must not be reused.
|
|
205
375
|
if (cached && cached.shape === data)
|
|
@@ -211,7 +381,9 @@ export function getOrCreateShapeAdapter(nodeShape) {
|
|
|
211
381
|
Object.defineProperty(RuntimeShape, 'name', {
|
|
212
382
|
value: data.label || 'RuntimeShape',
|
|
213
383
|
});
|
|
214
|
-
|
|
384
|
+
adapters.set(data.id, RuntimeShape);
|
|
385
|
+
if (catalog !== undefined)
|
|
386
|
+
adapterCatalogs.set(RuntimeShape, catalog);
|
|
215
387
|
return RuntimeShape;
|
|
216
388
|
}
|
|
217
389
|
/** Resolve a ShapeLike to node-shape metadata, or undefined if it isn't a shape. */
|
|
@@ -219,17 +391,18 @@ function toNodeShapeData(shape) {
|
|
|
219
391
|
var _a, _b;
|
|
220
392
|
if (!shape)
|
|
221
393
|
return undefined;
|
|
394
|
+
const shapes = activeNodeShapes();
|
|
222
395
|
if (typeof shape === 'string')
|
|
223
|
-
return
|
|
396
|
+
return shapes.get(shape);
|
|
224
397
|
const asData = shape;
|
|
225
398
|
// NodeShapeData is a plain object with an id; a Shape class is a function.
|
|
226
399
|
if (typeof shape === 'object' && typeof asData.id === 'string') {
|
|
227
|
-
return (_a =
|
|
400
|
+
return (_a = shapes.get(asData.id)) !== null && _a !== void 0 ? _a : asData;
|
|
228
401
|
}
|
|
229
402
|
const asClass = shape;
|
|
230
403
|
const shapeData = asClass === null || asClass === void 0 ? void 0 : asClass.shape;
|
|
231
404
|
if (shapeData === null || shapeData === void 0 ? void 0 : shapeData.id)
|
|
232
|
-
return (_b =
|
|
405
|
+
return (_b = shapes.get(shapeData.id)) !== null && _b !== void 0 ? _b : shapeData;
|
|
233
406
|
return undefined;
|
|
234
407
|
}
|
|
235
408
|
const warnedUnresolvedExtends = new Set();
|
|
@@ -265,7 +438,8 @@ export function getSuperShapes(shape) {
|
|
|
265
438
|
if (!start)
|
|
266
439
|
return chain;
|
|
267
440
|
// Class-backed: the prototype chain is the authority.
|
|
268
|
-
const
|
|
441
|
+
const shapes = activeNodeShapes();
|
|
442
|
+
const startClass = activeShapeClasses().get(start.id);
|
|
269
443
|
if (startClass) {
|
|
270
444
|
let current = startClass;
|
|
271
445
|
while (current) {
|
|
@@ -286,7 +460,7 @@ export function getSuperShapes(shape) {
|
|
|
286
460
|
if (seen.has(parentId))
|
|
287
461
|
break; // cycle guard — malformed data must not hang a read
|
|
288
462
|
seen.add(parentId);
|
|
289
|
-
const parent =
|
|
463
|
+
const parent = shapes.get(parentId);
|
|
290
464
|
if (!parent) {
|
|
291
465
|
if (!warnedUnresolvedExtends.has(current.id)) {
|
|
292
466
|
warnedUnresolvedExtends.add(current.id);
|
|
@@ -308,6 +482,7 @@ export function getSubShapes(shape) {
|
|
|
308
482
|
if (!start)
|
|
309
483
|
return [];
|
|
310
484
|
const index = getChildIndex();
|
|
485
|
+
const shapes = activeNodeShapes();
|
|
311
486
|
const out = [];
|
|
312
487
|
const seen = new Set([start.id]);
|
|
313
488
|
const queue = [start.id];
|
|
@@ -317,7 +492,7 @@ export function getSubShapes(shape) {
|
|
|
317
492
|
if (seen.has(childId))
|
|
318
493
|
continue;
|
|
319
494
|
seen.add(childId);
|
|
320
|
-
const child =
|
|
495
|
+
const child = shapes.get(childId);
|
|
321
496
|
if (child) {
|
|
322
497
|
out.push(child);
|
|
323
498
|
queue.push(childId);
|
|
@@ -355,7 +530,7 @@ function superShapesWithin(shape, local) {
|
|
|
355
530
|
seen.add(parentId);
|
|
356
531
|
const parent = local.get(parentId);
|
|
357
532
|
if (!parent) {
|
|
358
|
-
const registered =
|
|
533
|
+
const registered = activeNodeShapes().get(parentId);
|
|
359
534
|
if (registered)
|
|
360
535
|
chain.push(registered, ...getSuperShapes(registered));
|
|
361
536
|
break;
|
|
@@ -389,11 +564,12 @@ function targetClassIdWithin(shape, local) {
|
|
|
389
564
|
if (!id)
|
|
390
565
|
return undefined;
|
|
391
566
|
const given = typeof shape === 'string' ? undefined : shape;
|
|
392
|
-
const
|
|
567
|
+
const shapes = activeNodeShapes();
|
|
568
|
+
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 = shapes.get(id)) === null || _l === void 0 ? void 0 : _l.targetClass) === null || _m === void 0 ? void 0 : _m.id;
|
|
393
569
|
if (own)
|
|
394
570
|
return own;
|
|
395
571
|
// 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 =
|
|
572
|
+
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 = shapes.get(id)) !== null && _p !== void 0 ? _p : given);
|
|
397
573
|
if (!start)
|
|
398
574
|
return undefined;
|
|
399
575
|
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;
|
|
@@ -428,14 +604,8 @@ function leastSpecific(candidates, local) {
|
|
|
428
604
|
return (roots.length ? roots : [...candidates]).sort(byId);
|
|
429
605
|
}
|
|
430
606
|
/** targetClass IRI → registered shapes targeting it, ordered. Rebuilt when the registry changes. */
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
function getTargetClassIndex() {
|
|
434
|
-
if (targetClassIndex && targetClassIndexVersion === registryState.registryVersion) {
|
|
435
|
-
return targetClassIndex;
|
|
436
|
-
}
|
|
437
|
-
const index = new Map();
|
|
438
|
-
nodeShapeRegistry.forEach((shape) => {
|
|
607
|
+
const targetClassIndex = new RegistryCache((index) => {
|
|
608
|
+
activeNodeShapes().forEach((shape) => {
|
|
439
609
|
const classId = targetClassIdWithin(shape);
|
|
440
610
|
if (!classId)
|
|
441
611
|
return;
|
|
@@ -446,9 +616,9 @@ function getTargetClassIndex() {
|
|
|
446
616
|
index.set(classId, [shape]);
|
|
447
617
|
});
|
|
448
618
|
index.forEach((shapes, classId) => index.set(classId, leastSpecific(shapes)));
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
return
|
|
619
|
+
});
|
|
620
|
+
function getTargetClassIndex() {
|
|
621
|
+
return targetClassIndex.get();
|
|
452
622
|
}
|
|
453
623
|
export function getShapesForTargetClass(classIri, shapes) {
|
|
454
624
|
var _a;
|
|
@@ -462,6 +632,7 @@ export function getShapesForTargetClass(classIri, shapes) {
|
|
|
462
632
|
}
|
|
463
633
|
export function addNodeShapeToShapeClass(nodeShape, shapeClass) {
|
|
464
634
|
var _a, _b;
|
|
635
|
+
assertNoActiveCatalog();
|
|
465
636
|
if (!(nodeShape === null || nodeShape === void 0 ? void 0 : nodeShape.id)) {
|
|
466
637
|
return;
|
|
467
638
|
}
|
|
@@ -526,6 +697,17 @@ export function resolveShapeConstructor(nodeShape) {
|
|
|
526
697
|
// i.e. a ShapeConstructor. Same cast getShapeClass documents.
|
|
527
698
|
return getOrCreateShapeAdapter(id);
|
|
528
699
|
}
|
|
700
|
+
/**
|
|
701
|
+
* The constructor the query layer resolves an IRI to. In the global registry it is
|
|
702
|
+
* `getShapeClass` (authored classes only, as always). Inside a catalog, where every shape
|
|
703
|
+
* but core's built-ins is data, it is the catalog's constructor for any shape it holds.
|
|
704
|
+
* @internal
|
|
705
|
+
*/
|
|
706
|
+
export function getQueryShapeClass(nodeShape) {
|
|
707
|
+
return registryState.activeCatalog === undefined
|
|
708
|
+
? getShapeClass(nodeShape)
|
|
709
|
+
: resolveShapeConstructor(nodeShape);
|
|
710
|
+
}
|
|
529
711
|
export function getShapeClass(nodeShape) {
|
|
530
712
|
const id = typeof nodeShape === 'string' ? nodeShape : nodeShape === null || nodeShape === void 0 ? void 0 : nodeShape.id;
|
|
531
713
|
if (!id) {
|
|
@@ -533,13 +715,18 @@ export function getShapeClass(nodeShape) {
|
|
|
533
715
|
}
|
|
534
716
|
// SAFETY: The map stores `typeof Shape` (abstract), but registered shapes are always
|
|
535
717
|
// concrete subclasses with a constructor and static .shape — i.e. ShapeConstructor.
|
|
718
|
+
return activeShapeClasses().get(id);
|
|
719
|
+
}
|
|
720
|
+
/** The class registered globally for an IRI, whatever catalog is active. @internal */
|
|
721
|
+
export function getRegisteredShapeClass(id) {
|
|
536
722
|
return nodeShapeToShapeClass.get(id);
|
|
537
723
|
}
|
|
538
724
|
/**
|
|
539
|
-
* Returns all registered shape classes (keyed by NodeShape URI).
|
|
725
|
+
* Returns all registered shape classes (keyed by NodeShape URI). Inside a catalog scope:
|
|
726
|
+
* core's built-in classes only — a catalog holds no other class.
|
|
540
727
|
*/
|
|
541
728
|
export function getAllShapeClasses() {
|
|
542
|
-
return
|
|
729
|
+
return activeShapeClasses();
|
|
543
730
|
}
|
|
544
731
|
/**
|
|
545
732
|
* Returns all the sub shapes of the given shape
|
|
@@ -548,21 +735,17 @@ export function getAllShapeClasses() {
|
|
|
548
735
|
*/
|
|
549
736
|
export function getSubShapesClasses(shape, _internalKey) {
|
|
550
737
|
let key = _internalKey || getKey(shape);
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
mostSpecificSubShapesCache.clear();
|
|
554
|
-
subShapesCacheVersion = registryState.registryVersion;
|
|
555
|
-
}
|
|
556
|
-
if (!subShapesCache.has(key)) {
|
|
738
|
+
const cache = subShapesCache.get();
|
|
739
|
+
if (!cache.has(key)) {
|
|
557
740
|
//apply the hasSuperclass function to the shape
|
|
558
741
|
let filterFunction = applyFnToShapeOrArray(shape, hasSubClass);
|
|
559
742
|
//filter and then sort the results based on their inheritance (most specific classes first, so we use hasSuperClass for the sorting)
|
|
560
|
-
|
|
743
|
+
cache.set(key, filterShapeClasses(filterFunction).sort((a, b) => {
|
|
561
744
|
return hasSubClass(a, b) ? 1 : -1;
|
|
562
745
|
}));
|
|
563
746
|
}
|
|
564
747
|
//return a copy of the array to prevent it from being modified
|
|
565
|
-
return [...
|
|
748
|
+
return [...cache.get(key)];
|
|
566
749
|
}
|
|
567
750
|
/**
|
|
568
751
|
* Returns all the superclasses of the given shape
|
|
@@ -622,7 +805,7 @@ function applyFnToShapeOrArray(shape, filterFn) {
|
|
|
622
805
|
}
|
|
623
806
|
function filterShapeClasses(filterFn) {
|
|
624
807
|
let result = [];
|
|
625
|
-
|
|
808
|
+
activeShapeClasses().forEach((shapeClass) => {
|
|
626
809
|
if (filterFn(shapeClass)) {
|
|
627
810
|
result.push(shapeClass);
|
|
628
811
|
}
|
|
@@ -630,7 +813,7 @@ function filterShapeClasses(filterFn) {
|
|
|
630
813
|
return result;
|
|
631
814
|
}
|
|
632
815
|
export function getLeastSpecificShapeClasses(shapes) {
|
|
633
|
-
let shapeClasses = shapes.map((shape) =>
|
|
816
|
+
let shapeClasses = shapes.map((shape) => getQueryShapeClass(shape.nodeShape.id));
|
|
634
817
|
return filterShapesToLeastSpecific(shapeClasses);
|
|
635
818
|
}
|
|
636
819
|
export function getMostSpecificSubShapes(shape) {
|
|
@@ -639,18 +822,14 @@ export function getMostSpecificSubShapes(shape) {
|
|
|
639
822
|
}
|
|
640
823
|
//get the subshapes of the given shapes
|
|
641
824
|
let key = shape.map((s) => s.name).join(',');
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
mostSpecificSubShapesCache.clear();
|
|
645
|
-
subShapesCacheVersion = registryState.registryVersion;
|
|
646
|
-
}
|
|
647
|
-
if (!mostSpecificSubShapesCache.has(key)) {
|
|
825
|
+
const cache = mostSpecificSubShapesCache.get();
|
|
826
|
+
if (!cache.has(key)) {
|
|
648
827
|
//get the subshapes of the given shapes
|
|
649
828
|
let subShapes = getSubShapesClasses(shape, key);
|
|
650
829
|
//filter them down to the most specific ones (that are not extended by any other shape)
|
|
651
|
-
|
|
830
|
+
cache.set(key, filterShapesToMostSpecific(subShapes));
|
|
652
831
|
}
|
|
653
|
-
return
|
|
832
|
+
return cache.get(key);
|
|
654
833
|
}
|
|
655
834
|
/**
|
|
656
835
|
* Filters out all shapes that are extended by any other shape in the given set/array
|