@shaclmate/compiler 2.0.24 → 3.0.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.
Files changed (44) hide show
  1. package/dist/_ShapesGraphToAstTransformer/transformShapeToAstLiteralType.js +1 -1
  2. package/dist/generators/ts/BooleanType.d.ts +2 -1
  3. package/dist/generators/ts/BooleanType.js +9 -4
  4. package/dist/generators/ts/DateTimeType.d.ts +2 -1
  5. package/dist/generators/ts/DateTimeType.js +9 -4
  6. package/dist/generators/ts/IdentifierType.d.ts +1 -6
  7. package/dist/generators/ts/IdentifierType.js +1 -1
  8. package/dist/generators/ts/Import.d.ts +2 -1
  9. package/dist/generators/ts/Import.js +29 -24
  10. package/dist/generators/ts/ListType.js +2 -2
  11. package/dist/generators/ts/LiteralType.d.ts +3 -7
  12. package/dist/generators/ts/LiteralType.js +53 -51
  13. package/dist/generators/ts/NumberType.d.ts +2 -1
  14. package/dist/generators/ts/NumberType.js +9 -4
  15. package/dist/generators/ts/ObjectType.d.ts +2 -0
  16. package/dist/generators/ts/ObjectType.js +14 -3
  17. package/dist/generators/ts/ObjectUnionType.d.ts +1 -0
  18. package/dist/generators/ts/ObjectUnionType.js +7 -4
  19. package/dist/generators/ts/PrimitiveType.d.ts +1 -19
  20. package/dist/generators/ts/PrimitiveType.js +4 -14
  21. package/dist/generators/ts/SnippetDeclarations.d.ts +2 -1
  22. package/dist/generators/ts/SnippetDeclarations.js +28 -1
  23. package/dist/generators/ts/StringType.d.ts +2 -1
  24. package/dist/generators/ts/StringType.js +14 -7
  25. package/dist/generators/ts/TermType.d.ts +12 -1
  26. package/dist/generators/ts/TermType.js +11 -0
  27. package/dist/generators/ts/TsGenerator.js +24 -15
  28. package/dist/generators/ts/Type.d.ts +7 -8
  29. package/dist/generators/ts/Type.js +1 -1
  30. package/dist/generators/ts/TypeFactory.js +3 -2
  31. package/dist/generators/ts/_ObjectType/Property.d.ts +2 -2
  32. package/dist/generators/ts/_ObjectType/ShaclProperty.js +1 -1
  33. package/dist/generators/ts/_ObjectType/jsonFunctionDeclarations.js +1 -1
  34. package/dist/generators/ts/_ObjectType/rdfFunctionDeclarations.js +30 -11
  35. package/dist/generators/ts/_ObjectType/sparqlConstructQueryFunctionDeclaration.js +3 -3
  36. package/dist/generators/ts/_ObjectType/sparqlConstructQueryStringFunctionDeclaration.js +1 -1
  37. package/dist/generators/ts/_ObjectType/sparqlFunctionDeclarations.js +31 -15
  38. package/dist/generators/ts/forwardingObjectSetClassDeclaration.d.ts +8 -0
  39. package/dist/generators/ts/forwardingObjectSetClassDeclaration.js +29 -0
  40. package/dist/generators/ts/objectSetDeclarations.js +2 -0
  41. package/dist/generators/ts/rdfjsDatasetObjectSetClassDeclaration.js +21 -14
  42. package/dist/generators/ts/rdfjsTermExpression.js +3 -3
  43. package/dist/input/PropertyPath.d.ts +1 -1
  44. package/package.json +5 -8
