@ng-org/shex-orm 0.1.2

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.
Files changed (64) hide show
  1. package/README.md +240 -0
  2. package/dist/ShexJTypes.d.ts +542 -0
  3. package/dist/ShexJTypes.d.ts.map +1 -0
  4. package/dist/ShexJTypes.js +10 -0
  5. package/dist/build.d.ts +8 -0
  6. package/dist/build.d.ts.map +1 -0
  7. package/dist/build.js +72 -0
  8. package/dist/cli.d.ts +3 -0
  9. package/dist/cli.d.ts.map +1 -0
  10. package/dist/cli.js +15 -0
  11. package/dist/index.d.ts +2 -0
  12. package/dist/index.d.ts.map +1 -0
  13. package/dist/index.js +1 -0
  14. package/dist/schema-converter/__tests__/typingTransformer.test.d.ts +2 -0
  15. package/dist/schema-converter/__tests__/typingTransformer.test.d.ts.map +1 -0
  16. package/dist/schema-converter/__tests__/typingTransformer.test.js +76 -0
  17. package/dist/schema-converter/converter.d.ts +12 -0
  18. package/dist/schema-converter/converter.d.ts.map +1 -0
  19. package/dist/schema-converter/converter.js +79 -0
  20. package/dist/schema-converter/templates/schema.ejs +8 -0
  21. package/dist/schema-converter/templates/shapeTypes.ejs +14 -0
  22. package/dist/schema-converter/templates/typings.ejs +14 -0
  23. package/dist/schema-converter/transformers/ShexJSchemaTransformer.d.ts +348 -0
  24. package/dist/schema-converter/transformers/ShexJSchemaTransformer.d.ts.map +1 -0
  25. package/dist/schema-converter/transformers/ShexJSchemaTransformer.js +239 -0
  26. package/dist/schema-converter/transformers/ShexJTypingTransformer.d.ts +366 -0
  27. package/dist/schema-converter/transformers/ShexJTypingTransformer.d.ts.map +1 -0
  28. package/dist/schema-converter/transformers/ShexJTypingTransformer.js +623 -0
  29. package/dist/schema-converter/util/ShapeInterfaceDeclaration.d.ts +5 -0
  30. package/dist/schema-converter/util/ShapeInterfaceDeclaration.d.ts.map +1 -0
  31. package/dist/schema-converter/util/ShapeInterfaceDeclaration.js +1 -0
  32. package/dist/schema-converter/util/annotateReadablePredicates.d.ts +8 -0
  33. package/dist/schema-converter/util/annotateReadablePredicates.d.ts.map +1 -0
  34. package/dist/schema-converter/util/annotateReadablePredicates.js +148 -0
  35. package/dist/schema-converter/util/dedupeObjectTypeMembers.d.ts +3 -0
  36. package/dist/schema-converter/util/dedupeObjectTypeMembers.d.ts.map +1 -0
  37. package/dist/schema-converter/util/dedupeObjectTypeMembers.js +47 -0
  38. package/dist/schema-converter/util/getRdfTypesForTripleConstraint.d.ts +4 -0
  39. package/dist/schema-converter/util/getRdfTypesForTripleConstraint.d.ts.map +1 -0
  40. package/dist/schema-converter/util/getRdfTypesForTripleConstraint.js +98 -0
  41. package/dist/types.d.ts +37 -0
  42. package/dist/types.d.ts.map +1 -0
  43. package/dist/types.js +10 -0
  44. package/dist/util/forAllShapes.d.ts +2 -0
  45. package/dist/util/forAllShapes.d.ts.map +1 -0
  46. package/dist/util/forAllShapes.js +25 -0
  47. package/package.json +67 -0
  48. package/src/ShexJTypes.ts +616 -0
  49. package/src/build.ts +106 -0
  50. package/src/cli.ts +23 -0
  51. package/src/index.ts +1 -0
  52. package/src/schema-converter/__tests__/typingTransformer.test.ts +85 -0
  53. package/src/schema-converter/converter.ts +128 -0
  54. package/src/schema-converter/templates/schema.ejs +8 -0
  55. package/src/schema-converter/templates/shapeTypes.ejs +14 -0
  56. package/src/schema-converter/templates/typings.ejs +14 -0
  57. package/src/schema-converter/transformers/ShexJSchemaTransformer.ts +284 -0
  58. package/src/schema-converter/transformers/ShexJTypingTransformer.ts +807 -0
  59. package/src/schema-converter/util/ShapeInterfaceDeclaration.ts +5 -0
  60. package/src/schema-converter/util/annotateReadablePredicates.ts +173 -0
  61. package/src/schema-converter/util/dedupeObjectTypeMembers.ts +61 -0
  62. package/src/schema-converter/util/getRdfTypesForTripleConstraint.ts +153 -0
  63. package/src/types.ts +51 -0
  64. package/src/util/forAllShapes.ts +39 -0
