@nyrra/prismantix-cli 0.0.4-next.20 → 0.0.4-next.22

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 (54) hide show
  1. package/README.md +14 -0
  2. package/dist/commands/foundry/import.d.ts +17 -0
  3. package/dist/commands/foundry/import.d.ts.map +1 -0
  4. package/dist/commands/foundry/import.js +94 -0
  5. package/dist/constants.d.ts +1 -0
  6. package/dist/constants.d.ts.map +1 -1
  7. package/dist/constants.js +1 -0
  8. package/dist/foundry-import/actions.d.ts +3 -0
  9. package/dist/foundry-import/actions.d.ts.map +1 -0
  10. package/dist/foundry-import/actions.js +37 -0
  11. package/dist/foundry-import/convert.d.ts +3 -0
  12. package/dist/foundry-import/convert.d.ts.map +1 -0
  13. package/dist/foundry-import/convert.js +47 -0
  14. package/dist/foundry-import/emit.d.ts +3 -0
  15. package/dist/foundry-import/emit.d.ts.map +1 -0
  16. package/dist/foundry-import/emit.js +263 -0
  17. package/dist/foundry-import/interfaces.d.ts +3 -0
  18. package/dist/foundry-import/interfaces.d.ts.map +1 -0
  19. package/dist/foundry-import/interfaces.js +43 -0
  20. package/dist/foundry-import/names.d.ts +10 -0
  21. package/dist/foundry-import/names.d.ts.map +1 -0
  22. package/dist/foundry-import/names.js +83 -0
  23. package/dist/foundry-import/objects.d.ts +9 -0
  24. package/dist/foundry-import/objects.d.ts.map +1 -0
  25. package/dist/foundry-import/objects.js +128 -0
  26. package/dist/foundry-import/parse.d.ts +3 -0
  27. package/dist/foundry-import/parse.d.ts.map +1 -0
  28. package/dist/foundry-import/parse.js +28 -0
  29. package/dist/foundry-import/properties.d.ts +4 -0
  30. package/dist/foundry-import/properties.d.ts.map +1 -0
  31. package/dist/foundry-import/properties.js +83 -0
  32. package/dist/foundry-import/property-types.d.ts +7 -0
  33. package/dist/foundry-import/property-types.d.ts.map +1 -0
  34. package/dist/foundry-import/property-types.js +77 -0
  35. package/dist/foundry-import/relations.d.ts +11 -0
  36. package/dist/foundry-import/relations.d.ts.map +1 -0
  37. package/dist/foundry-import/relations.js +204 -0
  38. package/dist/foundry-import/types.d.ts +335 -0
  39. package/dist/foundry-import/types.d.ts.map +1 -0
  40. package/dist/foundry-import/types.js +1 -0
  41. package/dist/foundry-import/utils.d.ts +13 -0
  42. package/dist/foundry-import/utils.d.ts.map +1 -0
  43. package/dist/foundry-import/utils.js +82 -0
  44. package/dist/foundry-import/validate.d.ts +8 -0
  45. package/dist/foundry-import/validate.d.ts.map +1 -0
  46. package/dist/foundry-import/validate.js +117 -0
  47. package/dist/foundry-import/workflow.d.ts +3 -0
  48. package/dist/foundry-import/workflow.d.ts.map +1 -0
  49. package/dist/foundry-import/workflow.js +104 -0
  50. package/dist/foundry-import.d.ts +3 -0
  51. package/dist/foundry-import.d.ts.map +1 -0
  52. package/dist/foundry-import.js +1 -0
  53. package/oclif.manifest.json +62 -1
  54. package/package.json +6 -3