@@ -28,19 +28,6 @@ export class PrimitiveType extends LiteralType {
28
28
  fromJsonExpression({ variables, }) {
29
29
  return variables.value;
30
30
  }
31
- fromRdfExpressionChain({ variables, }) {
32
- return {
33
- ...super.fromRdfExpressionChain({ variables }),
34
- languageIn: undefined,
35
- valueTo: `chain(values => values.chainMap(value => ${this.fromRdfResourceValueExpression({
36
- variables: {
37
- predicate: variables.predicate,
38
- resource: variables.resource,
39
- resourceValue: "value",
40
- },
41
- })}))`,
42
- };
43
- }
44
31
  graphqlResolveExpression({ variables, }) {
45
32
  return variables.value;
46
33
  }
@@ -55,7 +42,10 @@ export class PrimitiveType extends LiteralType {
55
42
  return snippetDeclarations;
56
43
  }
57
44
  sparqlWherePatterns(parameters) {
58
- return super.sparqlWherePatterns({ ...parameters, ignoreLanguageIn: true });
45
+ return super.sparqlWherePatterns({
46
+ ...parameters,
47
+ ignoreLiteralLanguage: parameters.ignoreLiteralLanguage ?? true,
48
+ });
59
49
  }
60
50
  toJsonExpression({ variables, }) {
61
51
  return variables.value;
@@ -1,5 +1,6 @@
1
1
  export declare namespace SnippetDeclarations {
2
2
  const arrayEquals = "/**\n * Compare two arrays element-wise with the provided elementEquals function.\n */ \nexport function $arrayEquals<T>(\n leftArray: readonly T[],\n rightArray: readonly T[],\n elementEquals: (left: T, right: T) => boolean | $EqualsResult,\n): $EqualsResult {\n if (leftArray.length !== rightArray.length) {\n return purify.Left({\n left: leftArray,\n right: rightArray,\n type: \"ArrayLength\",\n });\n }\n\n for (\n let leftElementIndex = 0;\n leftElementIndex < leftArray.length;\n leftElementIndex++\n ) {\n const leftElement = leftArray[leftElementIndex];\n\n const rightUnequals: $EqualsResult.Unequal[] = [];\n for (\n let rightElementIndex = 0;\n rightElementIndex < rightArray.length;\n rightElementIndex++\n ) {\n const rightElement = rightArray[rightElementIndex];\n\n const leftElementEqualsRightElement =\n $EqualsResult.fromBooleanEqualsResult(\n leftElement,\n rightElement,\n elementEquals(leftElement, rightElement),\n );\n if (leftElementEqualsRightElement.isRight()) {\n break; // left element === right element, break out of the right iteration\n }\n rightUnequals.push(\n leftElementEqualsRightElement.extract() as $EqualsResult.Unequal,\n );\n }\n\n if (rightUnequals.length === rightArray.length) {\n // All right elements were unequal to the left element\n return purify.Left({\n left: {\n array: leftArray,\n element: leftElement,\n elementIndex: leftElementIndex,\n },\n right: {\n array: rightArray,\n unequals: rightUnequals,\n },\n type: \"ArrayElement\",\n });\n }\n // Else there was a right element equal to the left element, continue to the next left element\n }\n\n return $EqualsResult.Equal;\n}\n";
3
+ const arrayIntersection = "export function $arrayIntersection<T>(left: readonly T[], right: readonly T[]): readonly T[] {\n if (left.length === 0) {\n return right;\n }\n if (right.length === 0) {\n return left;\n }\n\n const intersection = new Set<T>();\n if (left.length <= right.length) {\n const rightSet = new Set(right);\n for (const leftElement of left) {\n if (rightSet.has(leftElement)) {\n intersection.add(leftElement);\n }\n }\n } else {\n const leftSet = new Set(left);\n for (const rightElement of right) {\n if (leftSet.has(rightElement)) {\n intersection.add(rightElement);\n } \n }\n }\n return [...intersection];\n}";
3
4
  const booleanEquals = "/**\n * Compare two objects with equals(other: T): boolean methods and return an $EqualsResult.\n */\nexport function $booleanEquals<T extends { equals: (other: T) => boolean }>(\n left: T,\n right: T,\n): $EqualsResult {\n return $EqualsResult.fromBooleanEqualsResult(\n left,\n right,\n left.equals(right),\n );\n}";
4
5
  const dateEquals = "/**\n * Compare two Dates and return an $EqualsResult.\n */\nexport function $dateEquals(left: Date, right: Date): $EqualsResult {\n return $EqualsResult.fromBooleanEqualsResult(\n left,\n right,\n left.getTime() === right.getTime(),\n );\n}";
5
6
  const EqualsResult = "export type $EqualsResult = purify.Either<$EqualsResult.Unequal, true>;\n\nexport namespace $EqualsResult {\n export const Equal: $EqualsResult = purify.Either.of<Unequal, true>(true);\n\n export function fromBooleanEqualsResult(\n left: any,\n right: any,\n equalsResult: boolean | $EqualsResult,\n ): $EqualsResult {\n if (typeof equalsResult !== \"boolean\") {\n return equalsResult;\n }\n\n if (equalsResult) {\n return Equal;\n }\n\n return purify.Left({ left, right, type: \"BooleanEquals\" });\n }\n\n export type Unequal =\n | {\n readonly left: {\n readonly array: readonly any[];\n readonly element: any;\n readonly elementIndex: number;\n };\n readonly right: {\n readonly array: readonly any[];\n readonly unequals: readonly Unequal[];\n };\n readonly type: \"ArrayElement\";\n }\n | {\n readonly left: readonly any[];\n readonly right: readonly any[];\n readonly type: \"ArrayLength\";\n }\n | {\n readonly left: any;\n readonly right: any;\n readonly type: \"BooleanEquals\";\n }\n | {\n readonly left: any;\n readonly right: any;\n readonly type: \"LeftError\";\n }\n | {\n readonly right: any;\n readonly type: \"LeftNull\";\n }\n | {\n readonly left: bigint | boolean | number | string;\n readonly right: bigint | boolean | number | string;\n readonly type: \"Primitive\";\n }\n | {\n readonly left: any;\n readonly right: any;\n readonly propertyName: string;\n readonly propertyValuesUnequal: Unequal;\n readonly type: \"Property\";\n }\n | {\n readonly left: any;\n readonly right: any;\n readonly type: \"RightError\";\n }\n | {\n readonly left: any;\n readonly type: \"RightNull\";\n };\n} \n";
@@ -8,7 +9,7 @@ export declare namespace SnippetDeclarations {
8
9
  const LazyOptionalObject = "/**\n * Type of lazy properties that return a single optional object. This is a class instead of an interface so it can be instanceof'd elsewhere.\n */\nexport class $LazyOptionalObject<ObjectIdentifierT extends rdfjs.BlankNode | rdfjs.NamedNode, ResolvedObjectT extends { $identifier: ObjectIdentifierT }, StubObjectT extends { $identifier: ObjectIdentifierT }> {\n private readonly resolver: (identifier: ObjectIdentifierT) => Promise<purify.Either<Error, ResolvedObjectT>>;\n readonly stub: purify.Maybe<StubObjectT>;\n\n constructor({ resolver, stub }: {\n resolver: (identifier: ObjectIdentifierT) => Promise<purify.Either<Error, ResolvedObjectT>>,\n stub: purify.Maybe<StubObjectT>\n }) {\n this.resolver = resolver;\n this.stub = stub;\n }\n\n async resolve(): Promise<purify.Either<Error, purify.Maybe<ResolvedObjectT>>> {\n if (this.stub.isNothing()) {\n return purify.Either.of(purify.Maybe.empty());\n }\n return (await this.resolver(this.stub.unsafeCoerce().$identifier)).map(purify.Maybe.of);\n }\n}";
9
10
  const LazyRequiredObject = "/**\n * Type of lazy properties that return a single required object. This is a class instead of an interface so it can be instanceof'd elsewhere.\n */\nexport class $LazyRequiredObject<ObjectIdentifierT extends rdfjs.BlankNode | rdfjs.NamedNode, ResolvedObjectT extends { $identifier: ObjectIdentifierT }, StubObjectT extends { $identifier: ObjectIdentifierT }> {\n private readonly resolver: (identifier: ObjectIdentifierT) => Promise<purify.Either<Error, ResolvedObjectT>>;\n readonly stub: StubObjectT;\n\n constructor({ resolver, stub }: {\n resolver: (identifier: ObjectIdentifierT) => Promise<purify.Either<Error, ResolvedObjectT>>,\n stub: StubObjectT\n }) {\n this.resolver = resolver;\n this.stub = stub;\n }\n\n resolve(): Promise<purify.Either<Error, ResolvedObjectT>> {\n return this.resolver(this.stub.$identifier);\n }\n}";
10
11
  const RdfVocabularies = "export namespace $RdfVocabularies {\n export namespace rdf {\n export const first = dataFactory.namedNode(\"http://www.w3.org/1999/02/22-rdf-syntax-ns#first\");\n export const nil = dataFactory.namedNode(\"http://www.w3.org/1999/02/22-rdf-syntax-ns#nil\");\n export const rest = dataFactory.namedNode(\"http://www.w3.org/1999/02/22-rdf-syntax-ns#rest\");\n export const subject = dataFactory.namedNode(\"http://www.w3.org/1999/02/22-rdf-syntax-ns#subject\");\n export const type = dataFactory.namedNode(\"http://www.w3.org/1999/02/22-rdf-syntax-ns#type\");\n }\n\n export namespace rdfs {\n export const subClassOf = dataFactory.namedNode(\"http://www.w3.org/2000/01/rdf-schema#subClassOf\");\n }\n\n export namespace xsd {\n export const boolean = dataFactory.namedNode(\"http://www.w3.org/2001/XMLSchema#boolean\");\n export const date = dataFactory.namedNode(\"http://www.w3.org/2001/XMLSchema#date\");\n export const dateTime = dataFactory.namedNode(\"http://www.w3.org/2001/XMLSchema#dateTime\");\n export const integer = dataFactory.namedNode(\"http://www.w3.org/2001/XMLSchema#integer\");\n }\n}";
11
- const sparqlInstancesOfPattern = "/**\n * A sparqljs.Pattern that's the equivalent of ?subject rdf:type/rdfs:subClassOf* ?rdfType .\n */\nexport function $sparqlInstancesOfPattern({ rdfType, subject }: { rdfType: rdfjs.NamedNode, subject: sparqljs.Triple[\"subject\"] }): sparqljs.Pattern {\n return {\n triples: [\n {\n subject,\n predicate: {\n items: [\n $RdfVocabularies.rdf.type,\n {\n items: [$RdfVocabularies.rdfs.subClassOf],\n pathType: \"*\",\n type: \"path\",\n },\n ],\n pathType: \"/\",\n type: \"path\",\n },\n object: rdfType,\n },\n ],\n type: \"bgp\",\n };\n}";
12
+ const sparqlInstancesOfPattern = "/**\n * A sparqljs.Pattern that's the equivalent of ?subject rdf:type/rdfs:subClassOf* ?rdfType .\n */\nexport function $sparqlInstancesOfPattern({ rdfType, subject }: { rdfType: rdfjs.NamedNode | rdfjs.Variable, subject: sparqljs.Triple[\"subject\"] }): sparqljs.Pattern {\n return {\n triples: [\n {\n subject,\n predicate: {\n items: [\n $RdfVocabularies.rdf.type,\n {\n items: [$RdfVocabularies.rdfs.subClassOf],\n pathType: \"*\",\n type: \"path\",\n },\n ],\n pathType: \"/\",\n type: \"path\",\n },\n object: rdfType,\n },\n ],\n type: \"bgp\",\n };\n}";
12
13
  const strictEquals = "/**\n * Compare two values for strict equality (===), returning an $EqualsResult rather than a boolean.\n */\nexport function $strictEquals<T extends bigint | boolean | number | string>(\n left: T,\n right: T,\n): $EqualsResult {\n return $EqualsResult.fromBooleanEqualsResult(left, right, left === right);\n}";
13
14
  const UnwrapL = "type $UnwrapL<T> = T extends purify.Either<infer L, any> ? L : never";
14
15
  const UnwrapR = "type $UnwrapR<T> = T extends purify.Either<any, infer R> ? R : never";
@@ -68,6 +68,33 @@ export function ${syntheticNamePrefix}arrayEquals<T>(
68
68
  return ${syntheticNamePrefix}EqualsResult.Equal;
69
69
  }
70
70
  `;
71
+ SnippetDeclarations.arrayIntersection = `\
72
+ export function ${syntheticNamePrefix}arrayIntersection<T>(left: readonly T[], right: readonly T[]): readonly T[] {
73
+ if (left.length === 0) {
74
+ return right;
75
+ }
76
+ if (right.length === 0) {
77
+ return left;
78
+ }
79
+
80
+ const intersection = new Set<T>();
81
+ if (left.length <= right.length) {
82
+ const rightSet = new Set(right);
83
+ for (const leftElement of left) {
84
+ if (rightSet.has(leftElement)) {
85
+ intersection.add(leftElement);
86
+ }
87
+ }
88
+ } else {
89
+ const leftSet = new Set(left);
90
+ for (const rightElement of right) {
91
+ if (leftSet.has(rightElement)) {
92
+ intersection.add(rightElement);
93
+ }
94
+ }
95
+ }
96
+ return [...intersection];
97
+ }`;
71
98
  SnippetDeclarations.booleanEquals = `\
72
99
  /**
73
100
  * Compare two objects with equals(other: T): boolean methods and return an ${syntheticNamePrefix}EqualsResult.
@@ -301,7 +328,7 @@ export namespace ${syntheticNamePrefix}RdfVocabularies {
301
328
  /**
302
329
  * A sparqljs.Pattern that's the equivalent of ?subject rdf:type/rdfs:subClassOf* ?rdfType .
303
330
  */
304
- export function ${syntheticNamePrefix}sparqlInstancesOfPattern({ rdfType, subject }: { rdfType: rdfjs.NamedNode, subject: sparqljs.Triple["subject"] }): sparqljs.Pattern {
331
+ export function ${syntheticNamePrefix}sparqlInstancesOfPattern({ rdfType, subject }: { rdfType: rdfjs.NamedNode | rdfjs.Variable, subject: sparqljs.Triple["subject"] }): sparqljs.Pattern {
305
332
  return {
306
333
  triples: [
307
334
  {
@@ -6,9 +6,10 @@ export declare class StringType extends PrimitiveType<string> {
6
6
  get conversions(): readonly Type.Conversion[];
7
7
  get graphqlName(): Type.GraphqlName;
8
8
  get name(): string;
9
- protected fromRdfResourceValueExpression({ variables, }: Parameters<PrimitiveType<string>["fromRdfResourceValueExpression"]>[0]): string;
9
+ protected fromRdfExpressionChain({ variables, }: Parameters<PrimitiveType<string>["fromRdfExpressionChain"]>[0]): ReturnType<PrimitiveType<string>["fromRdfExpressionChain"]>;
10
10
  hashStatements({ variables, }: Parameters<Type["hashStatements"]>[0]): readonly string[];
11
11
  jsonZodSchema({ variables, }: Parameters<Type["jsonZodSchema"]>[0]): ReturnType<Type["jsonZodSchema"]>;
12
+ sparqlWherePatterns(parameters: Parameters<PrimitiveType<string>["sparqlWherePatterns"]>[0]): readonly string[];
12
13
  toRdfExpression({ variables, }: Parameters<PrimitiveType<string>["toRdfExpression"]>[0]): string;
13
14
  }
14
15
  //# sourceMappingURL=StringType.d.ts.map
@@ -37,13 +37,14 @@ export class StringType extends PrimitiveType {
37
37
  }
38
38
  return this.typeof;
39
39
  }
40
- fromRdfResourceValueExpression({ variables, }) {
41
- let expression = `${variables.resourceValue}.toString()`;
42
- if (this.primitiveIn.length > 0) {
43
- const eitherTypeParameters = `<Error, ${this.name}>`;
44
- expression = `${expression}.chain(value => { switch (value) { ${this.primitiveIn.map((value) => `case "${value}":`).join(" ")} return purify.Either.of${eitherTypeParameters}(value); default: return purify.Left${eitherTypeParameters}(new rdfjsResource.Resource.MistypedValueError(${objectInitializer({ actualValue: "rdfLiteral.toRdf(value)", expectedValueType: JSON.stringify(this.name), focusResource: variables.resource, predicate: variables.predicate })})); } })`;
45
- }
46
- return expression;
40
+ fromRdfExpressionChain({ variables, }) {
41
+ const inChain = this.primitiveIn.length > 0
42
+ ? `.chain(string_ => { switch (string_) { ${this.primitiveIn.map((value) => `case "${value}":`).join(" ")} return purify.Either.of<Error, ${this.name}>(string_); default: return purify.Left<Error, ${this.name}>(new rdfjsResource.Resource.MistypedValueError(${objectInitializer({ actualValue: "value.toTerm()", expectedValueType: JSON.stringify(this.name), focusResource: variables.resource, predicate: variables.predicate })})); } })`
43
+ : "";
44
+ return {
45
+ ...super.fromRdfExpressionChain({ variables }),
46
+ valueTo: `chain(values => values.chainMap(value => value.toString()${inChain}))`,
47
+ };
47
48
  }
48
49
  hashStatements({ variables, }) {
49
50
  return [`${variables.hasher}.update(${variables.value});`];
@@ -58,6 +59,12 @@ export class StringType extends PrimitiveType {
58
59
  return `${variables.zod}.enum(${JSON.stringify(this.primitiveIn)})`;
59
60
  }
60
61
  }
62
+ sparqlWherePatterns(parameters) {
63
+ return super.sparqlWherePatterns({
64
+ ...parameters,
65
+ ignoreLiteralLanguage: false,
66
+ });
67
+ }
61
68
  toRdfExpression({ variables, }) {
62
69
  return this.primitiveDefaultValue
63
70
  .map((defaultValue) => `${variables.value} !== "${defaultValue}" ? ${variables.value} : undefined`)
@@ -31,11 +31,22 @@ export declare class TermType<ConstantTermT extends Literal | NamedNode = Litera
31
31
  get name(): string;
32
32
  fromJsonExpression({ variables, }: Parameters<Type["fromJsonExpression"]>[0]): string;
33
33
  fromRdfExpression(parameters: Parameters<Type["fromRdfExpression"]>[0]): string;
34
+ /**
35
+ * The fromRdfExpression for a term type can be decomposed into multiple sub-expressions with different purposes:
36
+ *
37
+ * defaultValues: add the default value to the values sequence if the latter doesn't contain values already
38
+ * hasValues: test whether the values sequence has sh:hasValue values
39
+ * languageIn: filter the values sequence to literals with the right sh:languageIn (or runtime languageIn)
40
+ * valueTo: convert values in the values sequence to the appropriate term type/sub-type (literal, string, etc.)
41
+ *
42
+ * Considering the sub-expressions as a record instead of an array allows them to be selectively overridden by subclasses.
43
+ */
34
44
  protected fromRdfExpressionChain({ variables, }: Parameters<Type["fromRdfExpression"]>[0]): {
35
45
  defaultValue?: string;
36
46
  hasValues?: string;
37
47
  languageIn?: string;
38
- valueTo?: string;
48
+ preferredLanguages?: string;
49
+ valueTo: string;
39
50
  };
40
51
  graphqlResolveExpression(_parameters: Parameters<Type["graphqlResolveExpression"]>[0]): string;
41
52
  hashStatements({ variables, }: Parameters<Type["hashStatements"]>[0]): readonly string[];
@@ -133,11 +133,22 @@ export class TermType extends Type {
133
133
  chain.defaultValue,
134
134
  chain.hasValues,
135
135
  chain.languageIn,
136
+ chain.preferredLanguages,
136
137
  chain.valueTo,
137
138
  ]
138
139
  .filter((_) => typeof _ !== "undefined")
139
140
  .join(".");
140
141
  }
142
+ /**
143
+ * The fromRdfExpression for a term type can be decomposed into multiple sub-expressions with different purposes:
144
+ *
145
+ * defaultValues: add the default value to the values sequence if the latter doesn't contain values already
146
+ * hasValues: test whether the values sequence has sh:hasValue values
147
+ * languageIn: filter the values sequence to literals with the right sh:languageIn (or runtime languageIn)
148
+ * valueTo: convert values in the values sequence to the appropriate term type/sub-type (literal, string, etc.)
149
+ *
150
+ * Considering the sub-expressions as a record instead of an array allows them to be selectively overridden by subclasses.
151
+ */
141
152
  fromRdfExpressionChain({ variables, }) {
142
153
  let valueToExpression = "purify.Either.of<Error, rdfjs.BlankNode | rdfjs.Literal | rdfjs.NamedNode>(value.toTerm())";
143
154
  if (this.nodeKinds.size < 3) {
@@ -1,5 +1,7 @@
1
+ import { invariant } from "ts-invariant";
1
2
  import { Project, } from "ts-morph";
2
3
  import * as ast from "../../ast/index.js";
4
+ import { Import } from "./Import.js";
3
5
  import { ObjectType } from "./ObjectType.js";
4
6
  import { ObjectUnionType } from "./ObjectUnionType.js";
5
7
  import { TypeFactory } from "./TypeFactory.js";
@@ -27,36 +29,43 @@ export class TsGenerator {
27
29
  return project.getFileSystem().readFileSync(sourceFile.getFilePath());
28
30
  }
29
31
  addStatements({ objectTypes, objectUnionTypes, sourceFile, }) {
30
- // sourceFile.addStatements(this.configuration.dataFactoryImport);
31
- sourceFile.addStatements([
32
- 'import { DataFactory as dataFactory, StoreFactory as _DatasetFactory } from "n3";',
33
- "const datasetFactory: rdfjs.DatasetCoreFactory = new _DatasetFactory();",
34
- ]);
35
32
  const declaredTypes = [
36
33
  ...objectTypes,
37
34
  ...objectUnionTypes,
38
35
  ];
39
36
  // Gather imports
40
- const imports = [];
37
+ const imports = [Import.DATA_FACTORY, Import.DATASET_FACTORY];
41
38
  for (const declaredType of declaredTypes) {
42
39
  imports.push(...declaredType.declarationImports);
43
40
  }
44
41
  // Deduplicate and add imports
45
- const addedStringImports = new Set();
46
- const addedStructureImports = [];
42
+ const stringImports = new Set();
43
+ const structureImports = [];
47
44
  for (const import_ of imports) {
48
45
  if (typeof import_ === "string") {
49
- if (!addedStringImports.has(import_)) {
50
- sourceFile.addStatements([import_]);
51
- }
52
- addedStringImports.add(import_);
46
+ stringImports.add(import_);
47
+ continue;
48
+ }
49
+ const importWithSameModuleSpecifier = structureImports.find((structureImport) => structureImport.moduleSpecifier === import_.moduleSpecifier);
50
+ if (!importWithSameModuleSpecifier) {
51
+ structureImports.push(import_);
53
52
  continue;
54
53
  }
55
- if (!addedStructureImports.find((addedStructureImport) => addedStructureImport.moduleSpecifier === import_.moduleSpecifier)) {
56
- sourceFile.addStatements([import_]);
57
- addedStructureImports.push(import_);
54
+ // Merge named imports
55
+ invariant(!import_.namespaceImport);
56
+ invariant(Array.isArray(import_.namedImports) &&
57
+ import_.namedImports.every((value) => typeof value === "string"));
58
+ invariant(!importWithSameModuleSpecifier.namespaceImport);
59
+ invariant(Array.isArray(importWithSameModuleSpecifier.namedImports) &&
60
+ importWithSameModuleSpecifier.namedImports.every((value) => typeof value === "string"));
61
+ for (const newNamedImport of import_.namedImports) {
62
+ if (!importWithSameModuleSpecifier.namedImports.includes(newNamedImport)) {
63
+ importWithSameModuleSpecifier.namedImports.push(newNamedImport);
64
+ }
58
65
  }
59
66
  }
67
+ sourceFile.addStatements([...stringImports]);
68
+ sourceFile.addStatements(structureImports);
60
69
  // Deduplicate and add snippet declarations
61
70
  const addedSnippetDeclarations = new Set();
62
71
  for (const declaredType of declaredTypes) {
@@ -50,22 +50,21 @@ export declare abstract class Type {
50
50
  };
51
51
  }): string;
52
52
  /**
53
- * An expression that converts a purify.Either<Error, rdfjsResource.Resource.Values<rdfjsResource.Resource.Value>> to
54
- * (1) a purify.Either<Error, rdfjsResource.Resource.Values<this type>> if this is an item type (identifier, object, et al.) or
55
- * (2) a purify.Either<Error, cardinality type> if this is a cardinality type
53
+ * An expression that converts a purify.Either<Error, rdfjsResource.Resource.Values<rdfjsResource.Resource.Value>> to a
54
+ * purify.Either<Error, rdfjsResource.Resource.Values<this type>>.
56
55
  *
57
56
  * Some types need to filter on the set of all objects/values of a (subject, predicate). For example, all sh:hasValue values must be present in the set for any values
58
57
  * to be considered valid. Similar
59
58
  *
60
- * Values may also need to be sorted. For example, applying sh:languageIn should sort the values in the order of the specified languages so that the first value
61
- * (if it exists) is always of the first specified language -- a common situation when sh:maxCount is 1.
59
+ * Values may also need to be sorted. For example, specifying preferredLanguages should sort the values in the order of the specified languages so that the first value
60
+ * (if it exists) is always of the first preferred language.
62
61
  */
63
62
  abstract fromRdfExpression(parameters: {
64
63
  variables: {
65
64
  context: string;
66
65
  ignoreRdfType?: boolean;
67
- languageIn: string;
68
66
  objectSet: string;
67
+ preferredLanguages: string;
69
68
  predicate: string;
70
69
  resource: string;
71
70
  resourceValues: string;
@@ -160,9 +159,9 @@ export declare abstract class Type {
160
159
  allowIgnoreRdfType: boolean;
161
160
  context: "object";
162
161
  variables: {
163
- languageIn: string;
164
162
  object: string;
165
163
  predicate: string;
164
+ preferredLanguages: string;
166
165
  subject: string;
167
166
  variablePrefix: string;
168
167
  };
@@ -170,7 +169,7 @@ export declare abstract class Type {
170
169
  allowIgnoreRdfType: boolean;
171
170
  context: "subject";
172
171
  variables: {
173
- languageIn: string;
172
+ preferredLanguages: string;
174
173
  subject: string;
175
174
  variablePrefix: string;
176
175
  };
@@ -66,7 +66,7 @@ export class Type {
66
66
  allowIgnoreRdfType,
67
67
  context: "subject",
68
68
  variables: {
69
- languageIn: variables.languageIn,
69
+ preferredLanguages: variables.preferredLanguages,
70
70
  subject: variables.object,
71
71
  variablePrefix: variables.object.substring(objectPrefix.length, variables.object.length - objectSuffix.length),
72
72
  },
@@ -332,13 +332,14 @@ export class TypeFactory {
332
332
  if (datatype.equals(xsd.anyURI) || datatype.equals(xsd.string)) {
333
333
  if (astType.defaultValue.isNothing() &&
334
334
  astType.hasValues.length === 0 &&
335
- astType.in_.length === 0) {
335
+ astType.in_.length === 0 &&
336
+ astType.languageIn.length === 0) {
336
337
  return this.cachedStringType;
337
338
  }
338
339
  return new StringType({
339
340
  defaultValue: astType.defaultValue,
340
341
  hasValues: astType.hasValues,
341
- languageIn: [],
342
+ languageIn: astType.languageIn,
342
343
  in_: astType.in_,
343
344
  primitiveDefaultValue: astType.defaultValue.map((value) => value.value),
344
345
  primitiveIn: astType.in_.map((value) => value.value),
@@ -96,8 +96,8 @@ export declare abstract class Property<TypeT extends Pick<Type, "mutable" | "nam
96
96
  abstract fromRdfStatements(parameters: {
97
97
  variables: {
98
98
  context: string;
99
- languageIn: string;
100
99
  objectSet: string;
100
+ preferredLanguages: string;
101
101
  resource: string;
102
102
  };
103
103
  }): readonly string[];
@@ -147,7 +147,7 @@ export declare abstract class Property<TypeT extends Pick<Type, "mutable" | "nam
147
147
  */
148
148
  abstract sparqlWherePatterns(parameters: {
149
149
  variables: {
150
- languageIn: string;
150
+ preferredLanguages: string;
151
151
  subject: string;
152
152
  variablePrefix: string;
153
153
  };
@@ -170,9 +170,9 @@ export class ShaclProperty extends Property {
170
170
  allowIgnoreRdfType: true,
171
171
  context: "object",
172
172
  variables: {
173
- languageIn: variables.languageIn,
174
173
  object: `dataFactory.variable!(${objectString})`,
175
174
  predicate: this.predicate,
175
+ preferredLanguages: variables.preferredLanguages,
176
176
  subject: variables.subject,
177
177
  variablePrefix: objectString,
178
178
  },
@@ -100,7 +100,7 @@ function jsonSchemaFunctionDeclaration() {
100
100
  kind: StructureKind.Function,
101
101
  name: `${syntheticNamePrefix}jsonSchema`,
102
102
  statements: [
103
- `return zodToJsonSchema(${syntheticNamePrefix}jsonZodSchema());`,
103
+ `return zod.toJSONSchema(${syntheticNamePrefix}jsonZodSchema());`,
104
104
  ],
105
105
  };
106
106
  }
@@ -7,7 +7,7 @@ import { syntheticNamePrefix } from "../syntheticNamePrefix.js";
7
7
  import { toRdfFunctionOrMethodDeclaration } from "./toRdfFunctionOrMethodDeclaration.js";
8
8
  function fromRdfFunctionDeclaration() {
9
9
  const statements = [];
10
- statements.push("let { ignoreRdfType = false, languageIn, objectSet, ...context } = (options ?? {});", `if (!objectSet) { objectSet = new ${syntheticNamePrefix}RdfjsDatasetObjectSet({ dataset: resource.dataset }); }`);
10
+ statements.push("let { ignoreRdfType = false, objectSet, preferredLanguages, ...context } = (options ?? {});", `if (!objectSet) { objectSet = new ${syntheticNamePrefix}RdfjsDatasetObjectSet({ dataset: resource.dataset }); }`);
11
11
  let returnExpression;
12
12
  if (this.childObjectTypes.length > 0) {
13
13
  // Can't ignore the RDF type.
@@ -20,7 +20,7 @@ function fromRdfFunctionDeclaration() {
20
20
  }, "");
21
21
  }
22
22
  if (!this.abstract) {
23
- let propertiesFromRdfExpression = `${this.staticModuleName}.${syntheticNamePrefix}propertiesFromRdf({ ...context, ignoreRdfType, languageIn, objectSet, resource })`;
23
+ let propertiesFromRdfExpression = `${this.staticModuleName}.${syntheticNamePrefix}propertiesFromRdf({ ...context, ignoreRdfType, objectSet, preferredLanguages, resource })`;
24
24
  if (this.declarationType === "class") {
25
25
  propertiesFromRdfExpression = `${propertiesFromRdfExpression}.map(properties => new ${this.name}(properties))`;
26
26
  }
@@ -51,7 +51,7 @@ function fromRdfFunctionDeclaration() {
51
51
  {
52
52
  hasQuestionToken: true,
53
53
  name: "options",
54
- type: `{ [_index: string]: any; ignoreRdfType?: boolean; languageIn?: readonly string[]; objectSet?: ${syntheticNamePrefix}ObjectSet; }`,
54
+ type: `{ [_index: string]: any; ignoreRdfType?: boolean; objectSet?: ${syntheticNamePrefix}ObjectSet; preferredLanguages?: readonly string[]; }`,
55
55
  },
56
56
  ],
57
57
  returnType: `purify.Either<Error, ${this.name}>`,
@@ -64,20 +64,39 @@ function propertiesFromRdfFunctionDeclaration() {
64
64
  const returnType = [];
65
65
  const statements = [];
66
66
  this.parentObjectTypes.forEach((parentObjectType, parentObjectTypeI) => {
67
- statements.push(`const ${syntheticNamePrefix}super${parentObjectTypeI}Either = ${parentObjectType.staticModuleName}.${syntheticNamePrefix}propertiesFromRdf({ ...${variables.context}, ignoreRdfType: true, languageIn: ${variables.languageIn}, objectSet: ${variables.objectSet}, resource: ${variables.resource} });`, `if (${syntheticNamePrefix}super${parentObjectTypeI}Either.isLeft()) { return ${syntheticNamePrefix}super${parentObjectTypeI}Either; }`, `const ${syntheticNamePrefix}super${parentObjectTypeI} = ${syntheticNamePrefix}super${parentObjectTypeI}Either.unsafeCoerce()`);
67
+ statements.push(`const ${syntheticNamePrefix}super${parentObjectTypeI}Either = ${parentObjectType.staticModuleName}.${syntheticNamePrefix}propertiesFromRdf({ ...${variables.context}, ignoreRdfType: true, objectSet: ${variables.objectSet}, preferredLanguages: ${variables.preferredLanguages}, resource: ${variables.resource} });`, `if (${syntheticNamePrefix}super${parentObjectTypeI}Either.isLeft()) { return ${syntheticNamePrefix}super${parentObjectTypeI}Either; }`, `const ${syntheticNamePrefix}super${parentObjectTypeI} = ${syntheticNamePrefix}super${parentObjectTypeI}Either.unsafeCoerce()`);
68
68
  initializers.push(`...${syntheticNamePrefix}super${parentObjectTypeI}`);
69
69
  returnType.push(`${syntheticNamePrefix}UnwrapR<ReturnType<typeof ${parentObjectType.staticModuleName}.${syntheticNamePrefix}propertiesFromRdf>>`);
70
70
  });
71
- this.fromRdfType.ifJust((rdfType) => {
71
+ this.fromRdfType.ifJust((fromRdfType) => {
72
+ const fromRdfTypeVariable = this.fromRdfTypeVariable.unsafeCoerce();
72
73
  const predicate = rdfjsTermExpression(rdf.type);
73
74
  statements.push(`\
74
- if (!${variables.ignoreRdfType} && !${variables.resource}.isInstanceOf(${syntheticNamePrefix}fromRdfType)) {
75
- return ${variables.resource}.value(${predicate}).chain(actualRdfType => actualRdfType.toIri()).chain((actualRdfType) => purify.Left(new Error(\`\${rdfjsResource.Resource.Identifier.toString(${variables.resource}.identifier)} has unexpected RDF type (actual: \${actualRdfType.value}, expected: ${rdfType.value})\`)));
75
+ if (!${variables.ignoreRdfType}) {
76
+ const ${syntheticNamePrefix}rdfTypeCheck: purify.Either<Error, true> = ${variables.resource}.value(${predicate})
77
+ .chain(actualRdfType => actualRdfType.toIri())
78
+ .chain((actualRdfType) => {
79
+ // Check the expected type and its known subtypes
80
+ switch (actualRdfType.value) {
81
+ ${[`case "${fromRdfType.value}":`].concat(this.descendantFromRdfTypes.map((descendantFromRdfType) => `case "${descendantFromRdfType.value}":`)).join("\n")}
82
+ return purify.Either.of(true);
83
+ }
84
+
85
+ // Check arbitrary rdfs:subClassOf's of the expected type
86
+ if (${variables.resource}.isInstanceOf(${fromRdfTypeVariable})) {
87
+ return purify.Either.of(true);
88
+ }
89
+
90
+ return purify.Left(new Error(\`\${rdfjsResource.Resource.Identifier.toString(${variables.resource}.identifier)} has unexpected RDF type (actual: \${actualRdfType.value}, expected: ${fromRdfType.value})\`));
91
+ });
92
+ if (${syntheticNamePrefix}rdfTypeCheck.isLeft()) {
93
+ return ${syntheticNamePrefix}rdfTypeCheck;
94
+ }
76
95
  }`);
77
96
  });
78
97
  const propertyFromRdfVariables = {
79
98
  context: variables.context,
80
- languageIn: variables.languageIn,
99
+ preferredLanguages: variables.preferredLanguages,
81
100
  objectSet: variables.objectSet,
82
101
  resource: variables.resource,
83
102
  };
@@ -101,8 +120,8 @@ if (!${variables.ignoreRdfType} && !${variables.resource}.isInstanceOf(${synthet
101
120
  name: `${syntheticNamePrefix}propertiesFromRdf`,
102
121
  parameters: [
103
122
  {
104
- name: `{ ignoreRdfType: ${variables.ignoreRdfType}, languageIn: ${variables.languageIn}, objectSet: ${variables.objectSet}, resource: ${variables.resource},\n// @ts-ignore\n...${variables.context} }`,
105
- type: `{ [_index: string]: any; ignoreRdfType: boolean; languageIn?: readonly string[]; objectSet: ${syntheticNamePrefix}ObjectSet; resource: rdfjsResource.Resource; }`,
123
+ name: `{ ignoreRdfType: ${variables.ignoreRdfType}, objectSet: ${variables.objectSet}, preferredLanguages: ${variables.preferredLanguages}, resource: ${variables.resource},\n// @ts-ignore\n...${variables.context} }`,
124
+ type: `{ [_index: string]: any; ignoreRdfType: boolean; objectSet: ${syntheticNamePrefix}ObjectSet; preferredLanguages?: readonly string[]; resource: rdfjsResource.Resource; }`,
106
125
  },
107
126
  ],
108
127
  returnType: `purify.Either<Error, ${returnType.join(" & ")}>`,
@@ -137,8 +156,8 @@ function toRdfFunctionDeclaration() {
137
156
  const variables = {
138
157
  context: `${syntheticNamePrefix}context`,
139
158
  ignoreRdfType: `${syntheticNamePrefix}ignoreRdfType`,
140
- languageIn: `${syntheticNamePrefix}languageIn`,
141
159
  objectSet: `${syntheticNamePrefix}objectSet`,
160
+ preferredLanguages: `${syntheticNamePrefix}preferredLanguages`,
142
161
  resource: `${syntheticNamePrefix}resource`,
143
162
  };
144
163
  //# sourceMappingURL=rdfFunctionDeclarations.js.map
@@ -9,13 +9,13 @@ export function sparqlConstructQueryFunctionDeclaration() {
9
9
  {
10
10
  hasQuestionToken: true,
11
11
  name: "parameters",
12
- type: '{ ignoreRdfType?: boolean; languageIn?: readonly string[]; prefixes?: { [prefix: string]: string }; subject?: sparqljs.Triple["subject"]; } & Omit<sparqljs.ConstructQuery, "prefixes" | "queryType" | "type">',
12
+ type: '{ ignoreRdfType?: boolean; prefixes?: { [prefix: string]: string }; preferredLanguages?: readonly string[]; subject?: sparqljs.Triple["subject"]; } & Omit<sparqljs.ConstructQuery, "prefixes" | "queryType" | "type">',
13
13
  },
14
14
  ],
15
15
  returnType: "sparqljs.ConstructQuery",
16
16
  statements: [
17
- "const { ignoreRdfType, languageIn, subject, ...queryParameters } = parameters ?? {}",
18
- `return { ...queryParameters, prefixes: parameters?.prefixes ?? {}, queryType: "CONSTRUCT", template: (queryParameters.template ?? []).concat(${this.staticModuleName}.${syntheticNamePrefix}sparqlConstructTemplateTriples({ ignoreRdfType, subject })), type: "query", where: (queryParameters.where ?? []).concat(${this.staticModuleName}.${syntheticNamePrefix}sparqlWherePatterns({ ignoreRdfType, languageIn, subject })) };`,
17
+ "const { ignoreRdfType, preferredLanguages, subject, ...queryParameters } = parameters ?? {}",
18
+ `return { ...queryParameters, prefixes: parameters?.prefixes ?? {}, queryType: "CONSTRUCT", template: (queryParameters.template ?? []).concat(${this.staticModuleName}.${syntheticNamePrefix}sparqlConstructTemplateTriples({ ignoreRdfType, subject })), type: "query", where: (queryParameters.where ?? []).concat(${this.staticModuleName}.${syntheticNamePrefix}sparqlWherePatterns({ ignoreRdfType, preferredLanguages, subject })) };`,
19
19
  ],
20
20
  };
21
21
  }
@@ -9,7 +9,7 @@ export function sparqlConstructQueryStringFunctionDeclaration() {
9
9
  {
10
10
  hasQuestionToken: true,
11
11
  name: "parameters",
12
- type: '{ ignoreRdfType?: boolean; languageIn?: readonly string[]; subject?: sparqljs.Triple["subject"]; variablePrefix?: string; } & Omit<sparqljs.ConstructQuery, "prefixes" | "queryType" | "type"> & sparqljs.GeneratorOptions',
12
+ type: '{ ignoreRdfType?: boolean; preferredLanguages?: readonly string[]; subject?: sparqljs.Triple["subject"]; variablePrefix?: string; } & Omit<sparqljs.ConstructQuery, "prefixes" | "queryType" | "type"> & sparqljs.GeneratorOptions',
13
13
  },
14
14
  ],
15
15
  returnType: "string",
@@ -13,7 +13,7 @@ export function sparqlFunctionDeclarations() {
13
13
  return [];
14
14
  }
15
15
  const variables = {
16
- languageIn: "parameters?.languageIn",
16
+ preferredLanguages: "parameters?.preferredLanguages",
17
17
  subject: "subject",
18
18
  variablePrefix: "variablePrefix",
19
19
  };
@@ -45,6 +45,9 @@ for (const pattern of ${parentObjectType.staticModuleName}.${syntheticNamePrefix
45
45
  nop = false;
46
46
  }
47
47
  if (this.fromRdfType.isJust()) {
48
+ const fromRdfTypeVariables = this.fromRdfTypeVariable
49
+ .toList()
50
+ .concat(this.descendantFromRdfTypeVariables);
48
51
  sparqlConstructTemplateTriplesStatements.push(`\
49
52
  if (!parameters?.ignoreRdfType) {
50
53
  triples.push(
@@ -52,25 +55,38 @@ if (!parameters?.ignoreRdfType) {
52
55
  { subject: ${rdfTypeVariable}, predicate: ${rdfjsTermExpression(rdfs.subClassOf)}, object: ${rdfClassVariable} }
53
56
  );
54
57
  }`);
55
- sparqlWherePatternsStatements.push(`\
58
+ sparqlWherePatternsStatements.push(`const rdfTypeVariable = ${rdfTypeVariable};`, `\
56
59
  if (!parameters?.ignoreRdfType) {
57
- requiredPatterns.push(${syntheticNamePrefix}sparqlInstancesOfPattern({ rdfType: ${syntheticNamePrefix}fromRdfType, subject }));
58
- requiredPatterns.push({
59
- triples: [
60
- {
61
- subject,
62
- predicate: ${rdfjsTermExpression(rdf.type)},
63
- object: ${rdfTypeVariable}
64
- }
65
- ],
66
- type: "bgp" as const
67
- });
60
+ requiredPatterns.push(
61
+ ${fromRdfTypeVariables.length > 1
62
+ ? `\
63
+ {
64
+ type: "values" as const,
65
+ values: [${fromRdfTypeVariables.join(", ")}].map((identifier) => {
66
+ const valuePatternRow: sparqljs.ValuePatternRow = {};
67
+ valuePatternRow[\`?\${${variables.variablePrefix}}FromRdfType\`] = identifier as rdfjs.NamedNode;
68
+ return valuePatternRow;
69
+ }),
70
+ },
71
+ ${syntheticNamePrefix}sparqlInstancesOfPattern({ rdfType: dataFactory.variable!(\`\${${variables.variablePrefix}}FromRdfType\`), subject }),`
72
+ : `${syntheticNamePrefix}sparqlInstancesOfPattern({ rdfType: ${fromRdfTypeVariables[0]}, subject }),`}
73
+ {
74
+ triples: [
75
+ {
76
+ subject,
77
+ predicate: ${rdfjsTermExpression(rdf.type)},
78
+ object: rdfTypeVariable
79
+ }
80
+ ],
81
+ type: "bgp" as const
82
+ }
83
+ );
68
84
  optionalPatterns.push({
69
85
  patterns: [
70
86
  {
71
87
  triples: [
72
88
  {
73
- subject: ${rdfTypeVariable},
89
+ subject: rdfTypeVariable,
74
90
  predicate: {
75
91
  items: [${rdfjsTermExpression(rdfs.subClassOf)}],
76
92
  pathType: "+" as const,
@@ -139,7 +155,7 @@ for (const pattern of propertyPatterns) {
139
155
  {
140
156
  hasQuestionToken: true,
141
157
  name: `${nop ? "_" : ""}parameters`,
142
- type: '{ ignoreRdfType?: boolean; languageIn?: readonly string[]; subject?: sparqljs.Triple["subject"], variablePrefix?: string }',
158
+ type: '{ ignoreRdfType?: boolean; preferredLanguages?: readonly string[]; subject?: sparqljs.Triple["subject"], variablePrefix?: string }',
143
159
  },
144
160
  ],
145
161
  returnType: "readonly sparqljs.Pattern[]",
@@ -0,0 +1,8 @@
1
+ import { type ClassDeclarationStructure } from "ts-morph";
2
+ import type { ObjectType } from "./ObjectType.js";
3
+ import type { ObjectUnionType } from "./ObjectUnionType.js";
4
+ export declare function forwardingObjectSetClassDeclaration({ objectTypes, objectUnionTypes, }: {
5
+ objectTypes: readonly ObjectType[];
6
+ objectUnionTypes: readonly ObjectUnionType[];
7
+ }): ClassDeclarationStructure;
8
+ //# sourceMappingURL=forwardingObjectSetClassDeclaration.d.ts.map