@nyrra/prismantix-cli 0.0.4-next.23 → 0.0.4-next.25
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 +2 -2
- package/dist/foundry-import/actions.d.ts +9 -2
- package/dist/foundry-import/actions.d.ts.map +1 -1
- package/dist/foundry-import/actions.js +436 -19
- package/dist/foundry-import/convert.d.ts.map +1 -1
- package/dist/foundry-import/convert.js +68 -4
- package/dist/foundry-import/emit.d.ts.map +1 -1
- package/dist/foundry-import/emit.js +172 -5
- package/dist/foundry-import/interfaces.d.ts +11 -2
- package/dist/foundry-import/interfaces.d.ts.map +1 -1
- package/dist/foundry-import/interfaces.js +132 -24
- package/dist/foundry-import/names.d.ts +1 -0
- package/dist/foundry-import/names.d.ts.map +1 -1
- package/dist/foundry-import/names.js +18 -0
- package/dist/foundry-import/objects.d.ts +2 -1
- package/dist/foundry-import/objects.d.ts.map +1 -1
- package/dist/foundry-import/objects.js +92 -10
- package/dist/foundry-import/parse.d.ts.map +1 -1
- package/dist/foundry-import/parse.js +520 -0
- package/dist/foundry-import/types.d.ts +78 -5
- package/dist/foundry-import/types.d.ts.map +1 -1
- package/dist/foundry-import/validate.js +15 -3
- package/oclif.manifest.json +1 -1
- package/package.json +1 -1
|
@@ -4,6 +4,8 @@ import { isRecord } from "./utils.js";
|
|
|
4
4
|
export function emitFoundryImportFiles(result, options = {}) {
|
|
5
5
|
const ontologyName = options.ontologyName ?? "ImportedFoundryOntology";
|
|
6
6
|
return [
|
|
7
|
+
emitPackageJson(ontologyName),
|
|
8
|
+
emitTsconfig(),
|
|
7
9
|
emitIndex(ontologyName),
|
|
8
10
|
emitOntologyEntrypoint(ontologyName),
|
|
9
11
|
{ path: "objects.mts", content: emitObjects(result, ontologyName) },
|
|
@@ -22,6 +24,45 @@ export function emitFoundryImportFiles(result, options = {}) {
|
|
|
22
24
|
{ path: "diagnostics.md", content: emitDiagnosticsMarkdown(result) },
|
|
23
25
|
];
|
|
24
26
|
}
|
|
27
|
+
function emitPackageJson(ontologyName) {
|
|
28
|
+
return {
|
|
29
|
+
path: "package.json",
|
|
30
|
+
content: `${JSON.stringify({
|
|
31
|
+
dependencies: {
|
|
32
|
+
"@osdk/maker": "0.44.0",
|
|
33
|
+
},
|
|
34
|
+
devDependencies: {
|
|
35
|
+
typescript: "^5.9.3",
|
|
36
|
+
},
|
|
37
|
+
name: `@imported-ontology/${packageSlug(ontologyName)}`,
|
|
38
|
+
private: true,
|
|
39
|
+
scripts: {
|
|
40
|
+
typecheck: "tsc -p tsconfig.json --noEmit",
|
|
41
|
+
},
|
|
42
|
+
type: "module",
|
|
43
|
+
version: "0.0.0",
|
|
44
|
+
}, null, 2)}\n`,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
function emitTsconfig() {
|
|
48
|
+
return {
|
|
49
|
+
path: "tsconfig.json",
|
|
50
|
+
content: `${JSON.stringify({
|
|
51
|
+
compilerOptions: {
|
|
52
|
+
declaration: true,
|
|
53
|
+
module: "NodeNext",
|
|
54
|
+
moduleResolution: "NodeNext",
|
|
55
|
+
noEmitOnError: true,
|
|
56
|
+
outDir: "dist",
|
|
57
|
+
rootDir: ".",
|
|
58
|
+
skipLibCheck: true,
|
|
59
|
+
strict: true,
|
|
60
|
+
target: "ES2022",
|
|
61
|
+
},
|
|
62
|
+
include: ["*.mts"],
|
|
63
|
+
}, null, 2)}\n`,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
25
66
|
function emitIndex(ontologyName) {
|
|
26
67
|
return {
|
|
27
68
|
path: "index.mts",
|
|
@@ -55,6 +96,7 @@ function emitObjects(result, ontologyName) {
|
|
|
55
96
|
return [
|
|
56
97
|
header(ontologyName),
|
|
57
98
|
`import { defineObject } from "@osdk/maker";`,
|
|
99
|
+
...objectInterfaceImports(result),
|
|
58
100
|
"",
|
|
59
101
|
body,
|
|
60
102
|
"",
|
|
@@ -62,6 +104,12 @@ function emitObjects(result, ontologyName) {
|
|
|
62
104
|
"",
|
|
63
105
|
].join("\n");
|
|
64
106
|
}
|
|
107
|
+
function objectInterfaceImports(result) {
|
|
108
|
+
const interfaceNames = Array.from(new Set(result.objects.flatMap((object) => object.interfaceImplementations.map((implementation) => implementation.interfaceVariableName))));
|
|
109
|
+
return interfaceNames.length === 0
|
|
110
|
+
? []
|
|
111
|
+
: [`import { ${interfaceNames.join(", ")} } from "./interfaces.mjs";`];
|
|
112
|
+
}
|
|
65
113
|
function emitObject(object) {
|
|
66
114
|
const properties = object.properties.map(emitObjectProperty).join(",\n");
|
|
67
115
|
return [
|
|
@@ -70,6 +118,9 @@ function emitObject(object) {
|
|
|
70
118
|
apiName: object.apiName.sanitized,
|
|
71
119
|
description: object.description,
|
|
72
120
|
displayName: object.displayName,
|
|
121
|
+
implementsInterfaces: object.interfaceImplementations.length > 0
|
|
122
|
+
? raw(`[\n${object.interfaceImplementations.map(emitObjectInterfaceImplementation).join(",\n")}\n\t]`)
|
|
123
|
+
: undefined,
|
|
73
124
|
pluralDisplayName: object.pluralDisplayName,
|
|
74
125
|
primaryKeyPropertyApiName: object.primaryKeyPropertyApiName,
|
|
75
126
|
properties: raw(`{\n${properties}\n\t}`),
|
|
@@ -78,6 +129,12 @@ function emitObject(object) {
|
|
|
78
129
|
}, 0)});`,
|
|
79
130
|
].join("\n");
|
|
80
131
|
}
|
|
132
|
+
function emitObjectInterfaceImplementation(implementation) {
|
|
133
|
+
return `\t\t{\n\t\t\timplements: ${implementation.interfaceVariableName},\n\t\t\tpropertyMapping: ${objectLiteral(implementation.propertyMappings.map((mapping) => ({
|
|
134
|
+
interfaceProperty: mapping.interfacePropertyApiName,
|
|
135
|
+
mapsTo: mapping.objectPropertyApiName,
|
|
136
|
+
})), 3)}\n\t\t}`;
|
|
137
|
+
}
|
|
81
138
|
function emitObjectProperty(property) {
|
|
82
139
|
return `\t\t${safePropertyKey(property.apiName.sanitized)}: ${objectLiteral({
|
|
83
140
|
array: property.array || undefined,
|
|
@@ -142,17 +199,56 @@ function emitSharedProperty(property) {
|
|
|
142
199
|
].join("\n");
|
|
143
200
|
}
|
|
144
201
|
function emitInterfaces(result, ontologyName) {
|
|
145
|
-
const
|
|
202
|
+
const interfaces = orderedInterfacesForEmit(result.interfaces);
|
|
203
|
+
const body = interfaces.map(emitInterface).join("\n\n");
|
|
204
|
+
const links = interfaces.flatMap(emitInterfaceLinks).join("\n\n");
|
|
146
205
|
return [
|
|
147
206
|
header(ontologyName),
|
|
148
|
-
`import { defineInterface } from "@osdk/maker";`,
|
|
207
|
+
`import { defineInterface, defineInterfaceLinkConstraint } from "@osdk/maker";`,
|
|
208
|
+
...interfaceSharedPropertyImports(result),
|
|
149
209
|
"",
|
|
150
210
|
body,
|
|
211
|
+
links ? `\n${links}` : "",
|
|
151
212
|
"",
|
|
152
|
-
`export const INTERFACES = [${
|
|
213
|
+
`export const INTERFACES = [${interfaces.map((interfaceType) => interfaceType.variableName).join(", ")}] as const;`,
|
|
153
214
|
"",
|
|
154
215
|
].join("\n");
|
|
155
216
|
}
|
|
217
|
+
function interfaceSharedPropertyImports(result) {
|
|
218
|
+
const sharedPropertyNames = Array.from(new Set(result.interfaces.flatMap((interfaceType) => interfaceType.properties.flatMap((property) => property.sharedPropertyVariableName
|
|
219
|
+
? [property.sharedPropertyVariableName]
|
|
220
|
+
: []))));
|
|
221
|
+
return sharedPropertyNames.length === 0
|
|
222
|
+
? []
|
|
223
|
+
: [
|
|
224
|
+
`import { ${sharedPropertyNames.join(", ")} } from "./sharedProperties.mjs";`,
|
|
225
|
+
];
|
|
226
|
+
}
|
|
227
|
+
function orderedInterfacesForEmit(interfaces) {
|
|
228
|
+
const byApiName = new Map(interfaces.map((interfaceType) => [
|
|
229
|
+
interfaceType.apiName.sanitized,
|
|
230
|
+
interfaceType,
|
|
231
|
+
]));
|
|
232
|
+
const emitted = new Set();
|
|
233
|
+
const ordered = [];
|
|
234
|
+
const visit = (interfaceType) => {
|
|
235
|
+
if (emitted.has(interfaceType.apiName.sanitized)) {
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
emitted.add(interfaceType.apiName.sanitized);
|
|
239
|
+
for (const parent of interfaceType.extendsInterfaces) {
|
|
240
|
+
const parentInterface = byApiName.get(parent.apiName.sanitized);
|
|
241
|
+
if (parentInterface) {
|
|
242
|
+
visit(parentInterface);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
ordered.push(interfaceType);
|
|
246
|
+
};
|
|
247
|
+
for (const interfaceType of interfaces) {
|
|
248
|
+
visit(interfaceType);
|
|
249
|
+
}
|
|
250
|
+
return ordered;
|
|
251
|
+
}
|
|
156
252
|
function emitInterface(interfaceType) {
|
|
157
253
|
return [
|
|
158
254
|
entityComment(interfaceType.apiName, interfaceType.rid),
|
|
@@ -160,6 +256,10 @@ function emitInterface(interfaceType) {
|
|
|
160
256
|
apiName: interfaceType.apiName.sanitized,
|
|
161
257
|
description: interfaceType.description,
|
|
162
258
|
displayName: interfaceType.displayName,
|
|
259
|
+
extends: emitInterfaceExtends(interfaceType),
|
|
260
|
+
properties: interfaceType.properties.length > 0
|
|
261
|
+
? raw(`{\n${interfaceType.properties.map(emitInterfaceProperty).join(",\n")}\n\t}`)
|
|
262
|
+
: undefined,
|
|
163
263
|
searchable: interfaceType.searchable,
|
|
164
264
|
status: interfaceType.status
|
|
165
265
|
? { type: interfaceType.status }
|
|
@@ -167,14 +267,74 @@ function emitInterface(interfaceType) {
|
|
|
167
267
|
}, 0)});`,
|
|
168
268
|
].join("\n");
|
|
169
269
|
}
|
|
270
|
+
function emitInterfaceExtends(interfaceType) {
|
|
271
|
+
if (interfaceType.extendsInterfaces.length === 0) {
|
|
272
|
+
return undefined;
|
|
273
|
+
}
|
|
274
|
+
const [firstReference] = interfaceType.extendsInterfaces;
|
|
275
|
+
return raw(interfaceType.extendsInterfaces.length === 1 && firstReference
|
|
276
|
+
? firstReference.variableName
|
|
277
|
+
: `[${interfaceType.extendsInterfaces.map((reference) => reference.variableName).join(", ")}]`);
|
|
278
|
+
}
|
|
279
|
+
function emitInterfaceProperty(property) {
|
|
280
|
+
const value = property.sharedPropertyVariableName
|
|
281
|
+
? objectLiteral(raw(`{ sharedPropertyType: ${property.sharedPropertyVariableName}, required: ${property.required ? "true" : "false"} }`), 2)
|
|
282
|
+
: objectLiteral({
|
|
283
|
+
displayName: property.displayName,
|
|
284
|
+
required: property.required || undefined,
|
|
285
|
+
type: property.type,
|
|
286
|
+
}, 2);
|
|
287
|
+
return `\t\t${safePropertyKey(property.apiName.sanitized)}: ${value}`;
|
|
288
|
+
}
|
|
289
|
+
function emitInterfaceLinks(interfaceType) {
|
|
290
|
+
return interfaceType.links.map((link) => `defineInterfaceLinkConstraint(${objectLiteral({
|
|
291
|
+
apiName: link.apiName.sanitized,
|
|
292
|
+
description: link.description,
|
|
293
|
+
displayName: link.displayName,
|
|
294
|
+
from: raw(interfaceType.variableName),
|
|
295
|
+
required: link.required,
|
|
296
|
+
...(link.cardinality === "MANY"
|
|
297
|
+
? { toMany: raw(link.targetVariableName) }
|
|
298
|
+
: { toOne: raw(link.targetVariableName) }),
|
|
299
|
+
}, 0)});`);
|
|
300
|
+
}
|
|
170
301
|
function emitActions(result, ontologyName) {
|
|
302
|
+
const body = result.actions.map(emitAction).join("\n\n");
|
|
171
303
|
return [
|
|
172
304
|
header(ontologyName),
|
|
173
|
-
|
|
174
|
-
|
|
305
|
+
`import { defineAction } from "@osdk/maker";`,
|
|
306
|
+
"",
|
|
307
|
+
body,
|
|
308
|
+
"",
|
|
309
|
+
`export const ACTIONS = [${result.actions.map((action) => action.variableName).join(", ")}] as const;`,
|
|
175
310
|
"",
|
|
176
311
|
].join("\n");
|
|
177
312
|
}
|
|
313
|
+
function emitAction(action) {
|
|
314
|
+
return [
|
|
315
|
+
entityComment(action.apiName, undefined),
|
|
316
|
+
`export const ${action.variableName} = defineAction(${objectLiteral({
|
|
317
|
+
apiName: action.apiName.sanitized,
|
|
318
|
+
displayName: action.displayName,
|
|
319
|
+
parameters: action.parameters.map(emitActionParameter),
|
|
320
|
+
parameterOrdering: action.parameters.map((parameter) => parameter.id.sanitized),
|
|
321
|
+
rules: action.rules,
|
|
322
|
+
status: action.status ?? "active",
|
|
323
|
+
}, 0)});`,
|
|
324
|
+
].join("\n");
|
|
325
|
+
}
|
|
326
|
+
function emitActionParameter(parameter) {
|
|
327
|
+
return {
|
|
328
|
+
description: parameter.description,
|
|
329
|
+
displayName: parameter.displayName,
|
|
330
|
+
id: parameter.id.sanitized,
|
|
331
|
+
type: parameter.type,
|
|
332
|
+
validation: {
|
|
333
|
+
allowedValues: parameter.validationAllowedValues,
|
|
334
|
+
required: parameter.required,
|
|
335
|
+
},
|
|
336
|
+
};
|
|
337
|
+
}
|
|
178
338
|
function emitTypeGroups(result, ontologyName) {
|
|
179
339
|
return [
|
|
180
340
|
header(ontologyName),
|
|
@@ -261,3 +421,10 @@ function header(ontologyName) {
|
|
|
261
421
|
`// Source ontology: ${ontologyName}. Review diagnostics before treating this as hand-authored OAC.`,
|
|
262
422
|
].join("\n");
|
|
263
423
|
}
|
|
424
|
+
function packageSlug(value) {
|
|
425
|
+
return (value
|
|
426
|
+
.toLowerCase()
|
|
427
|
+
.match(/[a-z0-9]+/g)
|
|
428
|
+
?.join("-")
|
|
429
|
+
.slice(0, 100) || "imported-foundry-ontology");
|
|
430
|
+
}
|
|
@@ -1,3 +1,12 @@
|
|
|
1
|
-
import type { ConversionDiagnostic, FoundryInterface, NormalizedInterface } from "./types.js";
|
|
2
|
-
|
|
1
|
+
import type { ConversionDiagnostic, FoundryInterface, NormalizedInterface, NormalizedSharedProperty } from "./types.js";
|
|
2
|
+
interface InterfaceNormalizationContext {
|
|
3
|
+
readonly diagnostics: ConversionDiagnostic[];
|
|
4
|
+
readonly interfaceNameAllocator: (name: string) => string;
|
|
5
|
+
readonly sharedPropertiesByOriginalApiName: ReadonlyMap<string, NormalizedSharedProperty>;
|
|
6
|
+
readonly sharedPropertiesByRid: ReadonlyMap<string, NormalizedSharedProperty>;
|
|
7
|
+
readonly variableNameAllocator: (name: string) => string;
|
|
8
|
+
}
|
|
9
|
+
export declare function normalizeInterface(interfaceType: FoundryInterface, interfaceIndex: number, context: InterfaceNormalizationContext): NormalizedInterface;
|
|
10
|
+
export declare function addInterfaceReferences(interfaceType: FoundryInterface, normalized: NormalizedInterface, interfaceIndex: number, interfacesByApiName: ReadonlyMap<string, NormalizedInterface>, diagnostics: ConversionDiagnostic[]): NormalizedInterface;
|
|
11
|
+
export {};
|
|
3
12
|
//# sourceMappingURL=interfaces.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"interfaces.d.ts","sourceRoot":"","sources":["../../src/foundry-import/interfaces.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"interfaces.d.ts","sourceRoot":"","sources":["../../src/foundry-import/interfaces.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EACX,oBAAoB,EACpB,gBAAgB,EAChB,mBAAmB,EACnB,wBAAwB,EACxB,MAAM,YAAY,CAAC;AAQpB,UAAU,6BAA6B;IACtC,QAAQ,CAAC,WAAW,EAAE,oBAAoB,EAAE,CAAC;IAC7C,QAAQ,CAAC,sBAAsB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IAC1D,QAAQ,CAAC,iCAAiC,EAAE,WAAW,CACtD,MAAM,EACN,wBAAwB,CACxB,CAAC;IACF,QAAQ,CAAC,qBAAqB,EAAE,WAAW,CAAC,MAAM,EAAE,wBAAwB,CAAC,CAAC;IAC9E,QAAQ,CAAC,qBAAqB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;CACzD;AAOD,wBAAgB,kBAAkB,CACjC,aAAa,EAAE,gBAAgB,EAC/B,cAAc,EAAE,MAAM,EACtB,OAAO,EAAE,6BAA6B,GACpC,mBAAmB,CA2CrB;AAED,wBAAgB,sBAAsB,CACrC,aAAa,EAAE,gBAAgB,EAC/B,UAAU,EAAE,mBAAmB,EAC/B,cAAc,EAAE,MAAM,EACtB,mBAAmB,EAAE,WAAW,CAAC,MAAM,EAAE,mBAAmB,CAAC,EAC7D,WAAW,EAAE,oBAAoB,EAAE,GACjC,mBAAmB,CAkBrB"}
|
|
@@ -1,43 +1,151 @@
|
|
|
1
|
-
import { addSanitizationDiagnostic, sanitizeApiName, toPascalCase, } from "./names.js";
|
|
1
|
+
import { addSanitizationDiagnostic, createNameAllocator, sanitizeApiName, toPascalCase, } from "./names.js";
|
|
2
|
+
import { mapPropertyType } from "./property-types.js";
|
|
2
3
|
import { displayNameFor, normalizeDescription, normalizeStatus, requiredString, } from "./utils.js";
|
|
3
|
-
export function normalizeInterface(interfaceType, interfaceIndex,
|
|
4
|
-
const originalApiName = requiredString(interfaceType.apiName, `$.interfaces[${interfaceIndex}].apiName`, diagnostics, `Interface${interfaceIndex + 1}`);
|
|
5
|
-
const sanitizedApiName =
|
|
6
|
-
addSanitizationDiagnostic(diagnostics, `$.interfaces[${interfaceIndex}].apiName`, originalApiName, sanitizedApiName);
|
|
7
|
-
addInterfaceDiagnostics(interfaceType, interfaceIndex, originalApiName, diagnostics);
|
|
4
|
+
export function normalizeInterface(interfaceType, interfaceIndex, context) {
|
|
5
|
+
const originalApiName = requiredString(interfaceType.apiName, `$.interfaces[${interfaceIndex}].apiName`, context.diagnostics, `Interface${interfaceIndex + 1}`);
|
|
6
|
+
const sanitizedApiName = context.interfaceNameAllocator(sanitizeApiName(originalApiName, "api"));
|
|
7
|
+
addSanitizationDiagnostic(context.diagnostics, `$.interfaces[${interfaceIndex}].apiName`, originalApiName, sanitizedApiName);
|
|
8
8
|
return {
|
|
9
9
|
apiName: { original: originalApiName, sanitized: sanitizedApiName },
|
|
10
10
|
description: normalizeDescription(interfaceType.displayMetadata?.description),
|
|
11
11
|
displayName: displayNameFor(interfaceType.displayMetadata, sanitizedApiName),
|
|
12
|
+
extendsInterfaces: [],
|
|
13
|
+
links: [],
|
|
14
|
+
properties: normalizeInterfaceProperties(interfaceType, interfaceIndex, context),
|
|
12
15
|
rid: interfaceType.rid,
|
|
13
16
|
searchable: interfaceType.searchable ?? false,
|
|
14
|
-
status: normalizeStatus(interfaceType.status, `$.interfaces[${interfaceIndex}].status`, diagnostics),
|
|
15
|
-
variableName: variableNameAllocator(`${toPascalCase(sanitizedApiName)}Interface`),
|
|
17
|
+
status: normalizeStatus(interfaceType.status, `$.interfaces[${interfaceIndex}].status`, context.diagnostics),
|
|
18
|
+
variableName: context.variableNameAllocator(`${toPascalCase(sanitizedApiName)}Interface`),
|
|
16
19
|
};
|
|
17
20
|
}
|
|
18
|
-
function
|
|
19
|
-
|
|
20
|
-
|
|
21
|
+
export function addInterfaceReferences(interfaceType, normalized, interfaceIndex, interfacesByApiName, diagnostics) {
|
|
22
|
+
return {
|
|
23
|
+
...normalized,
|
|
24
|
+
extendsInterfaces: normalizeInterfaceExtends(interfaceType, normalized, interfaceIndex, interfacesByApiName, diagnostics),
|
|
25
|
+
links: normalizeInterfaceLinks(interfaceType, normalized, interfaceIndex, interfacesByApiName, diagnostics),
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
function normalizeInterfaceProperties(interfaceType, interfaceIndex, context) {
|
|
29
|
+
const propertyNameAllocator = createNameAllocator();
|
|
30
|
+
return (interfaceType.properties ?? []).map((property, propertyIndex) => normalizeInterfaceProperty(property, propertyIndex, interfaceIndex, propertyNameAllocator, context));
|
|
31
|
+
}
|
|
32
|
+
function normalizeInterfaceProperty(property, propertyIndex, interfaceIndex, propertyNameAllocator, context) {
|
|
33
|
+
const path = `$.interfaces[${interfaceIndex}].properties[${propertyIndex}]`;
|
|
34
|
+
const original = requiredString(property.apiName, `${path}.apiName`, context.diagnostics, `property${propertyIndex + 1}`);
|
|
35
|
+
const sharedProperty = interfaceSharedProperty(property, original, context);
|
|
36
|
+
return sharedProperty
|
|
37
|
+
? sharedInterfaceProperty(property, sharedProperty)
|
|
38
|
+
: inlineInterfaceProperty(property, original, path, propertyNameAllocator, context);
|
|
39
|
+
}
|
|
40
|
+
function interfaceSharedProperty(property, original, context) {
|
|
41
|
+
return ((property.sharedPropertyRid
|
|
42
|
+
? context.sharedPropertiesByRid.get(property.sharedPropertyRid)
|
|
43
|
+
: undefined) ??
|
|
44
|
+
context.sharedPropertiesByOriginalApiName.get(original) ??
|
|
45
|
+
context.sharedPropertiesByOriginalApiName.get(sanitizeApiName(original, "api")));
|
|
46
|
+
}
|
|
47
|
+
function sharedInterfaceProperty(property, sharedProperty) {
|
|
48
|
+
return {
|
|
49
|
+
apiName: sharedProperty.apiName,
|
|
50
|
+
displayName: property.displayName ?? sharedProperty.apiName.sanitized,
|
|
51
|
+
required: property.required ?? false,
|
|
52
|
+
sharedPropertyVariableName: sharedProperty.variableName,
|
|
53
|
+
type: undefined,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
function inlineInterfaceProperty(property, original, path, propertyNameAllocator, context) {
|
|
57
|
+
const apiName = normalizeInterfacePropertyApiName(original, path, propertyNameAllocator, context.diagnostics);
|
|
58
|
+
return {
|
|
59
|
+
apiName,
|
|
60
|
+
displayName: property.displayName ?? apiName.sanitized,
|
|
61
|
+
required: property.required ?? false,
|
|
62
|
+
sharedPropertyVariableName: undefined,
|
|
63
|
+
type: mapPropertyType(property.type, `${path}.type`, context.diagnostics)
|
|
64
|
+
.type,
|
|
65
|
+
};
|
|
21
66
|
}
|
|
22
|
-
function
|
|
23
|
-
|
|
24
|
-
|
|
67
|
+
function normalizeInterfacePropertyApiName(original, path, nameAllocator, diagnostics) {
|
|
68
|
+
const sanitized = nameAllocator(sanitizeApiName(original, "api"));
|
|
69
|
+
addSanitizationDiagnostic(diagnostics, `${path}.apiName`, original, sanitized);
|
|
70
|
+
return { original, sanitized };
|
|
71
|
+
}
|
|
72
|
+
function normalizeInterfaceExtends(interfaceType, normalized, interfaceIndex, interfacesByApiName, diagnostics) {
|
|
73
|
+
return (interfaceType.extendsInterfaces ?? []).flatMap((apiName, index) => {
|
|
74
|
+
const target = interfacesByApiName.get(apiName);
|
|
75
|
+
if (target) {
|
|
76
|
+
return [
|
|
77
|
+
{
|
|
78
|
+
apiName: target.apiName,
|
|
79
|
+
variableName: target.variableName,
|
|
80
|
+
},
|
|
81
|
+
];
|
|
82
|
+
}
|
|
83
|
+
diagnostics.push({
|
|
84
|
+
code: "skipped.interfaceExtends",
|
|
85
|
+
message: `Interface ${normalized.apiName.original} extends missing interface ${apiName}; extension was not emitted.`,
|
|
86
|
+
path: `$.interfaces[${interfaceIndex}].extendsInterfaces[${index}]`,
|
|
87
|
+
severity: "warning",
|
|
88
|
+
});
|
|
89
|
+
return [];
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
function normalizeInterfaceLinks(interfaceType, normalized, interfaceIndex, interfacesByApiName, diagnostics) {
|
|
93
|
+
const linkNameAllocator = createNameAllocator();
|
|
94
|
+
return (interfaceType.links ?? []).flatMap((link, linkIndex) => normalizeInterfaceLink(link, linkIndex, normalized, interfaceIndex, linkNameAllocator, interfacesByApiName, diagnostics));
|
|
95
|
+
}
|
|
96
|
+
function normalizeInterfaceLink(link, linkIndex, normalized, interfaceIndex, linkNameAllocator, interfacesByApiName, diagnostics) {
|
|
97
|
+
const path = `$.interfaces[${interfaceIndex}].links[${linkIndex}]`;
|
|
98
|
+
const target = resolveInterfaceLinkTarget(link, linkIndex, normalized, path, interfacesByApiName, diagnostics);
|
|
99
|
+
if (!target) {
|
|
100
|
+
return [];
|
|
101
|
+
}
|
|
102
|
+
const original = requiredString(link.apiName, `${path}.apiName`, diagnostics, `link${linkIndex + 1}`);
|
|
103
|
+
const sanitized = linkNameAllocator(sanitizeApiName(original, "api"));
|
|
104
|
+
addSanitizationDiagnostic(diagnostics, `${path}.apiName`, original, sanitized);
|
|
105
|
+
return [
|
|
106
|
+
{
|
|
107
|
+
apiName: { original, sanitized },
|
|
108
|
+
cardinality: interfaceLinkCardinality(link),
|
|
109
|
+
description: normalizeDescription(link.description),
|
|
110
|
+
displayName: link.displayName ?? sanitized,
|
|
111
|
+
required: link.required,
|
|
112
|
+
targetApiName: target.apiName,
|
|
113
|
+
targetVariableName: target.variableName,
|
|
114
|
+
},
|
|
115
|
+
];
|
|
116
|
+
}
|
|
117
|
+
function resolveInterfaceLinkTarget(link, linkIndex, normalized, path, interfacesByApiName, diagnostics) {
|
|
118
|
+
if (unsupportedInterfaceLinkTarget(link)) {
|
|
119
|
+
addSkippedInterfaceLinkDiagnostic(link, linkIndex, normalized, path, diagnostics);
|
|
120
|
+
return undefined;
|
|
25
121
|
}
|
|
122
|
+
const target = link.linkedEntityApiName
|
|
123
|
+
? interfacesByApiName.get(link.linkedEntityApiName)
|
|
124
|
+
: undefined;
|
|
125
|
+
if (!target) {
|
|
126
|
+
addMissingInterfaceLinkTargetDiagnostic(link, linkIndex, normalized, path, diagnostics);
|
|
127
|
+
}
|
|
128
|
+
return target;
|
|
129
|
+
}
|
|
130
|
+
function unsupportedInterfaceLinkTarget(link) {
|
|
131
|
+
return Boolean(link.linkedEntityType && link.linkedEntityType !== "interfaceTypeApiName");
|
|
132
|
+
}
|
|
133
|
+
function addSkippedInterfaceLinkDiagnostic(link, linkIndex, normalized, path, diagnostics) {
|
|
26
134
|
diagnostics.push({
|
|
27
|
-
code: "
|
|
28
|
-
message: `Interface ${apiName}
|
|
29
|
-
path
|
|
135
|
+
code: "skipped.interfaceLinkTarget",
|
|
136
|
+
message: `Interface ${normalized.apiName.original} link ${link.apiName ?? linkIndex} targets ${link.linkedEntityType}; only interface targets are emitted.`,
|
|
137
|
+
path,
|
|
30
138
|
severity: "warning",
|
|
31
139
|
});
|
|
32
140
|
}
|
|
33
|
-
function
|
|
34
|
-
if ((interfaceType.properties?.length ?? 0) === 0) {
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
141
|
+
function addMissingInterfaceLinkTargetDiagnostic(link, linkIndex, normalized, path, diagnostics) {
|
|
37
142
|
diagnostics.push({
|
|
38
|
-
code: "
|
|
39
|
-
message: `Interface ${apiName}
|
|
40
|
-
path
|
|
143
|
+
code: "skipped.interfaceLinkTarget",
|
|
144
|
+
message: `Interface ${normalized.apiName.original} link ${link.apiName ?? linkIndex} targets missing interface ${link.linkedEntityApiName ?? "unknown"}; link was not emitted.`,
|
|
145
|
+
path,
|
|
41
146
|
severity: "warning",
|
|
42
147
|
});
|
|
43
148
|
}
|
|
149
|
+
function interfaceLinkCardinality(link) {
|
|
150
|
+
return link.cardinality === "MANY" ? "MANY" : "SINGLE";
|
|
151
|
+
}
|
|
@@ -2,6 +2,7 @@ import type { ConversionDiagnostic, NamePair } from "./types.js";
|
|
|
2
2
|
type ApiNameMode = "api" | "object";
|
|
3
3
|
export declare function addSanitizationDiagnostic(diagnostics: ConversionDiagnostic[], path: string, original: string, sanitized: string): void;
|
|
4
4
|
export declare function sanitizeApiName(name: string, mode: ApiNameMode): string;
|
|
5
|
+
export declare function sanitizeActionApiName(name: string): string;
|
|
5
6
|
export declare function createNameAllocator(): (name: string) => string;
|
|
6
7
|
export declare function entityComment(name: NamePair, rid: string | undefined): string;
|
|
7
8
|
export declare function safePropertyKey(key: string): string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"names.d.ts","sourceRoot":"","sources":["../../src/foundry-import/names.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"names.d.ts","sourceRoot":"","sources":["../../src/foundry-import/names.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAiBjE,KAAK,WAAW,GAAG,KAAK,GAAG,QAAQ,CAAC;AAEpC,wBAAgB,yBAAyB,CACxC,WAAW,EAAE,oBAAoB,EAAE,EACnC,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,GACf,IAAI,CAUN;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,GAAG,MAAM,CAMvE;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAmB1D;AAED,wBAAgB,mBAAmB,IAAI,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAO9D;AAQD,wBAAgB,aAAa,CAAC,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAI7E;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAGlD"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const objectApiNamePattern = /^[a-zA-Z][a-zA-Z0-9]{0,99}$/;
|
|
2
2
|
const apiNamePattern = /^[a-zA-Z][a-zA-Z0-9_]{0,99}$/;
|
|
3
|
+
const actionApiNamePattern = /^[a-z0-9]+(-[a-z0-9]+)*$/;
|
|
3
4
|
const reservedApiNames = new Set([
|
|
4
5
|
"ontology",
|
|
5
6
|
"object",
|
|
@@ -29,6 +30,23 @@ export function sanitizeApiName(name, mode) {
|
|
|
29
30
|
}
|
|
30
31
|
return prefixedApiName(candidate, mode);
|
|
31
32
|
}
|
|
33
|
+
export function sanitizeActionApiName(name) {
|
|
34
|
+
const words = name
|
|
35
|
+
.replace(/([a-z0-9])([A-Z])/g, "$1 $2")
|
|
36
|
+
.replace(/([A-Z])([A-Z][a-z])/g, "$1 $2")
|
|
37
|
+
.match(/[a-zA-Z0-9]+/g)
|
|
38
|
+
?.map((word) => word.toLowerCase())
|
|
39
|
+
.filter((word) => word.length > 0) ?? ["imported"];
|
|
40
|
+
const candidate = words
|
|
41
|
+
.join("-")
|
|
42
|
+
.replace(/^-+|-+$/g, "")
|
|
43
|
+
.slice(0, 100);
|
|
44
|
+
if (actionApiNamePattern.test(candidate)) {
|
|
45
|
+
return candidate;
|
|
46
|
+
}
|
|
47
|
+
const fallback = `imported-${candidate.replace(/^[^a-z0-9]+/, "")}`.slice(0, 100);
|
|
48
|
+
return actionApiNamePattern.test(fallback) ? fallback : "imported-action";
|
|
49
|
+
}
|
|
32
50
|
export function createNameAllocator() {
|
|
33
51
|
const seen = new Map();
|
|
34
52
|
return (name) => {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import type { ConversionDiagnostic, FoundryObjectType, NormalizedObject } from "./types.js";
|
|
1
|
+
import type { ConversionDiagnostic, FoundryObjectType, NormalizedInterface, NormalizedObject } from "./types.js";
|
|
2
2
|
interface ObjectNormalizationContext {
|
|
3
3
|
readonly diagnostics: ConversionDiagnostic[];
|
|
4
|
+
readonly interfacesByApiName: ReadonlyMap<string, NormalizedInterface>;
|
|
4
5
|
readonly objectNameAllocator: (name: string) => string;
|
|
5
6
|
readonly variableNameAllocator: (name: string) => string;
|
|
6
7
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"objects.d.ts","sourceRoot":"","sources":["../../src/foundry-import/objects.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EACX,oBAAoB,EACpB,iBAAiB,EACjB,gBAAgB,EAChB,MAAM,YAAY,CAAC;AAQpB,UAAU,0BAA0B;IACnC,QAAQ,CAAC,WAAW,EAAE,oBAAoB,EAAE,CAAC;IAC7C,QAAQ,CAAC,mBAAmB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IACvD,QAAQ,CAAC,qBAAqB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;CACzD;AAED,wBAAgB,eAAe,CAC9B,UAAU,EAAE,iBAAiB,EAC7B,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,0BAA0B,GACjC,gBAAgB,
|
|
1
|
+
{"version":3,"file":"objects.d.ts","sourceRoot":"","sources":["../../src/foundry-import/objects.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EACX,oBAAoB,EACpB,iBAAiB,EACjB,mBAAmB,EACnB,gBAAgB,EAChB,MAAM,YAAY,CAAC;AAQpB,UAAU,0BAA0B;IACnC,QAAQ,CAAC,WAAW,EAAE,oBAAoB,EAAE,CAAC;IAC7C,QAAQ,CAAC,mBAAmB,EAAE,WAAW,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;IACvE,QAAQ,CAAC,mBAAmB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IACvD,QAAQ,CAAC,qBAAqB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;CACzD;AAED,wBAAgB,eAAe,CAC9B,UAAU,EAAE,iBAAiB,EAC7B,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,0BAA0B,GACjC,gBAAgB,CA6DlB"}
|
|
@@ -13,6 +13,8 @@ export function normalizeObject(objectType, objectIndex, context) {
|
|
|
13
13
|
apiName,
|
|
14
14
|
description: objectDescription(objectType),
|
|
15
15
|
displayName: objectDisplayName(objectType, apiName.sanitized),
|
|
16
|
+
id: objectType.id,
|
|
17
|
+
interfaceImplementations: normalizeInterfaceImplementations(objectType, objectIndex, apiName.original, properties, context),
|
|
16
18
|
pluralDisplayName: pluralDisplayNameFor(objectType, apiName.sanitized),
|
|
17
19
|
primaryKeyPropertyApiName: keyPropertyApiName(keys.primaryKeyProperty, fallbackProperty),
|
|
18
20
|
properties,
|
|
@@ -57,20 +59,100 @@ function normalizeObjectProperties(objectType, objectIndex, context) {
|
|
|
57
59
|
return (objectType.properties ?? []).map((property, propertyIndex) => normalizeProperty(property, `$.objectTypes[${objectIndex}].properties[${propertyIndex}]`, propertyNameAllocator, context.diagnostics));
|
|
58
60
|
}
|
|
59
61
|
function addObjectMetadataDiagnostics(objectType, objectIndex, apiName, diagnostics) {
|
|
60
|
-
addObjectInterfacesDiagnostic(objectType, objectIndex, apiName, diagnostics);
|
|
61
62
|
addObjectTypeGroupsDiagnostic(objectType, objectIndex, apiName, diagnostics);
|
|
62
63
|
}
|
|
63
|
-
function
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
64
|
+
function normalizeInterfaceImplementations(objectType, objectIndex, apiName, properties, context) {
|
|
65
|
+
const implementations = objectInterfaceImplementations(objectType);
|
|
66
|
+
const propertiesByApiName = indexPropertiesByApiName(properties);
|
|
67
|
+
return implementations.flatMap((implementation, implementationIndex) => {
|
|
68
|
+
const path = `$.objectTypes[${objectIndex}].interfaces[${implementationIndex}]`;
|
|
69
|
+
const interfaceType = context.interfacesByApiName.get(implementation.interfaceApiName);
|
|
70
|
+
if (!interfaceType) {
|
|
71
|
+
context.diagnostics.push({
|
|
72
|
+
code: "skipped.objectInterfaceImplementation",
|
|
73
|
+
message: `Object ${apiName} implements missing interface ${implementation.interfaceApiName}; implementation was not emitted.`,
|
|
74
|
+
path,
|
|
75
|
+
severity: "warning",
|
|
76
|
+
});
|
|
77
|
+
return [];
|
|
78
|
+
}
|
|
79
|
+
const mappedProperties = implementation.propertyMappings.flatMap((mapping, mappingIndex) => normalizeInterfacePropertyMapping(mapping, mappingIndex, path, apiName, interfaceType, propertiesByApiName, context.diagnostics));
|
|
80
|
+
const missingProperties = flattenedInterfaceProperties(interfaceType, context.interfacesByApiName).filter((property) => !mappedProperties.some((mapping) => mapping.interfacePropertyApiName === property.apiName.sanitized));
|
|
81
|
+
if (missingProperties.length > 0) {
|
|
82
|
+
context.diagnostics.push({
|
|
83
|
+
code: "skipped.objectInterfaceImplementation",
|
|
84
|
+
message: `Object ${apiName} implementation of ${interfaceType.apiName.original} is missing mappings for ${missingProperties.map((property) => property.apiName.original).join(", ")}; implementation was not emitted.`,
|
|
85
|
+
path,
|
|
86
|
+
severity: "warning",
|
|
87
|
+
});
|
|
88
|
+
return [];
|
|
89
|
+
}
|
|
90
|
+
return [
|
|
91
|
+
{
|
|
92
|
+
interfaceApiName: interfaceType.apiName,
|
|
93
|
+
interfaceVariableName: interfaceType.variableName,
|
|
94
|
+
propertyMappings: mappedProperties,
|
|
95
|
+
},
|
|
96
|
+
];
|
|
72
97
|
});
|
|
73
98
|
}
|
|
99
|
+
function objectInterfaceImplementations(objectType) {
|
|
100
|
+
const explicit = objectType.interfaceImplementations ?? [];
|
|
101
|
+
if (explicit.length > 0) {
|
|
102
|
+
return explicit;
|
|
103
|
+
}
|
|
104
|
+
return (objectType.interfaces ?? []).map((interfaceApiName) => ({
|
|
105
|
+
interfaceApiName,
|
|
106
|
+
propertyMappings: [],
|
|
107
|
+
}));
|
|
108
|
+
}
|
|
109
|
+
function indexPropertiesByApiName(properties) {
|
|
110
|
+
const index = new Map();
|
|
111
|
+
for (const property of properties) {
|
|
112
|
+
index.set(property.originalId, property);
|
|
113
|
+
index.set(property.apiName.original, property);
|
|
114
|
+
index.set(property.apiName.sanitized, property);
|
|
115
|
+
}
|
|
116
|
+
return index;
|
|
117
|
+
}
|
|
118
|
+
function normalizeInterfacePropertyMapping(mapping, mappingIndex, path, objectApiName, interfaceType, propertiesByApiName, diagnostics) {
|
|
119
|
+
const interfaceProperty = interfacePropertyByApiName(interfaceType, mapping.interfacePropertyApiName);
|
|
120
|
+
const objectProperty = propertiesByApiName.get(mapping.objectPropertyApiName);
|
|
121
|
+
if (!interfaceProperty || !objectProperty) {
|
|
122
|
+
diagnostics.push({
|
|
123
|
+
code: "skipped.objectInterfacePropertyMapping",
|
|
124
|
+
message: `Object ${objectApiName} has an unresolved interface mapping ${mapping.interfacePropertyApiName} -> ${mapping.objectPropertyApiName}.`,
|
|
125
|
+
path: `${path}.propertyMappings[${mappingIndex}]`,
|
|
126
|
+
severity: "warning",
|
|
127
|
+
});
|
|
128
|
+
return [];
|
|
129
|
+
}
|
|
130
|
+
return [
|
|
131
|
+
{
|
|
132
|
+
interfacePropertyApiName: interfaceProperty.apiName.sanitized,
|
|
133
|
+
objectPropertyApiName: objectProperty.apiName.sanitized,
|
|
134
|
+
},
|
|
135
|
+
];
|
|
136
|
+
}
|
|
137
|
+
function interfacePropertyByApiName(interfaceType, apiName) {
|
|
138
|
+
return interfaceType.properties.find((property) => property.apiName.original === apiName ||
|
|
139
|
+
property.apiName.sanitized === apiName);
|
|
140
|
+
}
|
|
141
|
+
function flattenedInterfaceProperties(interfaceType, interfacesByApiName, seen = new Set()) {
|
|
142
|
+
if (seen.has(interfaceType.apiName.sanitized)) {
|
|
143
|
+
return interfaceType.properties;
|
|
144
|
+
}
|
|
145
|
+
seen.add(interfaceType.apiName.sanitized);
|
|
146
|
+
return [
|
|
147
|
+
...interfaceType.extendsInterfaces.flatMap((reference) => {
|
|
148
|
+
const extended = interfacesByApiName.get(reference.apiName.original);
|
|
149
|
+
return extended
|
|
150
|
+
? flattenedInterfaceProperties(extended, interfacesByApiName, seen)
|
|
151
|
+
: [];
|
|
152
|
+
}),
|
|
153
|
+
...interfaceType.properties,
|
|
154
|
+
];
|
|
155
|
+
}
|
|
74
156
|
function addObjectTypeGroupsDiagnostic(objectType, objectIndex, apiName, diagnostics) {
|
|
75
157
|
if ((objectType.typeGroups?.length ?? 0) === 0) {
|
|
76
158
|
return;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../../src/foundry-import/parse.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../../src/foundry-import/parse.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,oBAAoB,EAYpB,eAAe,EACf,MAAM,YAAY,CAAC;AAOpB,wBAAgB,oBAAoB,CACnC,KAAK,EAAE,OAAO,EACd,WAAW,EAAE,oBAAoB,EAAE,GACjC,eAAe,CAkBjB"}
|