ldkit 2.5.2 → 2.7.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.
@@ -0,0 +1,505 @@
1
+ import { Parser, Store } from "n3";
2
+ import { NAMESPACES, } from "./schema_to_script.js";
3
+ const BUILTIN_NAMESPACE_IRIS = new Set(NAMESPACES.map((n) => n.$iri));
4
+ const RDF = "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
5
+ const RDFS = "http://www.w3.org/2000/01/rdf-schema#";
6
+ const XSD = "http://www.w3.org/2001/XMLSchema#";
7
+ const SH = "http://www.w3.org/ns/shacl#";
8
+ const RDF_TYPE = `${RDF}type`;
9
+ const RDF_FIRST = `${RDF}first`;
10
+ const RDF_REST = `${RDF}rest`;
11
+ const RDF_NIL = `${RDF}nil`;
12
+ const RDF_LANG_STRING = `${RDF}langString`;
13
+ const XSD_STRING = `${XSD}string`;
14
+ const RDFS_CLASS = `${RDFS}Class`;
15
+ const SH_NODE_SHAPE = `${SH}NodeShape`;
16
+ const SH_TARGET_CLASS = `${SH}targetClass`;
17
+ const SH_PROPERTY = `${SH}property`;
18
+ const SH_PATH = `${SH}path`;
19
+ const SH_INVERSE_PATH = `${SH}inversePath`;
20
+ const SH_DATATYPE = `${SH}datatype`;
21
+ const SH_NODE_KIND = `${SH}nodeKind`;
22
+ const SH_IRI = `${SH}IRI`;
23
+ const SH_NODE = `${SH}node`;
24
+ const SH_CLASS = `${SH}class`;
25
+ const SH_MIN_COUNT = `${SH}minCount`;
26
+ const SH_MAX_COUNT = `${SH}maxCount`;
27
+ const SH_UNIQUE_LANG = `${SH}uniqueLang`;
28
+ const SH_AND = `${SH}and`;
29
+ const SH_OR = `${SH}or`;
30
+ const SH_IN = `${SH}in`;
31
+ // Numeric widening order: leftmost = widest.
32
+ const NUMERIC_WIDENING = [
33
+ `${XSD}decimal`,
34
+ `${XSD}double`,
35
+ `${XSD}float`,
36
+ `${XSD}long`,
37
+ `${XSD}integer`,
38
+ `${XSD}int`,
39
+ `${XSD}short`,
40
+ `${XSD}byte`,
41
+ `${XSD}nonNegativeInteger`,
42
+ `${XSD}positiveInteger`,
43
+ `${XSD}unsignedLong`,
44
+ `${XSD}unsignedInt`,
45
+ ];
46
+ export function shaclToSchema(turtle, options = {}) {
47
+ const converter = new ShaclConverter(options);
48
+ return converter.process(turtle);
49
+ }
50
+ class ShaclConverter {
51
+ constructor(options = {}) {
52
+ Object.defineProperty(this, "store", {
53
+ enumerable: true,
54
+ configurable: true,
55
+ writable: true,
56
+ value: void 0
57
+ });
58
+ Object.defineProperty(this, "schemas", {
59
+ enumerable: true,
60
+ configurable: true,
61
+ writable: true,
62
+ value: []
63
+ });
64
+ Object.defineProperty(this, "shapeIriToName", {
65
+ enumerable: true,
66
+ configurable: true,
67
+ writable: true,
68
+ value: new Map()
69
+ });
70
+ Object.defineProperty(this, "usedNames", {
71
+ enumerable: true,
72
+ configurable: true,
73
+ writable: true,
74
+ value: new Set()
75
+ });
76
+ Object.defineProperty(this, "prefixMap", {
77
+ enumerable: true,
78
+ configurable: true,
79
+ writable: true,
80
+ value: {}
81
+ });
82
+ Object.defineProperty(this, "prefixAliases", {
83
+ enumerable: true,
84
+ configurable: true,
85
+ writable: true,
86
+ value: void 0
87
+ });
88
+ this.prefixAliases = options.prefixAliases ?? {};
89
+ }
90
+ process(turtle) {
91
+ this.parseWithPrefixes(turtle);
92
+ const shapeIris = this.findNodeShapes();
93
+ for (const shapeIri of shapeIris) {
94
+ const name = this.deriveSchemaName(shapeIri);
95
+ this.shapeIriToName.set(shapeIri, name);
96
+ }
97
+ const schemaSourcePrefixes = new Map();
98
+ for (const shapeIri of shapeIris) {
99
+ const schema = this.buildSchema(shapeIri);
100
+ this.schemas.push(schema);
101
+ const baseIri = schema.type[0] ?? shapeIri;
102
+ const prefix = this.findNamespacePrefix(baseIri);
103
+ if (prefix)
104
+ schemaSourcePrefixes.set(schema.name, prefix);
105
+ }
106
+ return {
107
+ schemas: this.schemas,
108
+ extraNamespaces: this.deriveExtraNamespaces(),
109
+ schemaSourcePrefixes,
110
+ };
111
+ }
112
+ parseWithPrefixes(turtle) {
113
+ const parser = new Parser();
114
+ let quads;
115
+ try {
116
+ quads = parser.parse(turtle);
117
+ }
118
+ catch (error) {
119
+ const detail = error instanceof Error ? error.message : String(error);
120
+ throw new Error(`Failed to parse Turtle input: ${detail}`);
121
+ }
122
+ this.store = new Store(quads);
123
+ const prefixRe = /@prefix\s+([A-Za-z_][A-Za-z0-9_-]*)\s*:\s*<([^>]+)>\s*\./g;
124
+ for (const match of turtle.matchAll(prefixRe)) {
125
+ const [, prefix, iri] = match;
126
+ this.prefixMap[prefix] = iri;
127
+ }
128
+ }
129
+ deriveExtraNamespaces() {
130
+ const usedIris = new Set();
131
+ for (const schema of this.schemas) {
132
+ for (const t of schema.type)
133
+ usedIris.add(t);
134
+ for (const prop of Object.values(schema.properties)) {
135
+ usedIris.add(prop.id);
136
+ if (prop.type)
137
+ usedIris.add(prop.type);
138
+ }
139
+ }
140
+ const result = [];
141
+ const seenIris = new Set();
142
+ const usedNames = new Set();
143
+ for (const [prefix, iri] of Object.entries(this.prefixMap)) {
144
+ if (BUILTIN_NAMESPACE_IRIS.has(iri))
145
+ continue;
146
+ if (seenIris.has(iri))
147
+ continue;
148
+ const isUsed = [...usedIris].some((u) => u.startsWith(iri));
149
+ if (!isUsed)
150
+ continue;
151
+ seenIris.add(iri);
152
+ let safeName = prefix;
153
+ while (usedNames.has(safeName)) {
154
+ safeName += "_";
155
+ }
156
+ usedNames.add(safeName);
157
+ result.push({ iri, prefix: safeName });
158
+ }
159
+ return result;
160
+ }
161
+ findNodeShapes() {
162
+ const quads = this.store.getQuads(null, RDF_TYPE, SH_NODE_SHAPE, null);
163
+ const iris = [];
164
+ for (const q of quads) {
165
+ if (q.subject.termType === "NamedNode") {
166
+ iris.push(q.subject.value);
167
+ }
168
+ }
169
+ return iris;
170
+ }
171
+ deriveSchemaName(shapeIri) {
172
+ const targetClass = this.getObjectIri(shapeIri, SH_TARGET_CLASS);
173
+ const baseIri = targetClass ?? shapeIri;
174
+ let local = this.getSuffix(baseIri);
175
+ if (!targetClass && local.endsWith("Shape")) {
176
+ local = local.substring(0, local.length - "Shape".length);
177
+ }
178
+ return this.uniqueName(this.composeSchemaName(baseIri, local));
179
+ }
180
+ // Schema names are always namespace-prefixed (when a @prefix declaration
181
+ // covers the IRI) so that classes sharing a local-part across vocabularies
182
+ // — e.g. m:Campaign, meta:Campaign, google:Campaign — produce
183
+ // self-documenting, deterministic names like MCampaignSchema,
184
+ // MetaCampaignSchema, GoogleCampaignSchema. IRIs without a declared prefix
185
+ // fall back to the bare local-part (preserves prior behavior for
186
+ // hand-written SHACL test fixtures that omit @prefix declarations).
187
+ composeSchemaName(iri, local) {
188
+ const prefix = this.findNamespacePrefix(iri);
189
+ const prefixPart = prefix
190
+ ? (this.prefixAliases[prefix] ??
191
+ this.capitalize(this.sanitizeIdentifier(prefix)))
192
+ : "";
193
+ const localPart = this.capitalize(this.sanitizeIdentifier(local));
194
+ return `${prefixPart}${localPart}Schema`;
195
+ }
196
+ findNamespacePrefix(iri) {
197
+ let bestPrefix = null;
198
+ let bestLength = 0;
199
+ for (const [prefix, ns] of Object.entries(this.prefixMap)) {
200
+ if (iri.startsWith(ns) && ns.length > bestLength) {
201
+ bestPrefix = prefix;
202
+ bestLength = ns.length;
203
+ }
204
+ }
205
+ return bestPrefix;
206
+ }
207
+ uniqueName(name) {
208
+ if (!this.usedNames.has(name)) {
209
+ this.usedNames.add(name);
210
+ return name;
211
+ }
212
+ for (let i = 1; i < 1000; i++) {
213
+ const candidate = `${name}${i}`;
214
+ if (!this.usedNames.has(candidate)) {
215
+ this.usedNames.add(candidate);
216
+ return candidate;
217
+ }
218
+ }
219
+ throw new Error(`Could not generate a unique name for ${name}`);
220
+ }
221
+ buildSchema(shapeIri) {
222
+ return {
223
+ name: this.shapeIriToName.get(shapeIri),
224
+ type: this.deriveType(shapeIri),
225
+ properties: this.buildProperties(shapeIri),
226
+ };
227
+ }
228
+ deriveType(shapeIri) {
229
+ const targetClasses = this.getObjectIris(shapeIri, SH_TARGET_CLASS);
230
+ if (targetClasses.length > 0) {
231
+ return targetClasses;
232
+ }
233
+ const isRdfsClass = this.store.getQuads(shapeIri, RDF_TYPE, RDFS_CLASS, null).length > 0;
234
+ return isRdfsClass ? [shapeIri] : [];
235
+ }
236
+ buildProperties(shapeIri) {
237
+ const propertyNodes = this.store.getQuads(shapeIri, SH_PROPERTY, null, null);
238
+ const properties = {};
239
+ for (const q of propertyNodes) {
240
+ if (q.object.termType !== "NamedNode" &&
241
+ q.object.termType !== "BlankNode") {
242
+ console.error(`[shacl-to-schema] warning: skipping non-node sh:property value on shape <${shapeIri}> (got ${q.object.termType})`);
243
+ continue;
244
+ }
245
+ const { name, spec } = this.buildProperty(q.object, shapeIri);
246
+ if (properties[name]) {
247
+ properties[name] = this.mergePropertySpecs(properties[name], spec);
248
+ }
249
+ else {
250
+ properties[name] = spec;
251
+ }
252
+ }
253
+ return properties;
254
+ }
255
+ // SHACL conjoins multiple property shapes on the same path (AND). LDkit's
256
+ // runtime ignores @type when @schema is set, so schemaRef wins over type.
257
+ mergePropertySpecs(a, b) {
258
+ const merged = { id: a.id };
259
+ if (b.schemaRef !== undefined || a.schemaRef !== undefined) {
260
+ merged.schemaRef = b.schemaRef ?? a.schemaRef;
261
+ }
262
+ else if (b.type !== undefined) {
263
+ merged.type = b.type;
264
+ }
265
+ else if (a.type !== undefined) {
266
+ merged.type = a.type;
267
+ }
268
+ if (a.optional && b.optional)
269
+ merged.optional = true;
270
+ if (a.array && b.array)
271
+ merged.array = true;
272
+ if (a.multilang || b.multilang)
273
+ merged.multilang = true;
274
+ if (a.inverse || b.inverse)
275
+ merged.inverse = true;
276
+ return merged;
277
+ }
278
+ buildProperty(propertyNode, enclosingShapeIri) {
279
+ const { iri: pathIri, inverse } = this.resolvePath(propertyNode, enclosingShapeIri);
280
+ const name = this.getSuffix(pathIri);
281
+ const spec = { id: pathIri };
282
+ if (inverse) {
283
+ spec.inverse = true;
284
+ }
285
+ const direct = this.collectConstraints(propertyNode);
286
+ const orBranches = this.collectOrBranches(propertyNode);
287
+ let forceOptional = false;
288
+ const refTarget = direct.refNode ?? direct.refClass;
289
+ if (direct.uniqueLang || direct.datatype === RDF_LANG_STRING) {
290
+ spec.multilang = true;
291
+ }
292
+ else if (refTarget) {
293
+ // Default to IRI for sh:node / sh:class references
294
+ spec.type = "@id";
295
+ }
296
+ else if (direct.datatype && direct.datatype !== XSD_STRING) {
297
+ spec.type = direct.datatype;
298
+ }
299
+ else if (direct.nodeKind === SH_IRI) {
300
+ spec.type = "@id";
301
+ }
302
+ else if (direct.inFirstType) {
303
+ if (direct.inFirstType === "@id") {
304
+ spec.type = "@id";
305
+ }
306
+ else if (direct.inFirstType !== XSD_STRING) {
307
+ spec.type = direct.inFirstType;
308
+ }
309
+ }
310
+ else if (orBranches.length > 0) {
311
+ const reduced = this.reduceOrBranches(orBranches);
312
+ forceOptional = true;
313
+ if (reduced.kind === "datatype" && reduced.value !== XSD_STRING) {
314
+ spec.type = reduced.value;
315
+ }
316
+ else if (reduced.kind === "iri") {
317
+ spec.type = "@id";
318
+ }
319
+ }
320
+ const minCount = this.getObjectInteger(propertyNode, SH_MIN_COUNT);
321
+ const maxCount = this.getObjectInteger(propertyNode, SH_MAX_COUNT);
322
+ if (forceOptional || minCount === undefined || minCount === 0) {
323
+ spec.optional = true;
324
+ }
325
+ if (maxCount === undefined || maxCount > 1) {
326
+ spec.array = true;
327
+ }
328
+ return { name, spec };
329
+ }
330
+ resolvePath(propertyNode, enclosingShapeIri) {
331
+ const ctx = enclosingShapeIri ? ` on shape <${enclosingShapeIri}>` : "";
332
+ const pathTerm = this.getObjectTerm(propertyNode, SH_PATH);
333
+ if (!pathTerm) {
334
+ throw new Error(`Property shape${ctx} is missing sh:path`);
335
+ }
336
+ if (pathTerm.termType === "NamedNode") {
337
+ return { iri: pathTerm.value, inverse: false };
338
+ }
339
+ if (pathTerm.termType === "BlankNode") {
340
+ const inverseIri = this.getObjectIri(pathTerm, SH_INVERSE_PATH);
341
+ if (inverseIri) {
342
+ return { iri: inverseIri, inverse: true };
343
+ }
344
+ }
345
+ throw new Error(`Unsupported sh:path${ctx}: only simple predicate IRIs and sh:inversePath are supported (got ${pathTerm.termType})`);
346
+ }
347
+ collectConstraints(node) {
348
+ const c = {
349
+ datatype: this.getObjectIri(node, SH_DATATYPE),
350
+ nodeKind: this.getObjectIri(node, SH_NODE_KIND),
351
+ refNode: this.getObjectIri(node, SH_NODE),
352
+ refClass: this.getObjectIri(node, SH_CLASS),
353
+ uniqueLang: this.getObjectBoolean(node, SH_UNIQUE_LANG),
354
+ };
355
+ const inListTerm = this.getObjectTerm(node, SH_IN);
356
+ if (inListTerm) {
357
+ const items = this.walkList(inListTerm);
358
+ const first = items[0];
359
+ if (first?.termType === "NamedNode") {
360
+ c.inFirstType = "@id";
361
+ }
362
+ else if (first?.termType === "Literal") {
363
+ const dt = first.datatype?.value ??
364
+ XSD_STRING;
365
+ c.inFirstType = dt;
366
+ }
367
+ }
368
+ const andListTerm = this.getObjectTerm(node, SH_AND);
369
+ if (andListTerm) {
370
+ for (const branch of this.walkList(andListTerm)) {
371
+ const sub = this.collectConstraints(branch);
372
+ if (sub.datatype !== undefined)
373
+ c.datatype = sub.datatype;
374
+ if (sub.nodeKind !== undefined)
375
+ c.nodeKind = sub.nodeKind;
376
+ if (sub.refNode !== undefined)
377
+ c.refNode = sub.refNode;
378
+ if (sub.refClass !== undefined)
379
+ c.refClass = sub.refClass;
380
+ if (sub.uniqueLang !== undefined)
381
+ c.uniqueLang = sub.uniqueLang;
382
+ if (sub.inFirstType !== undefined)
383
+ c.inFirstType = sub.inFirstType;
384
+ }
385
+ }
386
+ return c;
387
+ }
388
+ collectOrBranches(node) {
389
+ const orListTerm = this.getObjectTerm(node, SH_OR);
390
+ if (!orListTerm)
391
+ return [];
392
+ return this.walkList(orListTerm).map((branch) => this.collectConstraints(branch));
393
+ }
394
+ reduceOrBranches(branches) {
395
+ if (branches.length === 0) {
396
+ return { kind: "untyped" };
397
+ }
398
+ const allDatatypes = branches.every((b) => b.datatype && !b.refNode && !b.refClass);
399
+ const allRefs = branches.every((b) => (b.refNode || b.refClass) && !b.datatype);
400
+ if (allDatatypes) {
401
+ const dts = branches.map((b) => b.datatype);
402
+ const widened = this.pickWidestNumeric(dts);
403
+ if (widened) {
404
+ return { kind: "datatype", value: widened };
405
+ }
406
+ const unique = new Set(dts);
407
+ if (unique.size === 1) {
408
+ return { kind: "datatype", value: dts[0] };
409
+ }
410
+ return { kind: "untyped" };
411
+ }
412
+ if (allRefs) {
413
+ return { kind: "iri" };
414
+ }
415
+ return { kind: "untyped" };
416
+ }
417
+ pickWidestNumeric(types) {
418
+ const indices = types.map((t) => NUMERIC_WIDENING.indexOf(t));
419
+ if (indices.every((i) => i >= 0)) {
420
+ return NUMERIC_WIDENING[Math.min(...indices)];
421
+ }
422
+ return undefined;
423
+ }
424
+ walkList(listHead) {
425
+ const items = [];
426
+ const visited = new Set();
427
+ let current = listHead;
428
+ while (current &&
429
+ !(current.termType === "NamedNode" && current.value === RDF_NIL)) {
430
+ const key = `${current.termType}:${current.value}`;
431
+ if (visited.has(key))
432
+ break;
433
+ visited.add(key);
434
+ const first = this.getObjectTerm(current, RDF_FIRST);
435
+ if (!first)
436
+ break;
437
+ items.push(first);
438
+ const rest = this.getObjectTerm(current, RDF_REST);
439
+ if (!rest)
440
+ break;
441
+ current = rest;
442
+ }
443
+ return items;
444
+ }
445
+ sanitizeIdentifier(value) {
446
+ let cleaned = value.replace(/[^A-Za-z0-9_$]/g, "_");
447
+ if (cleaned.length > 0 && /^[0-9]/.test(cleaned)) {
448
+ cleaned = `_${cleaned}`;
449
+ }
450
+ return cleaned;
451
+ }
452
+ getObjectTerm(subject, predicate) {
453
+ const quads = this.store.getQuads(subject, predicate, null, null);
454
+ return quads[0]?.object;
455
+ }
456
+ getObjectIri(subject, predicate) {
457
+ const term = this.getObjectTerm(subject, predicate);
458
+ if (term && term.termType === "NamedNode") {
459
+ return term.value;
460
+ }
461
+ return undefined;
462
+ }
463
+ getObjectIris(subject, predicate) {
464
+ const quads = this.store.getQuads(subject, predicate, null, null);
465
+ const result = [];
466
+ for (const q of quads) {
467
+ if (q.object.termType === "NamedNode") {
468
+ result.push(q.object.value);
469
+ }
470
+ }
471
+ return result;
472
+ }
473
+ getObjectInteger(subject, predicate) {
474
+ const term = this.getObjectTerm(subject, predicate);
475
+ if (term && term.termType === "Literal") {
476
+ const parsed = parseInt(term.value, 10);
477
+ if (!Number.isNaN(parsed)) {
478
+ return parsed;
479
+ }
480
+ }
481
+ return undefined;
482
+ }
483
+ getObjectBoolean(subject, predicate) {
484
+ const term = this.getObjectTerm(subject, predicate);
485
+ if (term && term.termType === "Literal") {
486
+ if (term.value === "true")
487
+ return true;
488
+ if (term.value === "false")
489
+ return false;
490
+ }
491
+ return undefined;
492
+ }
493
+ getSuffix(value) {
494
+ const cutoff = Math.max(value.lastIndexOf("#"), value.lastIndexOf("/"));
495
+ if (cutoff === -1) {
496
+ return value;
497
+ }
498
+ return value.substring(cutoff + 1);
499
+ }
500
+ capitalize(value) {
501
+ if (value.length === 0)
502
+ return value;
503
+ return value.charAt(0).toUpperCase() + value.slice(1);
504
+ }
505
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ldkit",
3
- "version": "2.5.2",
3
+ "version": "2.7.0",
4
4
  "description": "LDkit, a Linked Data query toolkit for TypeScript developers",
5
5
  "keywords": [
6
6
  "linked data",
@@ -43,7 +43,7 @@
43
43
  "ldkit": "./esm/cli.js"
44
44
  },
45
45
  "dependencies": {
46
- "@comunica/types": "^4",
46
+ "@comunica/types": "^5",
47
47
  "@rdfjs/types": "^2",
48
48
  "@shexjs/parser": "1.0.0-alpha.28",
49
49
  "@types/n3": "^1",
package/script/cli.js CHANGED
@@ -4,10 +4,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
4
4
  const node_process_1 = require("node:process");
5
5
  const node_util_1 = require("node:util");
6
6
  const node_fs_1 = require("node:fs");
7
+ const node_path_1 = require("node:path");
7
8
  const commander_1 = require("commander");
8
9
  const context_to_schema_js_1 = require("./scripts/context_to_schema.js");
9
10
  const shex_to_schema_js_1 = require("./scripts/shex_to_schema.js");
11
+ const shacl_to_schema_js_1 = require("./scripts/shacl_to_schema.js");
10
12
  const schema_to_script_js_1 = require("./scripts/schema_to_script.js");
13
+ const schema_to_package_js_1 = require("./scripts/schema_to_package.js");
11
14
  const asciiArt = String.raw `
12
15
  _ ____ _ _ _
13
16
  | | | _ \| | _(_) |_
@@ -87,6 +90,56 @@ program.command("shexj-to-schema")
87
90
  console.error((0, node_util_1.styleText)("red", `${error.message}`));
88
91
  }
89
92
  });
93
+ program.command("shacl-to-schema")
94
+ .description("Convert a SHACL shapes graph from a file or URL to a LDkit schema")
95
+ .addArgument(new commander_1.Argument("<method>", "type of input").choices([
96
+ "url",
97
+ "file",
98
+ "arg",
99
+ ]))
100
+ .argument("<input>", "input SHACL Turtle - file, URL, or string")
101
+ .option("--prefix-alias <mapping>", "rename a SHACL prefix in generated schema names (format: prefix=Alias). Repeatable.", (value, previous) => [...previous, value], [])
102
+ .action(async (method, input, opts) => {
103
+ try {
104
+ const resolvedInput = await resolve(method, input);
105
+ const prefixAliases = parsePrefixAliases(opts.prefixAlias);
106
+ const { schemas, extraNamespaces } = (0, shacl_to_schema_js_1.shaclToSchema)(resolvedInput, {
107
+ prefixAliases,
108
+ });
109
+ console.log((0, schema_to_script_js_1.schemaToScript)(schemas, extraNamespaces));
110
+ }
111
+ catch (error) {
112
+ console.error((0, node_util_1.styleText)("red", `${error.message}`));
113
+ }
114
+ });
115
+ program.command("shacl-to-package")
116
+ .description("Convert a SHACL shapes graph into a directory of per-namespace LDkit schema files (one .ts per prefix plus an index.ts barrel)")
117
+ .addArgument(new commander_1.Argument("<method>", "type of input").choices([
118
+ "url",
119
+ "file",
120
+ "arg",
121
+ ]))
122
+ .argument("<input>", "input SHACL Turtle - file, URL, or string")
123
+ .argument("<outDir>", "output directory for the generated package")
124
+ .option("--prefix-alias <mapping>", "rename a SHACL prefix in generated schema names AND in the per-namespace file name (format: prefix=Alias). Repeatable.", (value, previous) => [...previous, value], [])
125
+ .action(async (method, input, outDir, opts) => {
126
+ try {
127
+ const resolvedInput = await resolve(method, input);
128
+ const prefixAliases = parsePrefixAliases(opts.prefixAlias);
129
+ const { schemas, extraNamespaces, schemaSourcePrefixes } = (0, shacl_to_schema_js_1.shaclToSchema)(resolvedInput, { prefixAliases });
130
+ const { files } = (0, schema_to_package_js_1.schemaToPackage)(schemas, extraNamespaces, {
131
+ prefixAliases,
132
+ schemaSourcePrefixes,
133
+ });
134
+ (0, node_fs_1.mkdirSync)(outDir, { recursive: true });
135
+ for (const [base, contents] of files) {
136
+ (0, node_fs_1.writeFileSync)((0, node_path_1.join)(outDir, `${base}.ts`), contents);
137
+ }
138
+ }
139
+ catch (error) {
140
+ console.error((0, node_util_1.styleText)("red", `${error.message}`));
141
+ }
142
+ });
90
143
  // Check if no arguments were provided
91
144
  if (node_process_1.argv.length <= 2) {
92
145
  console.log((0, node_util_1.styleText)("red", asciiArt));
@@ -95,6 +148,21 @@ if (node_process_1.argv.length <= 2) {
95
148
  else {
96
149
  program.parse(node_process_1.argv);
97
150
  }
151
+ function parsePrefixAliases(pairs) {
152
+ if (!pairs || pairs.length === 0)
153
+ return {};
154
+ const result = {};
155
+ for (const pair of pairs) {
156
+ const eq = pair.indexOf("=");
157
+ if (eq <= 0 || eq === pair.length - 1) {
158
+ throw new Error(`Invalid --prefix-alias value "${pair}" (expected format: prefix=Alias)`);
159
+ }
160
+ const prefix = pair.substring(0, eq);
161
+ const alias = pair.substring(eq + 1);
162
+ result[prefix] = alias;
163
+ }
164
+ return result;
165
+ }
98
166
  async function resolve(method, input) {
99
167
  if (method === "url") {
100
168
  try {
@@ -51,8 +51,10 @@ export declare function resolveOptions(options?: Options): {
51
51
  fileBaseIRI?: string;
52
52
  log?: import("@comunica/types").Logger;
53
53
  datetime?: Date;
54
+ queryTimestampHighResolution?: DOMHighResTimeStamp;
54
55
  httpProxyHandler?: import("@comunica/types").IProxyHandler;
55
56
  lenient?: boolean;
57
+ parseUnsupportedVersions?: boolean;
56
58
  httpIncludeCredentials?: boolean;
57
59
  httpAuth?: string;
58
60
  httpTimeout?: number;
@@ -60,14 +62,27 @@ export declare function resolveOptions(options?: Options): {
60
62
  httpRetryCount?: number;
61
63
  httpRetryDelayFallback?: number;
62
64
  httpRetryDelayLimit?: number;
65
+ httpRetryStatusCodes?: number[];
66
+ httpRetryBodyCount?: number;
67
+ httpRetryBodyDelayFallback?: number;
68
+ httpRetryBodyAllowUnsafe?: boolean;
69
+ httpRetryBodyMaxBytes?: number;
70
+ httpAbortSignal?: AbortSignal;
71
+ httpCache?: boolean;
63
72
  fetch?: typeof fetch;
73
+ recoverBrokenLinks?: boolean;
64
74
  readOnly?: boolean;
75
+ extensionFunctions?: Record<string, (args: import("@rdfjs/types").Term[]) => Promise<import("@rdfjs/types").Term>>;
76
+ extensionFunctionsAlwaysPushdown?: boolean;
65
77
  extensionFunctionCreator?: (functionNamedNode: import("@rdfjs/types").NamedNode) => ((args: import("@rdfjs/types").Term[]) => Promise<import("@rdfjs/types").Term>) | undefined;
66
78
  functionArgumentsCache?: import("@comunica/types").FunctionArgumentsCache;
67
- extensionFunctions?: Record<string, (args: import("@rdfjs/types").Term[]) => Promise<import("@rdfjs/types").Term>>;
68
79
  explain?: import("@comunica/types").QueryExplainMode;
69
- recoverBrokenLinks?: boolean;
80
+ unionDefaultGraph?: boolean;
81
+ traverse?: boolean;
82
+ invalidateCache?: boolean;
83
+ dataFactory?: import("@comunica/types").ComunicaDataFactory;
70
84
  distinctConstruct?: boolean;
85
+ rdfSerializationPrefixes?: Record<string, string>;
71
86
  };
72
87
  export declare function resolveQueryContext(options: Options): QueryContext;
73
88
  //# sourceMappingURL=options.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../../src/library/options.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,YAAY,EAElB,MAAM,iBAAiB,CAAC;AAEzB;;;;;;;;GAQG;AACH,MAAM,MAAM,OAAO,GAAG;IACpB,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACpC,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;AAU1B;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAEvD;AAED,wBAAgB,cAAc,CAAC,OAAO,GAAE,OAAY;YAxCzC,YAAY;eACV,MAAM;UACV,MAAM;cACF,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;EA2CnC;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,YAAY,CAclE"}
1
+ {"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../../src/library/options.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,YAAY,EAElB,MAAM,iBAAiB,CAAC;AAEzB;;;;;;;;GAQG;AACH,MAAM,MAAM,OAAO,GAAG;IACpB,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACpC,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;AAU1B;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAEvD;AAED,wBAAgB,cAAc,CAAC,OAAO,GAAE,OAAY;YAxCzC,YAAY;eACV,MAAM;UACV,MAAM;cACF,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA2CnC;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,YAAY,CAclE"}
@@ -0,0 +1,10 @@
1
+ import { type ExtraNamespace, type SchemaSpec } from "./schema_to_script.js";
2
+ export type SchemaToPackageOptions = {
3
+ prefixAliases?: Record<string, string>;
4
+ schemaSourcePrefixes?: Map<string, string>;
5
+ };
6
+ export type SchemaPackage = {
7
+ files: Map<string, string>;
8
+ };
9
+ export declare function schemaToPackage(schemas: SchemaSpec[], extraNamespaces?: ExtraNamespace[], options?: SchemaToPackageOptions): SchemaPackage;
10
+ //# sourceMappingURL=schema_to_package.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema_to_package.d.ts","sourceRoot":"","sources":["../../src/scripts/schema_to_package.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,UAAU,EAEhB,MAAM,uBAAuB,CAAC;AAE/B,MAAM,MAAM,sBAAsB,GAAG;IACnC,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC,oBAAoB,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC5C,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC5B,CAAC;AAKF,wBAAgB,eAAe,CAC7B,OAAO,EAAE,UAAU,EAAE,EACrB,eAAe,GAAE,cAAc,EAAO,EACtC,OAAO,GAAE,sBAA2B,GACnC,aAAa,CAkDf"}