@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.
- package/README.md +240 -0
- package/dist/ShexJTypes.d.ts +542 -0
- package/dist/ShexJTypes.d.ts.map +1 -0
- package/dist/ShexJTypes.js +10 -0
- package/dist/build.d.ts +8 -0
- package/dist/build.d.ts.map +1 -0
- package/dist/build.js +72 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +15 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1 -0
- package/dist/schema-converter/__tests__/typingTransformer.test.d.ts +2 -0
- package/dist/schema-converter/__tests__/typingTransformer.test.d.ts.map +1 -0
- package/dist/schema-converter/__tests__/typingTransformer.test.js +76 -0
- package/dist/schema-converter/converter.d.ts +12 -0
- package/dist/schema-converter/converter.d.ts.map +1 -0
- package/dist/schema-converter/converter.js +79 -0
- package/dist/schema-converter/templates/schema.ejs +8 -0
- package/dist/schema-converter/templates/shapeTypes.ejs +14 -0
- package/dist/schema-converter/templates/typings.ejs +14 -0
- package/dist/schema-converter/transformers/ShexJSchemaTransformer.d.ts +348 -0
- package/dist/schema-converter/transformers/ShexJSchemaTransformer.d.ts.map +1 -0
- package/dist/schema-converter/transformers/ShexJSchemaTransformer.js +239 -0
- package/dist/schema-converter/transformers/ShexJTypingTransformer.d.ts +366 -0
- package/dist/schema-converter/transformers/ShexJTypingTransformer.d.ts.map +1 -0
- package/dist/schema-converter/transformers/ShexJTypingTransformer.js +623 -0
- package/dist/schema-converter/util/ShapeInterfaceDeclaration.d.ts +5 -0
- package/dist/schema-converter/util/ShapeInterfaceDeclaration.d.ts.map +1 -0
- package/dist/schema-converter/util/ShapeInterfaceDeclaration.js +1 -0
- package/dist/schema-converter/util/annotateReadablePredicates.d.ts +8 -0
- package/dist/schema-converter/util/annotateReadablePredicates.d.ts.map +1 -0
- package/dist/schema-converter/util/annotateReadablePredicates.js +148 -0
- package/dist/schema-converter/util/dedupeObjectTypeMembers.d.ts +3 -0
- package/dist/schema-converter/util/dedupeObjectTypeMembers.d.ts.map +1 -0
- package/dist/schema-converter/util/dedupeObjectTypeMembers.js +47 -0
- package/dist/schema-converter/util/getRdfTypesForTripleConstraint.d.ts +4 -0
- package/dist/schema-converter/util/getRdfTypesForTripleConstraint.d.ts.map +1 -0
- package/dist/schema-converter/util/getRdfTypesForTripleConstraint.js +98 -0
- package/dist/types.d.ts +37 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +10 -0
- package/dist/util/forAllShapes.d.ts +2 -0
- package/dist/util/forAllShapes.d.ts.map +1 -0
- package/dist/util/forAllShapes.js +25 -0
- package/package.json +67 -0
- package/src/ShexJTypes.ts +616 -0
- package/src/build.ts +106 -0
- package/src/cli.ts +23 -0
- package/src/index.ts +1 -0
- package/src/schema-converter/__tests__/typingTransformer.test.ts +85 -0
- package/src/schema-converter/converter.ts +128 -0
- package/src/schema-converter/templates/schema.ejs +8 -0
- package/src/schema-converter/templates/shapeTypes.ejs +14 -0
- package/src/schema-converter/templates/typings.ejs +14 -0
- package/src/schema-converter/transformers/ShexJSchemaTransformer.ts +284 -0
- package/src/schema-converter/transformers/ShexJTypingTransformer.ts +807 -0
- package/src/schema-converter/util/ShapeInterfaceDeclaration.ts +5 -0
- package/src/schema-converter/util/annotateReadablePredicates.ts +173 -0
- package/src/schema-converter/util/dedupeObjectTypeMembers.ts +61 -0
- package/src/schema-converter/util/getRdfTypesForTripleConstraint.ts +153 -0
- package/src/types.ts +51 -0
- package/src/util/forAllShapes.ts +39 -0
|
@@ -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
|
+
}
|