@@ -0,0 +1,83 @@
1
+ const objectApiNamePattern = /^[a-zA-Z][a-zA-Z0-9]{0,99}$/;
2
+ const apiNamePattern = /^[a-zA-Z][a-zA-Z0-9_]{0,99}$/;
3
+ const reservedApiNames = new Set([
4
+ "ontology",
5
+ "object",
6
+ "property",
7
+ "link",
8
+ "relation",
9
+ "rid",
10
+ "primarykey",
11
+ "typeid",
12
+ "ontologyobject",
13
+ ]);
14
+ export function addSanitizationDiagnostic(diagnostics, path, original, sanitized) {
15
+ if (original === sanitized) {
16
+ return;
17
+ }
18
+ diagnostics.push({
19
+ code: "coerced.apiName",
20
+ message: `API name ${original} was emitted as ${sanitized}.`,
21
+ path,
22
+ severity: "warning",
23
+ });
24
+ }
25
+ export function sanitizeApiName(name, mode) {
26
+ const candidate = sanitizedCandidate(name, mode);
27
+ if (isAllowedApiName(candidate, mode)) {
28
+ return candidate;
29
+ }
30
+ return prefixedApiName(candidate, mode);
31
+ }
32
+ export function createNameAllocator() {
33
+ const seen = new Map();
34
+ return (name) => {
35
+ const count = seen.get(name) ?? 0;
36
+ seen.set(name, count + 1);
37
+ return count === 0 ? name : `${name}${count + 1}`;
38
+ };
39
+ }
40
+ function originalComment(name) {
41
+ return name.original === name.sanitized
42
+ ? `// ${name.original}`
43
+ : `// ${name.original} -> ${name.sanitized}`;
44
+ }
45
+ export function entityComment(name, rid) {
46
+ return rid
47
+ ? `${originalComment(name)}\n// rid: ${rid}`
48
+ : originalComment(name);
49
+ }
50
+ export function safePropertyKey(key) {
51
+ return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(key) ? key : JSON.stringify(key);
52
+ }
53
+ export function toPascalCase(value) {
54
+ const words = value.match(/[a-zA-Z0-9]+/g) ?? ["Imported"];
55
+ return words.map(capitalize).join("") || "Imported";
56
+ }
57
+ function capitalize(value) {
58
+ return value.length === 0
59
+ ? value
60
+ : `${value[0]?.toUpperCase() ?? ""}${value.slice(1)}`;
61
+ }
62
+ function sanitizedCandidate(name, mode) {
63
+ const words = name.match(/[a-zA-Z0-9]+/g) ?? ["Imported"];
64
+ const joined = mode === "object" ? objectName(words) : apiName(words);
65
+ return (joined === "" ? "Imported" : joined).slice(0, 100);
66
+ }
67
+ function objectName(words) {
68
+ return words.map(capitalize).join("");
69
+ }
70
+ function apiName(words) {
71
+ const [firstWord = "imported", ...remainingWords] = words;
72
+ return `${firstWord.replace(/^[0-9]+/, "")}${remainingWords
73
+ .map(capitalize)
74
+ .join("")}`;
75
+ }
76
+ function isAllowedApiName(candidate, mode) {
77
+ const pattern = mode === "object" ? objectApiNamePattern : apiNamePattern;
78
+ return (pattern.test(candidate) && !reservedApiNames.has(candidate.toLowerCase()));
79
+ }
80
+ function prefixedApiName(candidate, mode) {
81
+ const prefix = mode === "object" ? "Imported" : "imported";
82
+ return `${prefix}${capitalize(candidate)}`.slice(0, 100);
83
+ }
@@ -0,0 +1,9 @@
1
+ import type { ConversionDiagnostic, FoundryObjectType, NormalizedObject } from "./types.js";
2
+ interface ObjectNormalizationContext {
3
+ readonly diagnostics: ConversionDiagnostic[];
4
+ readonly objectNameAllocator: (name: string) => string;
5
+ readonly variableNameAllocator: (name: string) => string;
6
+ }
7
+ export declare function normalizeObject(objectType: FoundryObjectType, objectIndex: number, context: ObjectNormalizationContext): NormalizedObject;
8
+ export {};
9
+ //# sourceMappingURL=objects.d.ts.map
@@ -0,0 +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,CAiDlB"}
@@ -0,0 +1,128 @@
1
+ import { addSanitizationDiagnostic, createNameAllocator, sanitizeApiName, toPascalCase, } from "./names.js";
2
+ import { normalizeProperty } from "./properties.js";
3
+ import { displayNameFor, normalizeDescription, normalizeStatus, requiredString, } from "./utils.js";
4
+ export function normalizeObject(objectType, objectIndex, context) {
5
+ const apiName = normalizeObjectApiName(objectType, objectIndex, context.objectNameAllocator, context.diagnostics);
6
+ const properties = normalizeObjectProperties(objectType, objectIndex, context);
7
+ const propertiesById = new Map(properties.map((property) => [property.originalId, property]));
8
+ addObjectMetadataDiagnostics(objectType, objectIndex, apiName.original, context.diagnostics);
9
+ const keys = resolveObjectKeys(objectType, propertiesById);
10
+ addKeyDiagnostics(objectType, objectIndex, apiName.original, keys.primaryKeyProperty, keys.titleProperty, context.diagnostics);
11
+ const fallbackProperty = properties[0];
12
+ return {
13
+ apiName,
14
+ description: objectDescription(objectType),
15
+ displayName: objectDisplayName(objectType, apiName.sanitized),
16
+ pluralDisplayName: pluralDisplayNameFor(objectType, apiName.sanitized),
17
+ primaryKeyPropertyApiName: keyPropertyApiName(keys.primaryKeyProperty, fallbackProperty),
18
+ properties,
19
+ propertiesById,
20
+ rid: objectType.rid,
21
+ status: normalizeStatus(objectType.status),
22
+ titlePropertyApiName: titlePropertyApiName(keys, fallbackProperty),
23
+ variableName: context.variableNameAllocator(toPascalCase(apiName.sanitized)),
24
+ };
25
+ }
26
+ function normalizeObjectApiName(objectType, objectIndex, nameAllocator, diagnostics) {
27
+ const original = requiredString(objectType.apiName, `$.objectTypes[${objectIndex}].apiName`, diagnostics, `Object${objectIndex + 1}`);
28
+ const sanitized = nameAllocator(sanitizeApiName(original, "object"));
29
+ addSanitizationDiagnostic(diagnostics, `$.objectTypes[${objectIndex}].apiName`, original, sanitized);
30
+ return { original, sanitized };
31
+ }
32
+ function pluralDisplayNameFor(objectType, apiName) {
33
+ return (objectType.displayMetadata?.pluralDisplayName ??
34
+ `${displayNameFor(objectType.displayMetadata, apiName)}s`);
35
+ }
36
+ function resolveObjectKeys(objectType, propertiesById) {
37
+ return {
38
+ primaryKeyProperty: resolveProperty(objectType.primaryKeys?.[0], propertiesById),
39
+ titleProperty: resolveProperty(objectType.titlePropertyId, propertiesById),
40
+ };
41
+ }
42
+ function objectDescription(objectType) {
43
+ return normalizeDescription(objectType.displayMetadata?.description);
44
+ }
45
+ function objectDisplayName(objectType, apiName) {
46
+ return displayNameFor(objectType.displayMetadata, apiName);
47
+ }
48
+ function keyPropertyApiName(property, fallbackProperty) {
49
+ return (property ?? fallbackProperty)?.apiName.sanitized ?? "id";
50
+ }
51
+ function titlePropertyApiName(keys, fallbackProperty) {
52
+ return ((keys.titleProperty ?? keys.primaryKeyProperty ?? fallbackProperty)?.apiName
53
+ .sanitized ?? "id");
54
+ }
55
+ function normalizeObjectProperties(objectType, objectIndex, context) {
56
+ const propertyNameAllocator = createNameAllocator();
57
+ return (objectType.properties ?? []).map((property, propertyIndex) => normalizeProperty(property, `$.objectTypes[${objectIndex}].properties[${propertyIndex}]`, propertyNameAllocator, context.diagnostics));
58
+ }
59
+ function addObjectMetadataDiagnostics(objectType, objectIndex, apiName, diagnostics) {
60
+ addObjectInterfacesDiagnostic(objectType, objectIndex, apiName, diagnostics);
61
+ addObjectTypeGroupsDiagnostic(objectType, objectIndex, apiName, diagnostics);
62
+ }
63
+ function addObjectInterfacesDiagnostic(objectType, objectIndex, apiName, diagnostics) {
64
+ if ((objectType.interfaces?.length ?? 0) === 0) {
65
+ return;
66
+ }
67
+ diagnostics.push({
68
+ code: "partial.objectInterfaces",
69
+ message: `Object ${apiName} implements interfaces; interface implementation bindings are not emitted in this first pass.`,
70
+ path: `$.objectTypes[${objectIndex}].interfaces`,
71
+ severity: "warning",
72
+ });
73
+ }
74
+ function addObjectTypeGroupsDiagnostic(objectType, objectIndex, apiName, diagnostics) {
75
+ if ((objectType.typeGroups?.length ?? 0) === 0) {
76
+ return;
77
+ }
78
+ diagnostics.push({
79
+ code: "partial.objectTypeGroups",
80
+ message: `Object ${apiName} references type groups; type-group membership is preserved only in summary output.`,
81
+ path: `$.objectTypes[${objectIndex}].typeGroups`,
82
+ severity: "info",
83
+ });
84
+ }
85
+ function resolveProperty(propertyId, propertiesById) {
86
+ return propertyId ? propertiesById.get(propertyId) : undefined;
87
+ }
88
+ function addKeyDiagnostics(objectType, objectIndex, apiName, primaryKeyProperty, titleProperty, diagnostics) {
89
+ addPrimaryKeyDiagnostics(objectType, objectIndex, apiName, primaryKeyProperty, diagnostics);
90
+ addTitlePropertyDiagnostics(objectIndex, apiName, titleProperty, diagnostics);
91
+ }
92
+ function addPrimaryKeyDiagnostics(objectType, objectIndex, apiName, primaryKeyProperty, diagnostics) {
93
+ addCompositePrimaryKeyDiagnostic(objectType, objectIndex, apiName, diagnostics);
94
+ addMissingPrimaryKeyDiagnostic(primaryKeyProperty, objectIndex, apiName, diagnostics);
95
+ }
96
+ function addCompositePrimaryKeyDiagnostic(objectType, objectIndex, apiName, diagnostics) {
97
+ if ((objectType.primaryKeys?.length ?? 0) === 1) {
98
+ return;
99
+ }
100
+ diagnostics.push({
101
+ code: "unsupported.compositePrimaryKey",
102
+ message: `Expected exactly one primary key for ${apiName}.`,
103
+ path: `$.objectTypes[${objectIndex}].primaryKeys`,
104
+ severity: "warning",
105
+ });
106
+ }
107
+ function addMissingPrimaryKeyDiagnostic(primaryKeyProperty, objectIndex, apiName, diagnostics) {
108
+ if (primaryKeyProperty) {
109
+ return;
110
+ }
111
+ diagnostics.push({
112
+ code: "missing.primaryKeyProperty",
113
+ message: `Primary key property could not be resolved for ${apiName}; using first property.`,
114
+ path: `$.objectTypes[${objectIndex}].primaryKeys`,
115
+ severity: "warning",
116
+ });
117
+ }
118
+ function addTitlePropertyDiagnostics(objectIndex, apiName, titleProperty, diagnostics) {
119
+ if (titleProperty) {
120
+ return;
121
+ }
122
+ diagnostics.push({
123
+ code: "missing.titleProperty",
124
+ message: `Title property could not be resolved for ${apiName}; using primary key or first property.`,
125
+ path: `$.objectTypes[${objectIndex}].titlePropertyId`,
126
+ severity: "warning",
127
+ });
128
+ }
@@ -0,0 +1,3 @@
1
+ import type { ConversionDiagnostic, FoundryV2Export } from "./types.js";
2
+ export declare function parseFoundryV2Export(input: unknown, diagnostics: ConversionDiagnostic[]): FoundryV2Export;
3
+ //# sourceMappingURL=parse.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../../src/foundry-import/parse.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAGxE,wBAAgB,oBAAoB,CACnC,KAAK,EAAE,OAAO,EACd,WAAW,EAAE,oBAAoB,EAAE,GACjC,eAAe,CAejB"}
@@ -0,0 +1,28 @@
1
+ import { arrayField, isRecord } from "./utils.js";
2
+ export function parseFoundryV2Export(input, diagnostics) {
3
+ if (!isRecord(input)) {
4
+ throw new Error("Expected a JSON object.");
5
+ }
6
+ const version = typeof input.version === "number" ? input.version : 0;
7
+ addVersionDiagnostic(version, input.version, diagnostics);
8
+ return {
9
+ actionTypes: arrayField(input, "actionTypes"),
10
+ interfaces: arrayField(input, "interfaces"),
11
+ objectTypes: arrayField(input, "objectTypes"),
12
+ relations: arrayField(input, "relations"),
13
+ sharedProperties: arrayField(input, "sharedProperties"),
14
+ typeGroups: arrayField(input, "typeGroups"),
15
+ version,
16
+ };
17
+ }
18
+ function addVersionDiagnostic(version, rawVersion, diagnostics) {
19
+ if (version === 2) {
20
+ return;
21
+ }
22
+ diagnostics.push({
23
+ code: "unsupported.version",
24
+ message: `Expected version 2 export, received ${String(rawVersion)}.`,
25
+ path: "$.version",
26
+ severity: "warning",
27
+ });
28
+ }
@@ -0,0 +1,4 @@
1
+ import type { ConversionDiagnostic, FoundryProperty, FoundrySharedProperty, NormalizedProperty, NormalizedSharedProperty } from "./types.js";
2
+ export declare function normalizeProperty(property: FoundryProperty, path: string, nameAllocator: (name: string) => string, diagnostics: ConversionDiagnostic[]): NormalizedProperty;
3
+ export declare function normalizeSharedProperty(sharedProperty: FoundrySharedProperty, index: number, nameAllocator: (name: string) => string, variableNameAllocator: (name: string) => string, diagnostics: ConversionDiagnostic[]): NormalizedSharedProperty;
4
+ //# sourceMappingURL=properties.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"properties.d.ts","sourceRoot":"","sources":["../../src/foundry-import/properties.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACX,oBAAoB,EACpB,eAAe,EACf,qBAAqB,EACrB,kBAAkB,EAClB,wBAAwB,EACxB,MAAM,YAAY,CAAC;AASpB,wBAAgB,iBAAiB,CAChC,QAAQ,EAAE,eAAe,EACzB,IAAI,EAAE,MAAM,EACZ,aAAa,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,EACvC,WAAW,EAAE,oBAAoB,EAAE,GACjC,kBAAkB,CA0BpB;AAkED,wBAAgB,uBAAuB,CACtC,cAAc,EAAE,qBAAqB,EACrC,KAAK,EAAE,MAAM,EACb,aAAa,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,EACvC,qBAAqB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,EAC/C,WAAW,EAAE,oBAAoB,EAAE,GACjC,wBAAwB,CA4C1B"}
@@ -0,0 +1,83 @@
1
+ import { addSanitizationDiagnostic, sanitizeApiName } from "./names.js";
2
+ import { mapPropertyType } from "./property-types.js";
3
+ import { displayNameFor, normalizeDescription, normalizeNullability, requiredString, visibilityFor, } from "./utils.js";
4
+ export function normalizeProperty(property, path, nameAllocator, diagnostics) {
5
+ const apiName = normalizePropertyApiName(property, path, nameAllocator, diagnostics);
6
+ addValueTypeDiagnostic(property, apiName.original, path, diagnostics);
7
+ const mappedType = mapPropertyType(property.baseType, `${path}.baseType`, diagnostics);
8
+ return {
9
+ apiName,
10
+ array: mappedType.array,
11
+ description: propertyDescription(property),
12
+ displayName: propertyDisplayName(property, apiName.sanitized),
13
+ editOnly: isEditOnlyProperty(property),
14
+ indexedForSearch: propertyIndexedForSearch(property),
15
+ nullability: propertyNullability(property, path, diagnostics),
16
+ originalId: propertyOriginalId(property, apiName.original),
17
+ rid: property.rid,
18
+ type: mappedType.type,
19
+ visibility: propertyVisibility(property),
20
+ };
21
+ }
22
+ function propertyDescription(property) {
23
+ return normalizeDescription(property.displayMetadata?.description);
24
+ }
25
+ function propertyDisplayName(property, fallback) {
26
+ return displayNameFor(property.displayMetadata, fallback);
27
+ }
28
+ function isEditOnlyProperty(property) {
29
+ return property.source?.type === "editOnly";
30
+ }
31
+ function propertyIndexedForSearch(property) {
32
+ return property.indexedForSearch ?? false;
33
+ }
34
+ function propertyOriginalId(property, fallback) {
35
+ return property.id ?? fallback;
36
+ }
37
+ function propertyNullability(property, path, diagnostics) {
38
+ return normalizeNullability(property.dataConstraints?.nullability, `${path}.dataConstraints.nullability`, diagnostics);
39
+ }
40
+ function propertyVisibility(property) {
41
+ return visibilityFor(property.displayMetadata);
42
+ }
43
+ function normalizePropertyApiName(property, path, nameAllocator, diagnostics) {
44
+ const original = requiredString(property.apiName, `${path}.apiName`, diagnostics, property.id ?? "property");
45
+ const sanitized = nameAllocator(sanitizeApiName(original, "api"));
46
+ addSanitizationDiagnostic(diagnostics, `${path}.apiName`, original, sanitized);
47
+ return { original, sanitized };
48
+ }
49
+ export function normalizeSharedProperty(sharedProperty, index, nameAllocator, variableNameAllocator, diagnostics) {
50
+ const path = `$.sharedProperties[${index}]`;
51
+ const originalApiName = requiredString(sharedProperty.apiName, `${path}.apiName`, diagnostics, `SharedProperty${index + 1}`);
52
+ const sanitizedApiName = nameAllocator(sanitizeApiName(originalApiName, "api"));
53
+ addSanitizationDiagnostic(diagnostics, `${path}.apiName`, originalApiName, sanitizedApiName);
54
+ const mappedType = mapPropertyType(sharedProperty.baseType, `${path}.baseType`, diagnostics);
55
+ return {
56
+ apiName: { original: originalApiName, sanitized: sanitizedApiName },
57
+ array: mappedType.array,
58
+ description: normalizeDescription(sharedProperty.displayMetadata?.description),
59
+ displayName: displayNameFor(sharedProperty.displayMetadata, sanitizedApiName),
60
+ nullability: normalizeNullability(sharedProperty.dataConstraints?.nullability, `${path}.dataConstraints.nullability`, diagnostics),
61
+ rid: sharedProperty.rid,
62
+ type: mappedType.type,
63
+ variableName: variableNameAllocator(`${toPascalCaseLocal(sanitizedApiName)}Spt`),
64
+ visibility: visibilityFor(sharedProperty.displayMetadata),
65
+ };
66
+ }
67
+ function addValueTypeDiagnostic(property, apiName, path, diagnostics) {
68
+ if (!property.valueType) {
69
+ return;
70
+ }
71
+ diagnostics.push({
72
+ code: "partial.valueTypeReference",
73
+ message: `Property ${apiName} references a Foundry value type; preserving scalar type only in OAC output.`,
74
+ path: `${path}.valueType`,
75
+ severity: "info",
76
+ });
77
+ }
78
+ function toPascalCaseLocal(value) {
79
+ const words = value.match(/[a-zA-Z0-9]+/g) ?? ["Imported"];
80
+ return words
81
+ .map((word) => `${word[0]?.toUpperCase() ?? ""}${word.slice(1)}`)
82
+ .join("");
83
+ }
@@ -0,0 +1,7 @@
1
+ import type { ConversionDiagnostic, FoundryBaseType } from "./types.js";
2
+ export interface MappedPropertyType {
3
+ readonly array: boolean;
4
+ readonly type: unknown;
5
+ }
6
+ export declare function mapPropertyType(baseType: FoundryBaseType | undefined, path: string, diagnostics: ConversionDiagnostic[]): MappedPropertyType;
7
+ //# sourceMappingURL=property-types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"property-types.d.ts","sourceRoot":"","sources":["../../src/foundry-import/property-types.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACX,oBAAoB,EACpB,eAAe,EAEf,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,kBAAkB;IAClC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;CACvB;AA0BD,wBAAgB,eAAe,CAC9B,QAAQ,EAAE,eAAe,GAAG,SAAS,EACrC,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,oBAAoB,EAAE,GACjC,kBAAkB,CAEpB"}
@@ -0,0 +1,77 @@
1
+ import { sanitizeApiName } from "./names.js";
2
+ const typeHandlers = {
3
+ ARRAY: mapArrayType,
4
+ ATTACHMENT: scalarType("attachment"),
5
+ BOOLEAN: scalarType("boolean"),
6
+ DATE: scalarType("date"),
7
+ DOUBLE: scalarType("double"),
8
+ GEOHASH: scalarType("geopoint"),
9
+ GEOSHAPE: scalarType("geoshape"),
10
+ INTEGER: scalarType("integer"),
11
+ LONG: scalarType("long"),
12
+ MARKING: mapMarkingType,
13
+ MEDIA_REFERENCE: scalarType("mediaReference"),
14
+ STRING: scalarType("string"),
15
+ STRUCT: mapStructType,
16
+ TIMESTAMP: scalarType("timestamp"),
17
+ VECTOR: mapVectorType,
18
+ };
19
+ export function mapPropertyType(baseType, path, diagnostics) {
20
+ return typeHandlerFor(baseType)(baseType, path, diagnostics);
21
+ }
22
+ function typeHandlerFor(baseType) {
23
+ return typeHandlers[baseType?.type ?? ""] ?? coerceUnknownType;
24
+ }
25
+ function scalarType(type) {
26
+ return () => ({ array: false, type });
27
+ }
28
+ function mapArrayType(baseType, path, diagnostics) {
29
+ return {
30
+ array: true,
31
+ type: mapPropertyType(baseType?.subType, `${path}.subType`, diagnostics)
32
+ .type,
33
+ };
34
+ }
35
+ function mapMarkingType(baseType) {
36
+ return {
37
+ array: false,
38
+ type: {
39
+ markingInputGroupName: "ImportedMarkings",
40
+ markingType: baseType?.markingType ?? "MANDATORY",
41
+ type: "marking",
42
+ },
43
+ };
44
+ }
45
+ function mapStructType(baseType, path, diagnostics) {
46
+ return {
47
+ array: false,
48
+ type: {
49
+ structDefinition: Object.fromEntries((baseType?.structFields ?? []).map((field, index) => structFieldEntry(field, `${path}.structFields[${index}]`, diagnostics))),
50
+ type: "struct",
51
+ },
52
+ };
53
+ }
54
+ function structFieldEntry(field, path, diagnostics) {
55
+ return [
56
+ sanitizeApiName(field.apiName ?? "field", "api"),
57
+ mapPropertyType(field.fieldType, `${path}.fieldType`, diagnostics).type,
58
+ ];
59
+ }
60
+ function mapVectorType(_baseType, path, diagnostics) {
61
+ diagnostics.push({
62
+ code: "coerced.vectorType",
63
+ message: "Vector properties are emitted as strings in the first-pass OAC output.",
64
+ path,
65
+ severity: "warning",
66
+ });
67
+ return { array: false, type: "string" };
68
+ }
69
+ function coerceUnknownType(baseType, path, diagnostics) {
70
+ diagnostics.push({
71
+ code: "coerced.unknownPropertyType",
72
+ message: `Unknown property type ${String(baseType?.type)} emitted as string.`,
73
+ path,
74
+ severity: "warning",
75
+ });
76
+ return { array: false, type: "string" };
77
+ }
@@ -0,0 +1,11 @@
1
+ import type { ConversionDiagnostic, FoundryRelation, NormalizedObject, NormalizedRelation } from "./types.js";
2
+ export declare function normalizeRelation(relation: FoundryRelation, relationIndex: number, objectsByRid: ReadonlyMap<string, NormalizedObject>, relationNameAllocator: (name: string) => string, variableNameAllocator: (name: string) => string, diagnostics: ConversionDiagnostic[]): readonly NormalizedRelation[];
3
+ export declare function raw(value: string): {
4
+ readonly __raw: true;
5
+ readonly value: string;
6
+ };
7
+ export declare function isRaw(value: unknown): value is {
8
+ readonly __raw: true;
9
+ readonly value: string;
10
+ };
11
+ //# sourceMappingURL=relations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relations.d.ts","sourceRoot":"","sources":["../../src/foundry-import/relations.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACX,oBAAoB,EAIpB,eAAe,EACf,gBAAgB,EAEhB,kBAAkB,EAClB,MAAM,YAAY,CAAC;AA4BpB,wBAAgB,iBAAiB,CAChC,QAAQ,EAAE,eAAe,EACzB,aAAa,EAAE,MAAM,EACrB,YAAY,EAAE,WAAW,CAAC,MAAM,EAAE,gBAAgB,CAAC,EACnD,qBAAqB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,EAC/C,qBAAqB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,EAC/C,WAAW,EAAE,oBAAoB,EAAE,GACjC,SAAS,kBAAkB,EAAE,CAO/B;AA8UD,wBAAgB,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG;IACnC,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC;IACrB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACvB,CAEA;AAED,wBAAgB,KAAK,CACpB,KAAK,EAAE,OAAO,GACZ,KAAK,IAAI;IAAE,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAI3D"}
@@ -0,0 +1,204 @@
1
+ import { addSanitizationDiagnostic, sanitizeApiName, toPascalCase, } from "./names.js";
2
+ import { isRecord, normalizeStatus, visibilityFor } from "./utils.js";
3
+ const relationNormalizers = {
4
+ intermediary: skipIntermediaryRelation,
5
+ manyToMany: normalizeRelationWithManyToMany,
6
+ oneToMany: normalizeRelationWithOneToMany,
7
+ };
8
+ export function normalizeRelation(relation, relationIndex, objectsByRid, relationNameAllocator, variableNameAllocator, diagnostics) {
9
+ return relationNormalizerFor(relation)(relation, relationIndex, {
10
+ diagnostics,
11
+ objectsByRid,
12
+ relationNameAllocator,
13
+ variableNameAllocator,
14
+ });
15
+ }
16
+ function relationNormalizerFor(relation) {
17
+ return (relationNormalizers[relationDefinitionType(relation) ?? ""] ??
18
+ skipUnknownRelation);
19
+ }
20
+ function relationDefinitionType(relation) {
21
+ return relation.definition?.type;
22
+ }
23
+ function linkMetadata(metadata) {
24
+ const displayMetadata = linkDisplayMetadata(metadata);
25
+ return {
26
+ apiName: sanitizeApiName(linkApiName(metadata), "api"),
27
+ displayName: linkDisplayName(metadata, displayMetadata),
28
+ groupDisplayName: displayMetadataValue(displayMetadata, "groupDisplayName"),
29
+ pluralDisplayName: displayMetadataValue(displayMetadata, "pluralDisplayName"),
30
+ visibility: visibilityFor(displayMetadata),
31
+ };
32
+ }
33
+ function linkDisplayMetadata(metadata) {
34
+ return metadata?.displayMetadata;
35
+ }
36
+ function linkApiName(metadata) {
37
+ return metadata?.apiName ?? "link";
38
+ }
39
+ function linkDisplayName(metadata, displayMetadata) {
40
+ return firstPresent(displayMetadata?.displayName, metadata?.apiName, "Link");
41
+ }
42
+ function firstPresent(...values) {
43
+ return (values.find((value) => typeof value === "string" && value !== "") ?? "Link");
44
+ }
45
+ function displayMetadataValue(displayMetadata, key) {
46
+ return displayMetadata?.[key] ?? undefined;
47
+ }
48
+ function normalizeRelationWithOneToMany(relation, relationIndex, context) {
49
+ const oneToMany = relation.definition?.oneToMany;
50
+ if (!oneToMany) {
51
+ return skipMalformedRelation(relation, relationIndex, context.diagnostics);
52
+ }
53
+ return normalizeOneToManyRelation(relation, oneToMany, relationIndex, context);
54
+ }
55
+ function normalizeRelationWithManyToMany(relation, relationIndex, context) {
56
+ const manyToMany = relation.definition?.manyToMany;
57
+ if (!manyToMany) {
58
+ return skipMalformedRelation(relation, relationIndex, context.diagnostics);
59
+ }
60
+ return normalizeManyToManyRelation(relation, manyToMany, relationIndex, context);
61
+ }
62
+ function normalizeOneToManyRelation(relation, oneToMany, relationIndex, context) {
63
+ const requirements = resolveOneToManyRequirements(relation, oneToMany, relationIndex, context);
64
+ if (!requirements) {
65
+ return [];
66
+ }
67
+ const relationNames = allocateRelationNames(relation, relationIndex, context.relationNameAllocator, context.variableNameAllocator, context.diagnostics);
68
+ return [
69
+ {
70
+ apiName: relationNames.apiName,
71
+ definition: {
72
+ apiName: relationNames.apiName.sanitized,
73
+ cardinality: cardinalityFor(oneToMany),
74
+ manyForeignKeyProperty: requirements.manyForeignKeyProperty.apiName.sanitized,
75
+ one: {
76
+ metadata: linkMetadata(oneToMany.oneToManyLinkMetadata),
77
+ object: raw(requirements.one.variableName),
78
+ },
79
+ toMany: {
80
+ metadata: linkMetadata(oneToMany.manyToOneLinkMetadata),
81
+ object: raw(requirements.many.variableName),
82
+ },
83
+ },
84
+ kind: "oneToMany",
85
+ rid: relation.rid,
86
+ status: normalizeStatus(relation.status),
87
+ variableName: relationNames.variableName,
88
+ },
89
+ ];
90
+ }
91
+ function resolveOneToManyRequirements(relation, oneToMany, relationIndex, context) {
92
+ const one = objectByRid(oneToMany.objectTypeRidOneSide, context.objectsByRid);
93
+ const many = objectByRid(oneToMany.objectTypeRidManySide, context.objectsByRid);
94
+ if (!one || !many) {
95
+ addRelationObjectReferenceDiagnostic(relation, relationIndex, context.diagnostics);
96
+ return undefined;
97
+ }
98
+ const manyForeignKeyProperty = propertyById(oneToMany.manySideForeignKeyPropertyId, many.propertiesById);
99
+ if (!manyForeignKeyProperty) {
100
+ addRelationForeignKeyDiagnostic(relation, relationIndex, context.diagnostics);
101
+ return undefined;
102
+ }
103
+ return { many, manyForeignKeyProperty, one };
104
+ }
105
+ function cardinalityFor(oneToMany) {
106
+ return oneToMany.cardinalityHint === "ONE_TO_ONE" ? "OneToOne" : "OneToMany";
107
+ }
108
+ function normalizeManyToManyRelation(relation, manyToMany, relationIndex, context) {
109
+ const objectA = objectByRid(manyToMany.objectTypeRidA, context.objectsByRid);
110
+ const objectB = objectByRid(manyToMany.objectTypeRidB, context.objectsByRid);
111
+ if (!objectA || !objectB) {
112
+ addRelationObjectReferenceDiagnostic(relation, relationIndex, context.diagnostics);
113
+ return [];
114
+ }
115
+ const relationNames = allocateRelationNames(relation, relationIndex, context.relationNameAllocator, context.variableNameAllocator, context.diagnostics);
116
+ return [
117
+ {
118
+ apiName: relationNames.apiName,
119
+ definition: {
120
+ apiName: relationNames.apiName.sanitized,
121
+ many: {
122
+ metadata: linkMetadata(manyToMany.objectTypeAToBLinkMetadata),
123
+ object: raw(objectA.variableName),
124
+ },
125
+ toMany: {
126
+ metadata: linkMetadata(manyToMany.objectTypeBToALinkMetadata),
127
+ object: raw(objectB.variableName),
128
+ },
129
+ },
130
+ kind: "manyToMany",
131
+ rid: relation.rid,
132
+ status: normalizeStatus(relation.status),
133
+ variableName: relationNames.variableName,
134
+ },
135
+ ];
136
+ }
137
+ function skipIntermediaryRelation(relation, relationIndex, context) {
138
+ context.diagnostics.push({
139
+ code: "skipped.intermediaryRelation",
140
+ message: `Intermediary relation ${relationLabel(relation, relationIndex)} is preserved only in diagnostics for this first pass.`,
141
+ path: `$.relations[${relationIndex}]`,
142
+ severity: "warning",
143
+ });
144
+ return [];
145
+ }
146
+ function skipUnknownRelation(relation, relationIndex, context) {
147
+ const definitionType = relationDefinitionType(relation);
148
+ context.diagnostics.push({
149
+ code: "skipped.unknownRelation",
150
+ message: `Relation ${relationLabel(relation, relationIndex)} has unsupported definition type ${String(definitionType)}.`,
151
+ path: `$.relations[${relationIndex}].definition.type`,
152
+ severity: "warning",
153
+ });
154
+ return [];
155
+ }
156
+ function skipMalformedRelation(relation, relationIndex, diagnostics) {
157
+ diagnostics.push({
158
+ code: "skipped.malformedRelation",
159
+ message: `Relation ${relationLabel(relation, relationIndex)} is missing the expected relation definition body.`,
160
+ path: `$.relations[${relationIndex}].definition`,
161
+ severity: "warning",
162
+ });
163
+ return [];
164
+ }
165
+ function allocateRelationNames(relation, relationIndex, relationNameAllocator, variableNameAllocator, diagnostics) {
166
+ const original = relation.id ?? `relation${relationIndex}`;
167
+ const sanitized = relationNameAllocator(sanitizeApiName(original, "api"));
168
+ addSanitizationDiagnostic(diagnostics, `$.relations[${relationIndex}].id`, original, sanitized);
169
+ return {
170
+ apiName: { original, sanitized },
171
+ variableName: variableNameAllocator(`${toPascalCase(sanitized)}Link`),
172
+ };
173
+ }
174
+ function objectByRid(rid, objectsByRid) {
175
+ return rid ? objectsByRid.get(rid) : undefined;
176
+ }
177
+ function propertyById(propertyId, propertiesById) {
178
+ return propertyId ? propertiesById.get(propertyId) : undefined;
179
+ }
180
+ function addRelationObjectReferenceDiagnostic(relation, relationIndex, diagnostics) {
181
+ diagnostics.push({
182
+ code: "skipped.relationObjectReference",
183
+ message: `Relation ${relationLabel(relation, relationIndex)} references an unknown object.`,
184
+ path: `$.relations[${relationIndex}]`,
185
+ severity: "warning",
186
+ });
187
+ }
188
+ function addRelationForeignKeyDiagnostic(relation, relationIndex, diagnostics) {
189
+ diagnostics.push({
190
+ code: "skipped.relationForeignKey",
191
+ message: `Relation ${relationLabel(relation, relationIndex)} has no resolvable many-side foreign key.`,
192
+ path: `$.relations[${relationIndex}].definition.oneToMany.manySideForeignKeyPropertyId`,
193
+ severity: "warning",
194
+ });
195
+ }
196
+ function relationLabel(relation, relationIndex) {
197
+ return relation.id ?? relation.rid ?? String(relationIndex);
198
+ }
199
+ export function raw(value) {
200
+ return { __raw: true, value };
201
+ }
202
+ export function isRaw(value) {
203
+ return (isRecord(value) && value.__raw === true && typeof value.value === "string");
204
+ }