@shaclmate/compiler 2.0.14 → 2.0.15

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 (50) hide show
  1. package/_ShapesGraphToAstTransformer/transformNodeShapeToAstType.js +17 -4
  2. package/_ShapesGraphToAstTransformer/transformPropertyShapeToAstCompositeType.js +3 -1
  3. package/generators/ts/DateTimeType.d.ts +3 -1
  4. package/generators/ts/DateTimeType.js +9 -1
  5. package/generators/ts/Import.d.ts +0 -1
  6. package/generators/ts/Import.js +0 -5
  7. package/generators/ts/ListType.d.ts +3 -2
  8. package/generators/ts/ListType.js +17 -9
  9. package/generators/ts/ObjectType.d.ts +3 -2
  10. package/generators/ts/ObjectType.js +20 -9
  11. package/generators/ts/ObjectUnionType.d.ts +1 -1
  12. package/generators/ts/ObjectUnionType.js +16 -47
  13. package/generators/ts/OptionType.d.ts +3 -1
  14. package/generators/ts/OptionType.js +12 -11
  15. package/generators/ts/PrimitiveType.d.ts +2 -2
  16. package/generators/ts/PrimitiveType.js +9 -4
  17. package/generators/ts/SetType.d.ts +3 -1
  18. package/generators/ts/SetType.js +12 -8
  19. package/generators/ts/SnippetDeclarations.d.ts +11 -0
  20. package/generators/ts/SnippetDeclarations.js +215 -0
  21. package/generators/ts/TermType.d.ts +3 -1
  22. package/generators/ts/TermType.js +16 -8
  23. package/generators/ts/TsGenerator.js +15 -1
  24. package/generators/ts/Type.d.ts +15 -5
  25. package/generators/ts/Type.js +17 -0
  26. package/generators/ts/TypeFactory.js +14 -4
  27. package/generators/ts/UnionType.d.ts +2 -1
  28. package/generators/ts/UnionType.js +3 -3
  29. package/generators/ts/_ObjectType/IdentifierProperty.d.ts +4 -5
  30. package/generators/ts/_ObjectType/IdentifierProperty.js +16 -7
  31. package/generators/ts/_ObjectType/Property.d.ts +17 -3
  32. package/generators/ts/_ObjectType/Property.js +2 -1
  33. package/generators/ts/_ObjectType/ShaclProperty.d.ts +1 -0
  34. package/generators/ts/_ObjectType/ShaclProperty.js +4 -1
  35. package/generators/ts/_ObjectType/TypeDiscriminatorProperty.d.ts +3 -5
  36. package/generators/ts/_ObjectType/TypeDiscriminatorProperty.js +11 -4
  37. package/generators/ts/_ObjectType/equalsFunctionOrMethodDeclaration.js +1 -1
  38. package/generators/ts/_ObjectType/fromJsonFunctionDeclarations.js +1 -1
  39. package/generators/ts/_ObjectType/fromRdfFunctionDeclarations.js +1 -1
  40. package/generators/ts/_ObjectType/sparqlConstructQueryFunctionDeclaration.d.ts +5 -0
  41. package/generators/ts/_ObjectType/sparqlConstructQueryFunctionDeclaration.js +21 -0
  42. package/generators/ts/_ObjectType/sparqlConstructQueryStringFunctionDeclaration.d.ts +5 -0
  43. package/generators/ts/_ObjectType/sparqlConstructQueryStringFunctionDeclaration.js +20 -0
  44. package/generators/ts/_ObjectType/sparqlFunctionDeclarations.js +35 -58
  45. package/generators/ts/_ObjectType/toJsonFunctionOrMethodDeclaration.js +1 -1
  46. package/input/generated.d.ts +15 -14
  47. package/input/generated.js +20 -4
  48. package/input/tsFeatures.d.ts +1 -1
  49. package/input/tsFeatures.js +17 -13
  50. package/package.json +4 -4
@@ -6,6 +6,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
6
6
  };
7
7
  import { invariant } from "ts-invariant";
8
8
  import { Memoize } from "typescript-memoize";
9
+ import { SnippetDeclarations } from "./SnippetDeclarations.js";
9
10
  import { Type } from "./Type.js";
10
11
  import { objectInitializer } from "./objectInitializer.js";