@@ -0,0 +1,5 @@
1
+ import type { InterfaceDeclaration } from "dts-dom";
2
+
3
+ export interface ShapeInterfaceDeclaration extends InterfaceDeclaration {
4
+ shapeId?: string;
5
+ }
@@ -0,0 +1,173 @@
1
+ // Copyright (c) 2025 Laurin Weger, Par le Peuple, NextGraph.org developers
2
+ // All rights reserved.
3
+ // Licensed under the Apache License, Version 2.0
4
+ // <LICENSE-APACHE2 or http://www.apache.org/licenses/LICENSE-2.0>
5
+ // or the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
6
+ // at your option. All files in the project carrying such
7
+ // notice may not be copied, modified, or distributed except
8
+ // according to those terms.
9
+ // SPDX-License-Identifier: Apache-2.0 OR MIT
10
+
11
+ import type { Schema, ShapeDecl, Shape, EachOf, TripleConstraint } from "shexj";
12
+
13
+ // Split IRI by colon, slash and hash; drop empties
14
+ const splitIriTokens = (iri: string): string[] =>
15
+ iri.split(/[:/#]+/).filter(Boolean);
16
+ // Keep dots and dashes (so 0.1 stays as 0.1) but sanitize everything else
17
+ const sanitize = (s: string) => s.replace(/[^\w.\-]/g, "_");
18
+
19
+ type TCwReadable = TripleConstraint & { readablePredicate?: string };
20
+
21
+ /**
22
+ * Annotate EachOf-level TripleConstraints with a collision-free readablePredicate.
23
+ * Rule: for any group that shares the same local token, rename all members using
24
+ * prefix-first `${prefix}_${local}` from right to left; fallback to composite.
25
+ */
26
+ export default function annotateReadablePredicates(schema: Schema): void {
27
+ const shapes = schema.shapes ?? [];
28
+
29
+ const annotateEachOf = (eachOf: EachOf): void => {
30
+ if (
31
+ !eachOf ||
32
+ eachOf.type !== "EachOf" ||
33
+ !Array.isArray(eachOf.expressions)
34
+ )
35
+ return;
36
+
37
+ const tcs = (eachOf.expressions as unknown[]).filter(
38
+ (e): e is TCwReadable =>
39
+ typeof e === "object" &&
40
+ e !== null &&
41
+ (e as any).type === "TripleConstraint"
42
+ );
43
+
44
+ if (tcs.length > 0) {
45
+ // Group by local token (last segment of IRI) and set a base readablePredicate for all
46
+ const readableNameToPredicatesMap = new Map<
47
+ string,
48
+ TCwReadable[]
49
+ >();
50
+ for (const tripleConstraint of tcs) {
51
+ // Use the name based on the IRI ending.
52
+ let readableName: string;
53
+ // Special case rdfs:type => @type
54
+ if (
55
+ tripleConstraint.predicate ===
56
+ "http://www.w3.org/1999/02/22-rdf-syntax-ns#type"
57
+ ) {
58
+ readableName = "@type";
59
+ } else {
60
+ const tokens = splitIriTokens(tripleConstraint.predicate);
61
+ readableName = tokens.length
62
+ ? tokens[tokens.length - 1]
63
+ : tripleConstraint.predicate;
64
+ }
65
+ // default base name for non-colliders
66
+ tripleConstraint.readablePredicate = readableName;
67
+ const groupMembers =
68
+ readableNameToPredicatesMap.get(readableName) ?? [];
69
+ groupMembers.push(tripleConstraint);
70
+ readableNameToPredicatesMap.set(readableName, groupMembers);
71
+ }
72
+ // Resolve each group (rename all in collisions)
73
+ for (const [, groupMembers] of readableNameToPredicatesMap) {
74
+ if (groupMembers.length <= 1) continue;
75
+ const used = new Set<string>();
76
+ const local =
77
+ splitIriTokens(groupMembers[0].predicate).slice(-1)[0] ??
78
+ "";
79
+ for (const tc of groupMembers) {
80
+ const tokens = splitIriTokens(tc.predicate);
81
+ let localIdx = tokens.lastIndexOf(local);
82
+ if (localIdx === -1)
83
+ localIdx = Math.max(tokens.length - 1, 0);
84
+ let prefixIdx = localIdx - 1;
85
+ let assigned = false;
86
+ while (prefixIdx >= 0) {
87
+ const cand = `${sanitize(tokens[prefixIdx])}_${sanitize(
88
+ tokens[localIdx]
89
+ )}`;
90
+ if (!used.has(cand)) {
91
+ tc.readablePredicate = cand;
92
+ used.add(cand);
93
+ assigned = true;
94
+ break;
95
+ }
96
+ prefixIdx -= 1;
97
+ }
98
+ if (!assigned) {
99
+ const iriNoProto = tc.predicate.replace(
100
+ /^[a-z]+:\/\//i,
101
+ ""
102
+ );
103
+ const composite = sanitize(
104
+ iriNoProto
105
+ .split(/[:/#]+/)
106
+ .slice(0, -1)
107
+ .join("_") || "iri"
108
+ );
109
+ let cand = `${composite}_${sanitize(tokens[localIdx] || local)}`;
110
+ let n = 1;
111
+ while (used.has(cand)) cand = `${cand}_${n++}`;
112
+ tc.readablePredicate = cand;
113
+ used.add(cand);
114
+ }
115
+ }
116
+ }
117
+
118
+ // Recurse into nested valueExpr shapes of each TC
119
+ for (const tc of tcs) {
120
+ const ve: any = (tc as any).valueExpr;
121
+ if (ve && typeof ve === "object") {
122
+ const t = (ve as any).type;
123
+ if (t === "Shape" && (ve as any).expression)
124
+ annotateEachOf((ve as any).expression as EachOf);
125
+ else if (t === "EachOf") annotateEachOf(ve as EachOf);
126
+ else if (
127
+ t === "ShapeOr" &&
128
+ Array.isArray((ve as any).shapeExprs)
129
+ ) {
130
+ for (const sub of (ve as any).shapeExprs)
131
+ annotateFromExpr(sub);
132
+ } else if (
133
+ t === "ShapeAnd" &&
134
+ Array.isArray((ve as any).shapeExprs)
135
+ ) {
136
+ for (const sub of (ve as any).shapeExprs)
137
+ annotateFromExpr(sub);
138
+ }
139
+ }
140
+ }
141
+ }
142
+
143
+ // Also recurse into any inline sub-EachOf/Shape expressions found directly in expressions
144
+ for (const ex of eachOf.expressions as any[]) {
145
+ if (ex && typeof ex === "object") annotateFromExpr(ex);
146
+ }
147
+ };
148
+
149
+ const annotateFromExpr = (expr: any): void => {
150
+ if (!expr || typeof expr !== "object") return;
151
+ const t = (expr as any).type;
152
+ if (t === "Shape" && (expr as any).expression)
153
+ annotateEachOf((expr as any).expression as EachOf);
154
+ else if (t === "EachOf") annotateEachOf(expr as EachOf);
155
+ else if (t === "ShapeOr" && Array.isArray((expr as any).shapeExprs)) {
156
+ for (const sub of (expr as any).shapeExprs) annotateFromExpr(sub);
157
+ } else if (
158
+ t === "ShapeAnd" &&
159
+ Array.isArray((expr as any).shapeExprs)
160
+ ) {
161
+ for (const sub of (expr as any).shapeExprs) annotateFromExpr(sub);
162
+ } else if (t === "TripleConstraint") {
163
+ const ve = (expr as any).valueExpr;
164
+ if (ve && typeof ve === "object") annotateFromExpr(ve);
165
+ }
166
+ };
167
+
168
+ for (const s of shapes) {
169
+ const sd = s as ShapeDecl;
170
+ const shape = (sd.shapeExpr || (sd as any)) as Shape | undefined;
171
+ if (shape?.expression) annotateFromExpr(shape as any);
172
+ }
173
+ }
@@ -0,0 +1,61 @@
1
+ // Copyright (c) 2025 Laurin Weger, Par le Peuple, NextGraph.org developers
2
+ // All rights reserved.
3
+ // Licensed under the Apache License, Version 2.0
4
+ // <LICENSE-APACHE2 or http://www.apache.org/licenses/LICENSE-2.0>
5
+ // or the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
6
+ // at your option. All files in the project carrying such
7
+ // notice may not be copied, modified, or distributed except
8
+ // according to those terms.
9
+ // SPDX-License-Identifier: Apache-2.0 OR MIT
10
+
11
+ import type { ObjectTypeMember } from "dts-dom";
12
+ import * as dom from "dts-dom";
13
+
14
+ export function dedupeObjectTypeMembers(
15
+ memberList: ObjectTypeMember[],
16
+ ): ObjectTypeMember[] {
17
+ const properties: Record<string, dom.PropertyDeclaration> = {};
18
+ memberList.forEach((expression) => {
19
+ const propertyDeclaration = expression as dom.PropertyDeclaration;
20
+ // Combine properties if they're duplicates
21
+ if (properties[propertyDeclaration.name]) {
22
+ const oldPropertyDeclaration = properties[propertyDeclaration.name];
23
+ const oldPropertyType = isLdSetType(oldPropertyDeclaration.type)
24
+ ? oldPropertyDeclaration.type.typeArguments[0]
25
+ : oldPropertyDeclaration.type;
26
+ const propertyType = isLdSetType(propertyDeclaration.type)
27
+ ? propertyDeclaration.type.typeArguments[0]
28
+ : propertyDeclaration.type;
29
+ const isOptional =
30
+ propertyDeclaration.flags === dom.DeclarationFlags.Optional ||
31
+ oldPropertyDeclaration.flags === dom.DeclarationFlags.Optional;
32
+ properties[propertyDeclaration.name] = dom.create.property(
33
+ propertyDeclaration.name,
34
+ {
35
+ kind: "name",
36
+ name: "LdSet",
37
+ typeArguments: [dom.create.union([oldPropertyType, propertyType])],
38
+ },
39
+ isOptional ? dom.DeclarationFlags.Optional : dom.DeclarationFlags.None,
40
+ );
41
+ // Set JS Comment
42
+ properties[propertyDeclaration.name].jsDocComment =
43
+ oldPropertyDeclaration.jsDocComment && propertyDeclaration.jsDocComment
44
+ ? `${oldPropertyDeclaration.jsDocComment} | ${propertyDeclaration.jsDocComment}`
45
+ : oldPropertyDeclaration.jsDocComment ||
46
+ propertyDeclaration.jsDocComment;
47
+ } else {
48
+ properties[propertyDeclaration.name] = propertyDeclaration;
49
+ }
50
+ });
51
+ return Object.values(properties);
52
+ }
53
+
54
+ function isLdSetType(
55
+ potentialLdSet: dom.Type,
56
+ ): potentialLdSet is dom.NamedTypeReference {
57
+ return (
58
+ (potentialLdSet as dom.NamedTypeReference).kind === "name" &&
59
+ (potentialLdSet as dom.NamedTypeReference).name === "LdSet"
60
+ );
61
+ }
@@ -0,0 +1,153 @@
1
+ // Copyright (c) 2025 Laurin Weger, Par le Peuple, NextGraph.org developers
2
+ // All rights reserved.
3
+ // Licensed under the Apache License, Version 2.0
4
+ // <LICENSE-APACHE2 or http://www.apache.org/licenses/LICENSE-2.0>
5
+ // or the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
6
+ // at your option. All files in the project carrying such
7
+ // notice may not be copied, modified, or distributed except
8
+ // according to those terms.
9
+ // SPDX-License-Identifier: Apache-2.0 OR MIT
10
+
11
+ import type {
12
+ ShexJTraverserTypes,
13
+ tripleExprOrRef,
14
+ } from "@ldo/traverser-shexj";
15
+ import type { InterfaceInstanceNode } from "@ldo/type-traverser";
16
+
17
+ function addRdfTypeFromTripleExpr(
18
+ tripleExpr: tripleExprOrRef,
19
+ rdfTypeSet: Set<string>
20
+ ) {
21
+ if (
22
+ typeof tripleExpr === "object" &&
23
+ tripleExpr.type === "TripleConstraint" &&
24
+ tripleExpr.predicate ===
25
+ "http://www.w3.org/1999/02/22-rdf-syntax-ns#type" &&
26
+ typeof tripleExpr.valueExpr === "object" &&
27
+ tripleExpr.valueExpr.type === "NodeConstraint" &&
28
+ tripleExpr.valueExpr.values
29
+ ) {
30
+ tripleExpr.valueExpr.values.forEach((val) => {
31
+ if (typeof val === "string") rdfTypeSet.add(val);
32
+ // TODO handle other edge cases like IRIStem
33
+ });
34
+ }
35
+ }
36
+
37
+ function recursivelyGatherTypesFromShapeNodes(
38
+ shapeNode: InterfaceInstanceNode<
39
+ ShexJTraverserTypes,
40
+ "Shape",
41
+ ShexJTraverserTypes["Shape"]
42
+ >,
43
+ rdfTypeSet: Set<string>
44
+ ): void {
45
+ const tripleExpr = shapeNode.instance.expression;
46
+ if (tripleExpr) addRdfTypeFromTripleExpr(tripleExpr, rdfTypeSet);
47
+
48
+ shapeNode.parent("shapeExpr").forEach((parentShapeExpr) => {
49
+ parentShapeExpr
50
+ .parent("ShapeDecl", "shapeExpr")
51
+ .forEach((parentShapeDecl) => {
52
+ parentShapeDecl
53
+ .parent("shapeDeclRef")
54
+ .forEach((parentShapeDeclOrRef) => {
55
+ parentShapeDeclOrRef
56
+ .parent("shapeExprOrRef")
57
+ .forEach((parentShapeExprOrRef) => {
58
+ parentShapeExprOrRef
59
+ .parent("Shape", "extends")
60
+ .forEach((parentShape) => {
61
+ recursivelyGatherTypesFromShapeNodes(
62
+ parentShape,
63
+ rdfTypeSet
64
+ );
65
+ const childExpressionNode =
66
+ parentShape.child("expression");
67
+ if (!childExpressionNode) return;
68
+ const childEachOf = childExpressionNode
69
+ .child()
70
+ .child();
71
+ if (childEachOf.typeName === "EachOf") {
72
+ recursivelyGatherTypesFromEachOfNodes(
73
+ childEachOf,
74
+ rdfTypeSet
75
+ );
76
+ }
77
+ });
78
+ });
79
+ });
80
+ });
81
+ });
82
+ }
83
+
84
+ function recursivelyGatherTypesFromEachOfNodes(
85
+ eachOfNode: InterfaceInstanceNode<
86
+ ShexJTraverserTypes,
87
+ "EachOf",
88
+ ShexJTraverserTypes["EachOf"]
89
+ >,
90
+ rdfTypeSet: Set<string>
91
+ ): void {
92
+ const tripleExprs = eachOfNode.instance.expressions;
93
+ tripleExprs.forEach((tripleExpr) => {
94
+ addRdfTypeFromTripleExpr(tripleExpr, rdfTypeSet);
95
+ });
96
+
97
+ eachOfNode.parent("tripleExpr").forEach((tripleExprNode) => {
98
+ const tripleExprOrRefNodes = tripleExprNode.parent("tripleExprOrRef");
99
+ tripleExprOrRefNodes.forEach((tripleExprOrRdfNode) => {
100
+ const parentEachOfs = tripleExprOrRdfNode.parent(
101
+ "EachOf",
102
+ "expressions"
103
+ );
104
+ parentEachOfs.forEach((parentEachOf) => {
105
+ recursivelyGatherTypesFromEachOfNodes(parentEachOf, rdfTypeSet);
106
+ });
107
+ // Deal with shape extends
108
+ const parentShapes = tripleExprOrRdfNode.parent(
109
+ "Shape",
110
+ "expression"
111
+ );
112
+ parentShapes.forEach((parentShape) =>
113
+ recursivelyGatherTypesFromShapeNodes(parentShape, rdfTypeSet)
114
+ );
115
+ });
116
+ });
117
+ }
118
+
119
+ export function getRdfTypesForTripleConstraint(
120
+ tripleConstraintNode: InterfaceInstanceNode<
121
+ ShexJTraverserTypes,
122
+ "TripleConstraint",
123
+ ShexJTraverserTypes["TripleConstraint"]
124
+ >
125
+ ): string[] | undefined[] {
126
+ // Check that there's a triple constraint that is a type at the
127
+ // same level if there is, use that as an rdfType
128
+ const rdfTypeSet = new Set<string>();
129
+ tripleConstraintNode.parent("tripleExpr").forEach((tripleExprParents) => {
130
+ tripleExprParents
131
+ .parent("tripleExprOrRef")
132
+ .forEach((tripleExprOrRefParent) => {
133
+ tripleExprOrRefParent
134
+ .parent("EachOf", "expressions")
135
+ .forEach((eachOfParent) => {
136
+ recursivelyGatherTypesFromEachOfNodes(
137
+ eachOfParent,
138
+ rdfTypeSet
139
+ );
140
+ });
141
+ tripleExprOrRefParent
142
+ .parent("Shape", "expression")
143
+ .forEach((shapeParent) => {
144
+ recursivelyGatherTypesFromShapeNodes(
145
+ shapeParent,
146
+ rdfTypeSet
147
+ );
148
+ });
149
+ });
150
+ });
151
+ const rdfTypes = rdfTypeSet.size > 0 ? Array.from(rdfTypeSet) : [undefined];
152
+ return rdfTypes;
153
+ }
package/src/types.ts ADDED
@@ -0,0 +1,51 @@
1
+ // Copyright (c) 2025 Laurin Weger, Par le Peuple, NextGraph.org developers
2
+ // All rights reserved.
3
+ // Licensed under the Apache License, Version 2.0
4
+ // <LICENSE-APACHE2 or http://www.apache.org/licenses/LICENSE-2.0>
5
+ // or the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
6
+ // at your option. All files in the project carrying such
7
+ // notice may not be copied, modified, or distributed except
8
+ // according to those terms.
9
+ // SPDX-License-Identifier: Apache-2.0 OR MIT
10
+
11
+ export interface ShapeType<T extends BaseType> {
12
+ schema: Schema;
13
+ shape: string;
14
+ }
15
+
16
+ export interface BaseType extends Record<string, any> {
17
+ "@id": string;
18
+ }
19
+
20
+ export type Schema = {
21
+ [id: string]: Shape;
22
+ };
23
+
24
+ export interface Shape {
25
+ iri: string;
26
+ predicates: Predicate[];
27
+ }
28
+
29
+ export type DataType = {
30
+ /** The required literal value(s), if type is `literal`. Others are allowed, if `extra` is true. */
31
+ literals?: number[] | string[] | boolean;
32
+ /** If `valType` is `"shape"`, the nested shape or its reference. Use reference for serialization. */
33
+ shape?: string | Shape;
34
+ /** The type of object value for a triple constraint. */
35
+ valType: "number" | "string" | "boolean" | "iri" | "literal" | "shape";
36
+ };
37
+
38
+ export interface Predicate {
39
+ /** Allowed type of object. If more than one is present, either of them is allowed. */
40
+ dataTypes: DataType[];
41
+ /** The RDF predicate URI. */
42
+ iri: string;
43
+ /** The alias of the `predicateUri` when serialized to a JSON object. */
44
+ readablePredicate: string;
45
+ /** Maximum allowed number of values. `-1` means infinite. */
46
+ maxCardinality: number;
47
+ /** Minimum required number of values */
48
+ minCardinality: number;
49
+ /** If other (additional) values are permitted. Useful for literals. */
50
+ extra?: boolean;
51
+ }
@@ -0,0 +1,39 @@
1
+ // Copyright (c) 2023 Jackson Morgan
2
+ // Licensed under the Apache License, Version 2.0
3
+ // <LICENSE-APACHE2 or http://www.apache.org/licenses/LICENSE-2.0>
4
+ // or the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
5
+ // at your option. All files in the project carrying such
6
+ // notice may not be copied, modified, or distributed except
7
+ // according to those terms.
8
+ // SPDX-License-Identifier: Apache-2.0 OR MIT
9
+
10
+ import fs from "fs";
11
+ import path from "node:path";
12
+
13
+ export async function forAllShapes(
14
+ shapePath: string,
15
+ callback: (filename: string, shape: string) => Promise<void>
16
+ ): Promise<void> {
17
+ const shapeDir = await fs.promises.readdir(shapePath, {
18
+ withFileTypes: true,
19
+ });
20
+ // Filter out non-shex documents
21
+ const shexFiles = shapeDir.filter(
22
+ (file) => file.isFile() && file.name.endsWith(".shex")
23
+ );
24
+ const shexPromise = Promise.all(
25
+ shexFiles.map(async (file) => {
26
+ const fileName = path.parse(file.name).name;
27
+ // Get the content of each document
28
+ const shexC = await fs.promises.readFile(
29
+ path.join(shapePath, file.name),
30
+ "utf8"
31
+ );
32
+ await callback(fileName, shexC);
33
+ })
34
+ );
35
+
36
+ // Note: SHACL conversion omitted here.
37
+
38
+ await Promise.all([shexPromise]);
39
+ }