11
12
  export class SetType extends Type {
@@ -40,11 +41,7 @@ export class SetType extends Type {
40
41
  return conversions;
41
42
  }
42
43
  get equalsFunction() {
43
- const itemTypeEqualsFunction = this.itemType.equalsFunction;
44
- if (itemTypeEqualsFunction === "purifyHelpers.Equatable.equals") {
45
- return "purifyHelpers.Equatable.arrayEquals";
46
- }
47
- return `(left, right) => purifyHelpers.Arrays.equals(left, right, ${itemTypeEqualsFunction})`;
44
+ return `((left, right) => arrayEquals(left, right, ${this.itemType.equalsFunction}))`;
48
45
  }
49
46
  get jsonName() {
50
47
  if (this.minCount === 0) {
@@ -61,9 +58,6 @@ export class SetType extends Type {
61
58
  }
62
59
  return `purify.NonEmptyList<${this.itemType.name}>`;
63
60
  }
64
- get useImports() {
65
- return this.itemType.useImports;
66
- }
67
61
  fromJsonExpression({ variables, }) {
68
62
  let expression = variables.value;
69
63
  if (this.minCount > 0) {
@@ -108,6 +102,13 @@ export class SetType extends Type {
108
102
  }
109
103
  return schema;
110
104
  }
105
+ snippetDeclarations(features) {
106
+ const snippetDeclarations = [];
107
+ if (features.has("equals")) {
108
+ snippetDeclarations.push(SnippetDeclarations.arrayEquals);
109
+ }
110
+ return snippetDeclarations;
111
+ }
111
112
  sparqlConstructTemplateTriples({ context, variables, }) {
112
113
  switch (context) {
113
114
  case "property":
@@ -143,6 +144,9 @@ export class SetType extends Type {
143
144
  variables: { ...variables, value: "_item" },
144
145
  })})`;
145
146
  }
147
+ useImports(features) {
148
+ return this.itemType.useImports(features);
149
+ }
146
150
  }
147
151
  __decorate([
148
152
  Memoize()
@@ -0,0 +1,11 @@
1
+ export declare namespace SnippetDeclarations {
2
+ const arrayEquals = "export 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 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
+ 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
+ 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 return purify.Left({\n left,\n right,\n type: \"BooleanEquals\",\n });\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: object;\n readonly right: object;\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";
6
+ const maybeEquals = "export function maybeEquals<T>(\n leftMaybe: purify.Maybe<T>,\n rightMaybe: purify.Maybe<T>,\n valueEquals: (left: T, right: T) => boolean | EqualsResult,\n): EqualsResult {\n if (leftMaybe.isJust()) {\n if (rightMaybe.isJust()) {\n return EqualsResult.fromBooleanEqualsResult(\n leftMaybe,\n rightMaybe,\n valueEquals(leftMaybe.unsafeCoerce(), rightMaybe.unsafeCoerce()),\n );\n }\n return purify.Left({\n left: leftMaybe.unsafeCoerce(),\n type: \"RightNull\",\n });\n }\n\n if (rightMaybe.isJust()) {\n return purify.Left({\n right: rightMaybe.unsafeCoerce(),\n type: \"LeftNull\",\n });\n }\n\n return EqualsResult.Equal;\n}\n";
7
+ 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}";
8
+ const UnwrapL = "type UnwrapL<T> = T extends purify.Either<infer L, any> ? L : never";
9
+ const UnwrapR = "type UnwrapR<T> = T extends purify.Either<any, infer R> ? R : never";
10
+ }
11
+ //# sourceMappingURL=SnippetDeclarations.d.ts.map
@@ -0,0 +1,215 @@
1
+ export var SnippetDeclarations;
2
+ (function (SnippetDeclarations) {
3
+ SnippetDeclarations.arrayEquals = `\
4
+ export function arrayEquals<T>(
5
+ leftArray: readonly T[],
6
+ rightArray: readonly T[],
7
+ elementEquals: (left: T, right: T) => boolean | EqualsResult,
8
+ ): EqualsResult {
9
+ if (leftArray.length !== rightArray.length) {
10
+ return purify.Left({
11
+ left: leftArray,
12
+ right: rightArray,
13
+ type: "ArrayLength",
14
+ });
15
+ }
16
+
17
+ for (
18
+ let leftElementIndex = 0;
19
+ leftElementIndex < leftArray.length;
20
+ leftElementIndex++
21
+ ) {
22
+ const leftElement = leftArray[leftElementIndex];
23
+
24
+ const rightUnequals: EqualsResult.Unequal[] = [];
25
+ for (
26
+ let rightElementIndex = 0;
27
+ rightElementIndex < rightArray.length;
28
+ rightElementIndex++
29
+ ) {
30
+ const rightElement = rightArray[rightElementIndex];
31
+
32
+ const leftElementEqualsRightElement =
33
+ EqualsResult.fromBooleanEqualsResult(
34
+ leftElement,
35
+ rightElement,
36
+ elementEquals(leftElement, rightElement),
37
+ );
38
+ if (leftElementEqualsRightElement.isRight()) {
39
+ break; // left element === right element, break out of the right iteration
40
+ }
41
+ rightUnequals.push(
42
+ leftElementEqualsRightElement.extract() as EqualsResult.Unequal,
43
+ );
44
+ }
45
+
46
+ if (rightUnequals.length === rightArray.length) {
47
+ // All right elements were unequal to the left element
48
+ return purify.Left({
49
+ left: {
50
+ array: leftArray,
51
+ element: leftElement,
52
+ elementIndex: leftElementIndex,
53
+ },
54
+ right: {
55
+ array: rightArray,
56
+ unequals: rightUnequals,
57
+ },
58
+ type: "ArrayElement",
59
+ });
60
+ }
61
+ // Else there was a right element equal to the left element, continue to the next left element
62
+ }
63
+
64
+ return EqualsResult.Equal;
65
+ }
66
+ `;
67
+ SnippetDeclarations.booleanEquals = `\
68
+ /**
69
+ * Compare two objects with equals(other: T): boolean methods and return an EqualsResult.
70
+ */
71
+ export function booleanEquals<T extends { equals: (other: T) => boolean }>(
72
+ left: T,
73
+ right: T,
74
+ ): EqualsResult {
75
+ return EqualsResult.fromBooleanEqualsResult(
76
+ left,
77
+ right,
78
+ left.equals(right),
79
+ );
80
+ }`;
81
+ SnippetDeclarations.dateEquals = `\
82
+ /**
83
+ * Compare two Dates and return an EqualsResult.
84
+ */
85
+ export function dateEquals(left: Date, right: Date): EqualsResult {
86
+ return EqualsResult.fromBooleanEqualsResult(
87
+ left,
88
+ right,
89
+ left.getTime() === right.getTime(),
90
+ );
91
+ }`;
92
+ SnippetDeclarations.EqualsResult = `\
93
+ export type EqualsResult = purify.Either<EqualsResult.Unequal, true>;
94
+
95
+ export namespace EqualsResult {
96
+ export const Equal: EqualsResult = purify.Either.of<Unequal, true>(true);
97
+
98
+ export function fromBooleanEqualsResult(
99
+ left: any,
100
+ right: any,
101
+ equalsResult: boolean | EqualsResult,
102
+ ): EqualsResult {
103
+ if (typeof equalsResult !== "boolean") {
104
+ return equalsResult;
105
+ }
106
+
107
+ if (equalsResult) {
108
+ return Equal;
109
+ }
110
+ return purify.Left({
111
+ left,
112
+ right,
113
+ type: "BooleanEquals",
114
+ });
115
+ }
116
+
117
+ export type Unequal =
118
+ | {
119
+ readonly left: {
120
+ readonly array: readonly any[];
121
+ readonly element: any;
122
+ readonly elementIndex: number;
123
+ };
124
+ readonly right: {
125
+ readonly array: readonly any[];
126
+ readonly unequals: readonly Unequal[];
127
+ };
128
+ readonly type: "ArrayElement";
129
+ }
130
+ | {
131
+ readonly left: readonly any[];
132
+ readonly right: readonly any[];
133
+ readonly type: "ArrayLength";
134
+ }
135
+ | {
136
+ readonly left: any;
137
+ readonly right: any;
138
+ readonly type: "BooleanEquals";
139
+ }
140
+ | {
141
+ readonly left: any;
142
+ readonly right: any;
143
+ readonly type: "LeftError";
144
+ }
145
+ | {
146
+ readonly right: any;
147
+ readonly type: "LeftNull";
148
+ }
149
+ | {
150
+ readonly left: bigint | boolean | number | string;
151
+ readonly right: bigint | boolean | number | string;
152
+ readonly type: "Primitive";
153
+ }
154
+ | {
155
+ readonly left: object;
156
+ readonly right: object;
157
+ readonly propertyName: string;
158
+ readonly propertyValuesUnequal: Unequal;
159
+ readonly type: "Property";
160
+ }
161
+ | {
162
+ readonly left: any;
163
+ readonly right: any;
164
+ readonly type: "RightError";
165
+ }
166
+ | {
167
+ readonly left: any;
168
+ readonly type: "RightNull";
169
+ };
170
+ }
171
+ `;
172
+ SnippetDeclarations.maybeEquals = `\
173
+ export function maybeEquals<T>(
174
+ leftMaybe: purify.Maybe<T>,
175
+ rightMaybe: purify.Maybe<T>,
176
+ valueEquals: (left: T, right: T) => boolean | EqualsResult,
177
+ ): EqualsResult {
178
+ if (leftMaybe.isJust()) {
179
+ if (rightMaybe.isJust()) {
180
+ return EqualsResult.fromBooleanEqualsResult(
181
+ leftMaybe,
182
+ rightMaybe,
183
+ valueEquals(leftMaybe.unsafeCoerce(), rightMaybe.unsafeCoerce()),
184
+ );
185
+ }
186
+ return purify.Left({
187
+ left: leftMaybe.unsafeCoerce(),
188
+ type: "RightNull",
189
+ });
190
+ }
191
+
192
+ if (rightMaybe.isJust()) {
193
+ return purify.Left({
194
+ right: rightMaybe.unsafeCoerce(),
195
+ type: "LeftNull",
196
+ });
197
+ }
198
+
199
+ return EqualsResult.Equal;
200
+ }
201
+ `;
202
+ SnippetDeclarations.strictEquals = `\
203
+ /**
204
+ * Compare two values for strict equality (===), returning an EqualsResult rather than a boolean.
205
+ */
206
+ export function strictEquals<T extends bigint | boolean | number | string>(
207
+ left: T,
208
+ right: T,
209
+ ): EqualsResult {
210
+ return EqualsResult.fromBooleanEqualsResult(left, right, left === right);
211
+ }`;
212
+ SnippetDeclarations.UnwrapL = "type UnwrapL<T> = T extends purify.Either<infer L, any> ? L : never";
213
+ SnippetDeclarations.UnwrapR = "type UnwrapR<T> = T extends purify.Either<any, infer R> ? R : never";
214
+ })(SnippetDeclarations || (SnippetDeclarations = {}));
215
+ //# sourceMappingURL=SnippetDeclarations.js.map
@@ -1,5 +1,6 @@
1
1
  import type { BlankNode, Literal, NamedNode } from "@rdfjs/types";
2
2
  import { Maybe } from "purify-ts";
3
+ import type { TsFeature } from "../../enums/index.js";
3
4
  import { Import } from "./Import.js";
4
5
  import { Type } from "./Type.js";
5
6
  /**
@@ -22,14 +23,15 @@ export declare class TermType<TermT extends BlankNode | Literal | NamedNode> ext
22
23
  get discriminatorProperty(): Maybe<Type.DiscriminatorProperty>;
23
24
  get jsonName(): string;
24
25
  get name(): string;
25
- get useImports(): readonly Import[];
26
26
  fromJsonExpression({ variables, }: Parameters<Type["fromJsonExpression"]>[0]): string;
27
27
  fromRdfExpression({ variables, }: Parameters<Type["fromRdfExpression"]>[0]): string;
28
28
  hashStatements({ variables, }: Parameters<Type["hashStatements"]>[0]): readonly string[];
29
29
  jsonZodSchema({ variables, }: Parameters<Type["jsonZodSchema"]>[0]): ReturnType<Type["jsonZodSchema"]>;
30
+ snippetDeclarations(features: Set<TsFeature>): readonly string[];
30
31
  sparqlWherePatterns(parameters: Parameters<Type["sparqlWherePatterns"]>[0]): readonly string[];
31
32
  toJsonExpression({ variables, }: Parameters<Type["toJsonExpression"]>[0]): string;
32
33
  toRdfExpression({ variables, }: Parameters<Type["toRdfExpression"]>[0]): string;
34
+ useImports(): readonly Import[];
33
35
  /**
34
36
  * Filter the rdfjsResource.Resource.Values to those that are relevant to the type.
35
37
  *
@@ -9,6 +9,7 @@ import { Maybe } from "purify-ts";
9
9
  import { invariant } from "ts-invariant";
10
10
  import { Memoize } from "typescript-memoize";
11
11
  import { Import } from "./Import.js";
12
+ import { SnippetDeclarations } from "./SnippetDeclarations.js";
12
13
  import { Type } from "./Type.js";
13
14
  import { objectInitializer } from "./objectInitializer.js";
14
15
  /**
@@ -17,7 +18,7 @@ import { objectInitializer } from "./objectInitializer.js";
17
18
  export class TermType extends Type {
18
19
  constructor({ defaultValue, hasValues, in_, nodeKinds, ...superParameters }) {
19
20
  super(superParameters);
20
- this.equalsFunction = "purifyHelpers.Equatable.booleanEquals";
21
+ this.equalsFunction = "booleanEquals";
21
22
  this.mutable = false;
22
23
  this.defaultValue = defaultValue;
23
24
  this.hasValues = hasValues;
@@ -80,13 +81,6 @@ export class TermType extends Type {
80
81
  .map((nodeKind) => `rdfjs.${nodeKind}`)
81
82
  .join(" | ")})`;
82
83
  }
83
- get useImports() {
84
- const imports = [Import.RDFJS_TYPES];
85
- if (this.nodeKinds.has("Literal")) {
86
- imports.push(Import.RDF_LITERAL);
87
- }
88
- return imports;
89
- }
90
84
  fromJsonExpression({ variables, }) {
91
85
  invariant(this.nodeKinds.has("Literal") &&
92
86
  (this.nodeKinds.has("BlankNode") || this.nodeKinds.has("NamedNode")), "IdentifierType and LiteralType should override");
@@ -161,6 +155,13 @@ export class TermType extends Type {
161
155
  })
162
156
  .join(", ")}])`;
163
157
  }
158
+ snippetDeclarations(features) {
159
+ const snippetDeclarations = [];
160
+ if (features.has("equals")) {
161
+ snippetDeclarations.push(SnippetDeclarations.booleanEquals);
162
+ }
163
+ return snippetDeclarations;
164
+ }
164
165
  sparqlWherePatterns(parameters) {
165
166
  switch (parameters.context) {
166
167
  case "property":
@@ -201,6 +202,13 @@ export class TermType extends Type {
201
202
  .map((defaultValue) => `!${variables.value}.equals(${this.rdfjsTermExpression(defaultValue)}) ? ${variables.value} : undefined`)
202
203
  .orDefault(variables.value);
203
204
  }
205
+ useImports() {
206
+ const imports = [Import.RDFJS_TYPES];
207
+ if (this.nodeKinds.has("Literal")) {
208
+ imports.push(Import.RDF_LITERAL);
209
+ }
210
+ return imports;
211
+ }
204
212
  /**
205
213
  * Filter the rdfjsResource.Resource.Values to those that are relevant to the type.
206
214
  *
@@ -30,9 +30,13 @@ export class TsGenerator {
30
30
  addDeclarations({ objectTypes, objectUnionTypes, sourceFile, }) {
31
31
  // sourceFile.addStatements(this.configuration.dataFactoryImport);
32
32
  sourceFile.addStatements('import { DataFactory as dataFactory } from "n3"');
33
+ const declaredTypes = [
34
+ ...objectTypes,
35
+ ...objectUnionTypes,
36
+ ];
33
37
  // Gather imports
34
38
  const imports = [];
35
- for (const declaredType of [...objectTypes, ...objectUnionTypes]) {
39
+ for (const declaredType of declaredTypes) {
36
40
  imports.push(...declaredType.declarationImports);
37
41
  }
38
42
  // Deduplicate and add imports
@@ -51,6 +55,16 @@ export class TsGenerator {
51
55
  addedStructureImports.push(import_);
52
56
  }
53
57
  }
58
+ // Deduplicate and add snippet declarations
59
+ const addedSnippetDeclarations = new Set();
60
+ for (const declaredType of declaredTypes) {
61
+ for (const snippetDeclaration of declaredType.snippetDeclarations(declaredType.features)) {
62
+ if (!addedSnippetDeclarations.has(snippetDeclaration)) {
63
+ sourceFile.addStatements([snippetDeclaration]);
64
+ addedSnippetDeclarations.add(snippetDeclaration);
65
+ }
66
+ }
67
+ }
54
68
  // Add type declarations
55
69
  for (const objectType of objectTypes) {
56
70
  sourceFile.addStatements(objectType.declarations);
@@ -1,5 +1,6 @@
1
1
  import type { BlankNode, Literal, NamedNode, Variable } from "@rdfjs/types";
2
2
  import { Maybe } from "purify-ts";
3
+ import type { TsFeature } from "../../enums/index.js";
3
4
  import type { Import } from "./Import.js";
4
5
  /**
5
6
  * Abstract base class for generating TypeScript expressions and statemenst in the TypeScript generator.
@@ -13,7 +14,7 @@ export declare abstract class Type {
13
14
  abstract readonly conversions: readonly Type.Conversion[];
14
15
  /**
15
16
  * A function (reference or declaration) that compares two property values of this type, returning a
16
- * purifyHelpers.Equatable.EqualsResult.
17
+ * EqualsResult.
17
18
  */
18
19
  abstract readonly equalsFunction: string;
19
20
  /**
@@ -28,10 +29,6 @@ export declare abstract class Type {
28
29
  * Name of the type.
29
30
  */
30
31
  abstract readonly name: string;
31
- /**
32
- * Imports necessary to use this type.
33
- */
34
- abstract readonly useImports: readonly Import[];
35
32
  protected readonly dataFactoryVariable: string;
36
33
  constructor({ dataFactoryVariable, }: {
37
34
  dataFactoryVariable: string;
@@ -87,6 +84,15 @@ export declare abstract class Type {
87
84
  zod: string;
88
85
  };
89
86
  }): string;
87
+ /**
88
+ * Reusable function, type, and other declarations that are not particular to this type but that type-specific code
89
+ * relies on. For example, the equals function/method of ObjectType has a custom return type that's the same across all
90
+ * ObjectType's. Instead of re-declaring the return type anonymously on every equals function, declare a named type
91
+ * as a snippet and reference it.
92
+ *
93
+ * The generator deduplicates snippet declarations across all types before adding them to the source.
94
+ */
95
+ snippetDeclarations(_features: Set<TsFeature>): readonly string[];
90
96
  /**
91
97
  * An array of SPARQL.js CONSTRUCT template triples for a value of this type, as strings (so they can incorporate runtime calls).
92
98
  *
@@ -153,6 +159,10 @@ export declare abstract class Type {
153
159
  value: string;
154
160
  };
155
161
  }): string;
162
+ /**
163
+ * Imports necessary to use this type.
164
+ */
165
+ useImports(_features: Set<TsFeature>): readonly Import[];
156
166
  protected rdfjsTermExpression(rdfjsTerm: Omit<BlankNode, "equals"> | Omit<Literal, "equals"> | Omit<NamedNode, "equals"> | Omit<Variable, "equals">): string;
157
167
  }
158
168
  export declare namespace Type {
@@ -23,6 +23,17 @@ export class Type {
23
23
  jsonUiSchemaElement(_parameters) {
24
24
  return Maybe.empty();
25
25
  }
26
+ /**
27
+ * Reusable function, type, and other declarations that are not particular to this type but that type-specific code
28
+ * relies on. For example, the equals function/method of ObjectType has a custom return type that's the same across all
29
+ * ObjectType's. Instead of re-declaring the return type anonymously on every equals function, declare a named type
30
+ * as a snippet and reference it.
31
+ *
32
+ * The generator deduplicates snippet declarations across all types before adding them to the source.
33
+ */
34
+ snippetDeclarations(_features) {
35
+ return [];
36
+ }
26
37
  /**
27
38
  * An array of SPARQL.js CONSTRUCT template triples for a value of this type, as strings (so they can incorporate runtime calls).
28
39
  *
@@ -90,6 +101,12 @@ export class Type {
90
101
  return [];
91
102
  }
92
103
  }
104
+ /**
105
+ * Imports necessary to use this type.
106
+ */
107
+ useImports(_features) {
108
+ return [];
109
+ }
93
110
  rdfjsTermExpression(rdfjsTerm) {
94
111
  return rdfjsTermExpression({
95
112
  dataFactoryVariable: this.dataFactoryVariable,
@@ -232,7 +232,7 @@ export class TypeFactory {
232
232
  lazyDescendantObjectTypes: () => astType.descendantObjectTypes.map((astType) => this.createObjectTypeFromAstType(astType)),
233
233
  lazyParentObjectTypes: () => astType.parentObjectTypes.map((astType) => this.createObjectTypeFromAstType(astType)),
234
234
  lazyProperties: () => {
235
- const properties = astType.properties.map((astProperty) => this.createObjectTypePropertyFromAstProperty(astProperty));
235
+ const properties = astType.properties.map((astProperty) => this.createObjectTypePropertyFromAstProperty(astType, astProperty));
236
236
  let identifierPropertyClassDeclarationVisibility;
237
237
  if (astType.abstract) {
238
238
  // If the type is abstract, don't declare a property.
@@ -256,7 +256,10 @@ export class TypeFactory {
256
256
  mintingStrategy: astType.mintingStrategy,
257
257
  name: astType.tsIdentifierPropertyName,
258
258
  lazyObjectTypeMutable: () => properties.some((property) => property.mutable || property.type.mutable),
259
- objectTypeDeclarationType: astType.tsObjectDeclarationType,
259
+ objectType: {
260
+ declarationType: astType.tsObjectDeclarationType,
261
+ features: astType.tsFeatures,
262
+ },
260
263
  override: astType.parentObjectTypes.length > 0,
261
264
  type: identifierType,
262
265
  visibility: "public",
@@ -277,7 +280,10 @@ export class TypeFactory {
277
280
  abstract: astType.abstract,
278
281
  dataFactoryVariable: this.dataFactoryVariable,
279
282
  name: astType.tsTypeDiscriminatorPropertyName,
280
- objectTypeDeclarationType: objectType.declarationType,
283
+ objectType: {
284
+ declarationType: astType.tsObjectDeclarationType,
285
+ features: astType.tsFeatures,
286
+ },
281
287
  override: objectType.parentObjectTypes.length > 0,
282
288
  type: new ObjectType.TypeDiscriminatorProperty.Type({
283
289
  mutable: false,
@@ -296,7 +302,7 @@ export class TypeFactory {
296
302
  this.cachedObjectTypesByIdentifier.set(astType.name.identifier, objectType);
297
303
  return objectType;
298
304
  }
299
- createObjectTypePropertyFromAstProperty(astObjectTypeProperty) {
305
+ createObjectTypePropertyFromAstProperty(astObjectType, astObjectTypeProperty) {
300
306
  {
301
307
  const cachedProperty = this.cachedObjectTypePropertiesByIdentifier.get(astObjectTypeProperty.name.identifier);
302
308
  if (cachedProperty) {
@@ -309,6 +315,10 @@ export class TypeFactory {
309
315
  description: astObjectTypeProperty.description,
310
316
  label: astObjectTypeProperty.label,
311
317
  mutable: astObjectTypeProperty.mutable.orDefault(false),
318
+ objectType: {
319
+ declarationType: astObjectType.tsObjectDeclarationType,
320
+ features: astObjectType.tsFeatures,
321
+ },
312
322
  name: tsName(astObjectTypeProperty.name),
313
323
  path: astObjectTypeProperty.path.iri,
314
324
  type: this.createTypeFromAstType(astObjectTypeProperty.type),
@@ -1,4 +1,5 @@
1
1
  import { Maybe } from "purify-ts";
2
+ import type { TsFeature } from "../../enums/index.js";
2
3
  import type { Import } from "./Import.js";
3
4
  import { Type } from "./Type.js";
4
5
  export declare class UnionType extends Type {
@@ -15,7 +16,6 @@ export declare class UnionType extends Type {
15
16
  get equalsFunction(): string;
16
17
  get jsonName(): string;
17
18
  get mutable(): boolean;
18
- get useImports(): readonly Import[];
19
19
  private get _discriminatorProperty();
20
20
  private get memberTypeTraits();
21
21
  fromJsonExpression({ variables, }: Parameters<Type["fromJsonExpression"]>[0]): string;
@@ -26,6 +26,7 @@ export declare class UnionType extends Type {
26
26
  sparqlWherePatterns(parameters: Parameters<Type["sparqlWherePatterns"]>[0]): readonly string[];
27
27
  toJsonExpression({ variables, }: Parameters<Type["toJsonExpression"]>[0]): string;
28
28
  toRdfExpression({ variables, }: Parameters<Type["toRdfExpression"]>[0]): string;
29
+ useImports(features: Set<TsFeature>): readonly Import[];
29
30
  private ternaryExpression;
30
31
  }
31
32
  //# sourceMappingURL=UnionType.d.ts.map
@@ -71,9 +71,6 @@ ${this.memberTypeTraits
71
71
  get mutable() {
72
72
  return this.memberTypes.some((memberType) => memberType.mutable);
73
73
  }
74
- get useImports() {
75
- return this.memberTypes.flatMap((memberType) => memberType.useImports);
76
- }
77
74
  get _discriminatorProperty() {
78
75
  let sharedDiscriminatorProperty;
79
76
  for (const memberType of this.memberTypes) {
@@ -252,6 +249,9 @@ ${this.memberTypeTraits
252
249
  variables,
253
250
  });
254
251
  }
252
+ useImports(features) {
253
+ return this.memberTypes.flatMap((memberType) => memberType.useImports(features));
254
+ }
255
255
  ternaryExpression({ memberTypeExpression, variables, }) {
256
256
  return this.memberTypeTraits.reduce((expression, memberTypeTraits) => {
257
257
  if (expression.length === 0) {
@@ -1,24 +1,22 @@
1
1
  import { Maybe } from "purify-ts";
2
2
  import type { GetAccessorDeclarationStructure, OptionalKind, PropertyDeclarationStructure, PropertySignatureStructure } from "ts-morph";
3
- import type { MintingStrategy, PropertyVisibility, TsObjectDeclarationType } from "../../../enums/index.js";
3
+ import type { MintingStrategy, PropertyVisibility } from "../../../enums/index.js";
4
4
  import type { IdentifierType } from "../IdentifierType.js";
5
5
  import { Import } from "../Import.js";
6
6
  import { Property } from "./Property.js";
7
7
  export declare class IdentifierProperty extends Property<IdentifierType> {
8
8
  readonly abstract: boolean;
9
- readonly equalsFunction = "purifyHelpers.Equatable.booleanEquals";
9
+ readonly equalsFunction = "booleanEquals";
10
10
  readonly mutable = false;
11
11
  private readonly classDeclarationVisibility;
12
12
  private readonly lazyObjectTypeMutable;
13
13
  private readonly mintingStrategy;
14
- private readonly objectTypeDeclarationType;
15
14
  private readonly override;
16
- constructor({ abstract, classDeclarationVisibility, lazyObjectTypeMutable, mintingStrategy, objectTypeDeclarationType, override, ...superParameters }: {
15
+ constructor({ abstract, classDeclarationVisibility, lazyObjectTypeMutable, mintingStrategy, override, ...superParameters }: {
17
16
  abstract: boolean;
18
17
  classDeclarationVisibility: Maybe<PropertyVisibility>;
19
18
  lazyObjectTypeMutable: () => boolean;
20
19
  mintingStrategy: Maybe<MintingStrategy>;
21
- objectTypeDeclarationType: TsObjectDeclarationType;
22
20
  override: boolean;
23
21
  type: IdentifierType;
24
22
  } & ConstructorParameters<typeof Property>[0]);
@@ -28,6 +26,7 @@ export declare class IdentifierProperty extends Property<IdentifierType> {
28
26
  get declarationImports(): readonly Import[];
29
27
  get interfacePropertySignature(): OptionalKind<PropertySignatureStructure>;
30
28
  get jsonPropertySignature(): OptionalKind<PropertySignatureStructure>;
29
+ get snippetDeclarations(): readonly string[];
31
30
  classConstructorStatements({ variables, }: Parameters<Property<IdentifierType>["classConstructorStatements"]>[0]): readonly string[];
32
31
  fromJsonStatements({ variables, }: Parameters<Property<IdentifierType>["fromJsonStatements"]>[0]): readonly string[];
33
32
  fromRdfStatements({ variables, }: Parameters<Property<IdentifierType>["fromRdfStatements"]>[0]): readonly string[];