@palantir/pack.document-schema.type-gen 0.9.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (156) hide show
  1. package/build/esm/commands/asset/__tests__/buildPrefixRewriteFetch.test.js +85 -0
  2. package/build/esm/commands/asset/__tests__/buildPrefixRewriteFetch.test.js.map +1 -0
  3. package/build/esm/commands/asset/assetDeployHandler.js +36 -1
  4. package/build/esm/commands/asset/assetDeployHandler.js.map +1 -1
  5. package/build/esm/commands/asset/assetUpdateSchemaHandler.js +84 -0
  6. package/build/esm/commands/asset/assetUpdateSchemaHandler.js.map +1 -0
  7. package/build/esm/commands/asset/registerAssetCommands.js +3 -1
  8. package/build/esm/commands/asset/registerAssetCommands.js.map +1 -1
  9. package/build/esm/commands/ir/irGenTypesHandler.js +49 -0
  10. package/build/esm/commands/ir/irGenTypesHandler.js.map +1 -0
  11. package/build/esm/commands/ir/registerIrCommands.js +2 -0
  12. package/build/esm/commands/ir/registerIrCommands.js.map +1 -1
  13. package/build/esm/commands/schema/registerSchemaCommands.js +2 -2
  14. package/build/esm/commands/schema/registerSchemaCommands.js.map +1 -1
  15. package/build/esm/commands/schema/schemaIrHandler.js +56 -0
  16. package/build/esm/commands/schema/schemaIrHandler.js.map +1 -0
  17. package/build/esm/index.js +0 -6
  18. package/build/esm/index.js.map +1 -1
  19. package/build/esm/utils/ir/__tests__/__snapshots__/generateModelsFromIr/custom-discriminant.js +1 -1
  20. package/build/esm/utils/ir/__tests__/__snapshots__/generateModelsFromIr/custom-discriminant.js.map +1 -1
  21. package/build/esm/utils/ir/__tests__/__snapshots__/generateModelsFromIr/external-refs.js +1 -1
  22. package/build/esm/utils/ir/__tests__/__snapshots__/generateModelsFromIr/external-refs.js.map +1 -1
  23. package/build/esm/utils/ir/__tests__/__snapshots__/generateModelsFromIr/simple-record.js +1 -1
  24. package/build/esm/utils/ir/__tests__/__snapshots__/generateModelsFromIr/simple-record.js.map +1 -1
  25. package/build/esm/utils/ir/__tests__/__snapshots__/generateModelsFromIr/union-types.js +1 -1
  26. package/build/esm/utils/ir/__tests__/__snapshots__/generateModelsFromIr/union-types.js.map +1 -1
  27. package/build/esm/utils/ir/__tests__/__snapshots__/generateZodSchemasFromIr/array-and-map-types.js +1 -1
  28. package/build/esm/utils/ir/__tests__/__snapshots__/generateZodSchemasFromIr/array-and-map-types.js.map +1 -1
  29. package/build/esm/utils/ir/__tests__/__snapshots__/generateZodSchemasFromIr/boolean-fields.js +1 -1
  30. package/build/esm/utils/ir/__tests__/__snapshots__/generateZodSchemasFromIr/boolean-fields.js.map +1 -1
  31. package/build/esm/utils/ir/__tests__/__snapshots__/generateZodSchemasFromIr/custom-discriminant.js +1 -1
  32. package/build/esm/utils/ir/__tests__/__snapshots__/generateZodSchemasFromIr/custom-discriminant.js.map +1 -1
  33. package/build/esm/utils/ir/__tests__/__snapshots__/generateZodSchemasFromIr/datetime-fields.js +1 -1
  34. package/build/esm/utils/ir/__tests__/__snapshots__/generateZodSchemasFromIr/datetime-fields.js.map +1 -1
  35. package/build/esm/utils/ir/__tests__/__snapshots__/generateZodSchemasFromIr/simple-records.js +1 -1
  36. package/build/esm/utils/ir/__tests__/__snapshots__/generateZodSchemasFromIr/simple-records.js.map +1 -1
  37. package/build/esm/utils/ir/__tests__/__snapshots__/generateZodSchemasFromIr/union-before-records.js +1 -1
  38. package/build/esm/utils/ir/__tests__/__snapshots__/generateZodSchemasFromIr/union-before-records.js.map +1 -1
  39. package/build/esm/utils/ir/__tests__/__snapshots__/generateZodSchemasFromIr/union-types.js +1 -1
  40. package/build/esm/utils/ir/__tests__/__snapshots__/generateZodSchemasFromIr/union-types.js.map +1 -1
  41. package/build/esm/utils/ir/__tests__/convertIrToWireSchema.test.js +23 -0
  42. package/build/esm/utils/ir/__tests__/convertIrToWireSchema.test.js.map +1 -1
  43. package/build/esm/utils/ir/irFieldHelpers.js +383 -0
  44. package/build/esm/utils/ir/irFieldHelpers.js.map +1 -0
  45. package/build/esm/utils/schema/__tests__/__snapshots__/generateVersionsFromSchema/single-version.js.map +1 -1
  46. package/build/esm/utils/schema/__tests__/__snapshots__/generateVersionsFromSchema/three-version-chain.js.map +1 -1
  47. package/build/esm/utils/schema/__tests__/__snapshots__/generateVersionsFromSchema/two-version.js.map +1 -1
  48. package/build/esm/utils/schema/__tests__/convertSchemaToSteps.test.js +13 -0
  49. package/build/esm/utils/schema/__tests__/convertSchemaToSteps.test.js.map +1 -1
  50. package/build/esm/utils/schema/__tests__/fixtures.js +78 -13
  51. package/build/esm/utils/schema/__tests__/fixtures.js.map +1 -1
  52. package/build/esm/utils/schema/__tests__/generateInternalFromSchema.test.js +19 -7
  53. package/build/esm/utils/schema/__tests__/generateInternalFromSchema.test.js.map +1 -1
  54. package/build/esm/utils/schema/__tests__/generateModelMetadataFromSchema.test.js +12 -7
  55. package/build/esm/utils/schema/__tests__/generateModelMetadataFromSchema.test.js.map +1 -1
  56. package/build/esm/utils/schema/__tests__/generateScopeFromSchema.test.js +6 -5
  57. package/build/esm/utils/schema/__tests__/generateScopeFromSchema.test.js.map +1 -1
  58. package/build/esm/utils/schema/__tests__/generateVersionedTypesFromSchema.test.js +19 -10
  59. package/build/esm/utils/schema/__tests__/generateVersionedTypesFromSchema.test.js.map +1 -1
  60. package/build/esm/utils/schema/__tests__/generateVersionedZodFromSchema.test.js +15 -10
  61. package/build/esm/utils/schema/__tests__/generateVersionedZodFromSchema.test.js.map +1 -1
  62. package/build/esm/utils/schema/__tests__/generateVersionsFromSchema.test.js +6 -5
  63. package/build/esm/utils/schema/__tests__/generateVersionsFromSchema.test.js.map +1 -1
  64. package/build/esm/utils/schema/__tests__/snapshotUtils.js +3 -0
  65. package/build/esm/utils/schema/__tests__/snapshotUtils.js.map +1 -1
  66. package/build/esm/utils/schema/convertSchemaToSteps.js +6 -0
  67. package/build/esm/utils/schema/convertSchemaToSteps.js.map +1 -1
  68. package/build/esm/utils/schema/generateIndexFromSchema.js +21 -14
  69. package/build/esm/utils/schema/generateIndexFromSchema.js.map +1 -1
  70. package/build/esm/utils/schema/generateInternalFromSchema.js +202 -191
  71. package/build/esm/utils/schema/generateInternalFromSchema.js.map +1 -1
  72. package/build/esm/utils/schema/generateModelMetadataFromSchema.js +89 -80
  73. package/build/esm/utils/schema/generateModelMetadataFromSchema.js.map +1 -1
  74. package/build/esm/utils/schema/generateScopeFromSchema.js +29 -33
  75. package/build/esm/utils/schema/generateScopeFromSchema.js.map +1 -1
  76. package/build/esm/utils/schema/generateTypesFromSchema.js +9 -1
  77. package/build/esm/utils/schema/generateTypesFromSchema.js.map +1 -1
  78. package/build/esm/utils/schema/generateVersionedTypesFromSchema.js +61 -155
  79. package/build/esm/utils/schema/generateVersionedTypesFromSchema.js.map +1 -1
  80. package/build/esm/utils/schema/generateVersionedZodFromSchema.js +58 -94
  81. package/build/esm/utils/schema/generateVersionedZodFromSchema.js.map +1 -1
  82. package/build/esm/utils/schema/generateVersionsFromSchema.js +7 -5
  83. package/build/esm/utils/schema/generateVersionsFromSchema.js.map +1 -1
  84. package/build/esm/utils/schema/loadSchemaModule.js +53 -0
  85. package/build/esm/utils/schema/loadSchemaModule.js.map +1 -0
  86. package/build/esm/utils/schema/resolveSchemaChain.js +68 -9
  87. package/build/esm/utils/schema/resolveSchemaChain.js.map +1 -1
  88. package/build/esm/utils/schema/runtimeSchema.js +3 -27
  89. package/build/esm/utils/schema/runtimeSchema.js.map +1 -1
  90. package/build/esm/utils/schema/writeAllSdkFiles.js +113 -0
  91. package/build/esm/utils/schema/writeAllSdkFiles.js.map +1 -0
  92. package/build/esm/utils/steps/__tests__/__snapshots__/types/arrayFields.js.map +1 -1
  93. package/build/esm/utils/steps/__tests__/__snapshots__/types/customDiscriminant.js +1 -1
  94. package/build/esm/utils/steps/__tests__/__snapshots__/types/customDiscriminant.js.map +1 -1
  95. package/build/esm/utils/steps/__tests__/__snapshots__/types/generateTypeScriptInterfaces.js +1 -1
  96. package/build/esm/utils/steps/__tests__/__snapshots__/types/generateTypeScriptInterfaces.js.map +1 -1
  97. package/build/esm/utils/steps/__tests__/__snapshots__/types/refTypes.js.map +1 -1
  98. package/build/esm/utils/steps/__tests__/__snapshots__/types/simpleRecord.js.map +1 -1
  99. package/build/esm/utils/steps/__tests__/__snapshots__/types/simpleSteps.js +1 -1
  100. package/build/esm/utils/steps/__tests__/__snapshots__/types/simpleSteps.js.map +1 -1
  101. package/build/esm/utils/steps/__tests__/convertStepsToIr.test.js +93 -1
  102. package/build/esm/utils/steps/__tests__/convertStepsToIr.test.js.map +1 -1
  103. package/build/esm/utils/steps/convertStepsToIr.js +43 -35
  104. package/build/esm/utils/steps/convertStepsToIr.js.map +1 -1
  105. package/build/types/commands/asset/__tests__/buildPrefixRewriteFetch.test.d.ts +2 -0
  106. package/build/types/commands/asset/__tests__/buildPrefixRewriteFetch.test.d.ts.map +1 -0
  107. package/build/types/commands/asset/assetDeployHandler.d.ts +15 -0
  108. package/build/types/commands/asset/assetDeployHandler.d.ts.map +1 -1
  109. package/build/types/commands/asset/assetUpdateSchemaHandler.d.ts +12 -0
  110. package/build/types/commands/asset/assetUpdateSchemaHandler.d.ts.map +1 -0
  111. package/build/types/commands/asset/registerAssetCommands.d.ts.map +1 -1
  112. package/build/types/commands/ir/irGenTypesHandler.d.ts +8 -0
  113. package/build/types/commands/ir/irGenTypesHandler.d.ts.map +1 -0
  114. package/build/types/commands/ir/registerIrCommands.d.ts.map +1 -1
  115. package/build/types/commands/schema/registerSchemaCommands.d.ts.map +1 -1
  116. package/build/types/commands/schema/schemaIrHandler.d.ts +19 -0
  117. package/build/types/commands/schema/schemaIrHandler.d.ts.map +1 -0
  118. package/build/types/index.d.ts +1 -6
  119. package/build/types/index.d.ts.map +1 -1
  120. package/build/types/utils/ir/irFieldHelpers.d.ts +36 -0
  121. package/build/types/utils/ir/irFieldHelpers.d.ts.map +1 -0
  122. package/build/types/utils/schema/__tests__/fixtures.d.ts +10 -1
  123. package/build/types/utils/schema/__tests__/fixtures.d.ts.map +1 -1
  124. package/build/types/utils/schema/__tests__/snapshotUtils.d.ts +2 -0
  125. package/build/types/utils/schema/__tests__/snapshotUtils.d.ts.map +1 -1
  126. package/build/types/utils/schema/convertSchemaToSteps.d.ts.map +1 -1
  127. package/build/types/utils/schema/generateIndexFromSchema.d.ts +5 -3
  128. package/build/types/utils/schema/generateIndexFromSchema.d.ts.map +1 -1
  129. package/build/types/utils/schema/generateInternalFromSchema.d.ts +6 -7
  130. package/build/types/utils/schema/generateInternalFromSchema.d.ts.map +1 -1
  131. package/build/types/utils/schema/generateModelMetadataFromSchema.d.ts +3 -8
  132. package/build/types/utils/schema/generateModelMetadataFromSchema.d.ts.map +1 -1
  133. package/build/types/utils/schema/generateScopeFromSchema.d.ts +2 -2
  134. package/build/types/utils/schema/generateScopeFromSchema.d.ts.map +1 -1
  135. package/build/types/utils/schema/generateTypesFromSchema.d.ts.map +1 -1
  136. package/build/types/utils/schema/generateVersionedTypesFromSchema.d.ts +4 -7
  137. package/build/types/utils/schema/generateVersionedTypesFromSchema.d.ts.map +1 -1
  138. package/build/types/utils/schema/generateVersionedZodFromSchema.d.ts +3 -7
  139. package/build/types/utils/schema/generateVersionedZodFromSchema.d.ts.map +1 -1
  140. package/build/types/utils/schema/generateVersionsFromSchema.d.ts +3 -3
  141. package/build/types/utils/schema/generateVersionsFromSchema.d.ts.map +1 -1
  142. package/build/types/utils/schema/loadSchemaModule.d.ts +14 -0
  143. package/build/types/utils/schema/loadSchemaModule.d.ts.map +1 -0
  144. package/build/types/utils/schema/resolveSchemaChain.d.ts +29 -8
  145. package/build/types/utils/schema/resolveSchemaChain.d.ts.map +1 -1
  146. package/build/types/utils/schema/runtimeSchema.d.ts +2 -32
  147. package/build/types/utils/schema/runtimeSchema.d.ts.map +1 -1
  148. package/build/types/utils/schema/writeAllSdkFiles.d.ts +8 -0
  149. package/build/types/utils/schema/writeAllSdkFiles.d.ts.map +1 -0
  150. package/build/types/utils/steps/convertStepsToIr.d.ts +3 -3
  151. package/build/types/utils/steps/convertStepsToIr.d.ts.map +1 -1
  152. package/package.json +4 -4
  153. package/build/esm/commands/schema/schemaGenTypesHandler.js +0 -147
  154. package/build/esm/commands/schema/schemaGenTypesHandler.js.map +0 -1
  155. package/build/types/commands/schema/schemaGenTypesHandler.d.ts +0 -8
  156. package/build/types/commands/schema/schemaGenTypesHandler.d.ts.map +0 -1
@@ -15,109 +15,8 @@
15
15
  */
16
16
 
17
17
  import { GENERATED_FILE_HEADER } from "../generatedFileHeader.js";
18
- import { resolveSchemaChain } from "./resolveSchemaChain.js";
19
- import { findRecordExportName, isRecordSchema, isUnionSchema, TypeKind } from "./runtimeSchema.js";
20
- /**
21
- * Convert a schema field type to TypeScript string for internal types.
22
- */
23
- function convertTypeToTypeScript(fieldType) {
24
- switch (fieldType.type) {
25
- case TypeKind.ARRAY:
26
- {
27
- if (fieldType.items == null) {
28
- throw new Error("Array field is missing items type");
29
- }
30
- const inner = convertTypeToTypeScript(fieldType.items);
31
- // Wrap compound types (unions, other arrays) in parens before appending []
32
- const needsParens = inner.includes("|") || inner.startsWith("readonly ");
33
- const wrapped = needsParens ? `(${inner})` : inner;
34
- return `readonly ${wrapped}[]`;
35
- }
36
- case TypeKind.BOOLEAN:
37
- return "boolean";
38
- case TypeKind.DOC_REF:
39
- return "string";
40
- case TypeKind.DOUBLE:
41
- return "number";
42
- case TypeKind.MEDIA_REF:
43
- return "string";
44
- case TypeKind.OBJECT_REF:
45
- return "string";
46
- case TypeKind.OPTIONAL:
47
- if (fieldType.item == null) {
48
- throw new Error("Optional field is missing inner type");
49
- }
50
- return `(${convertTypeToTypeScript(fieldType.item)} | undefined)`;
51
- case TypeKind.REF:
52
- return "unknown";
53
- case TypeKind.STRING:
54
- return "string";
55
- case TypeKind.USER_REF:
56
- return "string";
57
- default:
58
- throw new Error(`Unknown schema field type: ${fieldType.type}`);
59
- }
60
- }
61
-
62
- /**
63
- * Convert a schema field type to a FieldTypeDescriptor source string.
64
- */
65
- function convertTypeToFieldTypeDescriptor(fieldType, schema) {
66
- switch (fieldType.type) {
67
- case TypeKind.ARRAY:
68
- if (fieldType.items == null) {
69
- throw new Error("Array field is missing items type");
70
- }
71
- return `{ kind: "array", element: ${convertTypeToFieldTypeDescriptor(fieldType.items, schema)} }`;
72
- case TypeKind.OPTIONAL:
73
- if (fieldType.item == null) {
74
- throw new Error("Optional field is missing inner type");
75
- }
76
- return `{ kind: "optional", inner: ${convertTypeToFieldTypeDescriptor(fieldType.item, schema)} }`;
77
- case TypeKind.REF:
78
- {
79
- if (fieldType.name == null) {
80
- throw new Error("Ref field is missing a name");
81
- }
82
- const exportKey = fieldType.refType === "record" ? findRecordExportName(fieldType.name, schema) ?? fieldType.name : fieldType.name;
83
- return `{ kind: "modelRef", model: "${exportKey}" }`;
84
- }
85
- default:
86
- return `{ kind: "primitive" }`;
87
- }
88
- }
89
-
90
- /**
91
- * Convert a schema field type to a Zod schema string.
92
- */
93
- function convertTypeToZodSchema(fieldType) {
94
- switch (fieldType.type) {
95
- case TypeKind.ARRAY:
96
- if (fieldType.items == null) {
97
- throw new Error("Array field is missing items type");
98
- }
99
- return `z.array(${convertTypeToZodSchema(fieldType.items)})`;
100
- case TypeKind.BOOLEAN:
101
- return "z.boolean()";
102
- case TypeKind.DOC_REF:
103
- case TypeKind.MEDIA_REF:
104
- case TypeKind.OBJECT_REF:
105
- case TypeKind.STRING:
106
- case TypeKind.USER_REF:
107
- return "z.string()";
108
- case TypeKind.DOUBLE:
109
- return "z.number()";
110
- case TypeKind.OPTIONAL:
111
- if (fieldType.item == null) {
112
- throw new Error("Optional field is missing inner type");
113
- }
114
- return `${convertTypeToZodSchema(fieldType.item)}.optional()`;
115
- case TypeKind.REF:
116
- return "z.unknown()";
117
- default:
118
- throw new Error(`Unknown schema field type: ${fieldType.type}`);
119
- }
120
- }
18
+ import { convertFieldTypeToDescriptor, convertFieldTypeToInternalTypeScript, convertFieldTypeToInternalZod } from "../ir/irFieldHelpers.js";
19
+ import { chainHasDerivedFields } from "./resolveSchemaChain.js";
121
20
 
122
21
  /** Collected info about all fields for a model across all versions. */
123
22
 
@@ -141,30 +40,35 @@ function collectRecordModels(chain) {
141
40
  // Initialize models from all versions
142
41
  for (const {
143
42
  version,
144
- schema
43
+ ir
145
44
  } of chain) {
146
- for (const [exportName, item] of Object.entries(schema)) {
147
- if (!isRecordSchema(item)) continue;
148
- if (!allRecordModels.has(exportName)) {
149
- allRecordModels.set(exportName, {
45
+ for (const [modelKey, modelDef] of Object.entries(ir.models)) {
46
+ if (modelDef.type !== "record") continue;
47
+ if (!allRecordModels.has(modelKey)) {
48
+ allRecordModels.set(modelKey, {
150
49
  allFields: new Map(),
151
50
  steps: []
152
51
  });
153
52
  }
154
- const model = allRecordModels.get(exportName);
155
- for (const [fieldName, fieldType] of Object.entries(item.fields)) {
156
- const existing = model.allFields.get(fieldName);
53
+ const model = allRecordModels.get(modelKey);
54
+ for (const field of modelDef.record.fields) {
55
+ const existing = model.allFields.get(field.key);
157
56
  if (existing == null) {
158
- model.allFields.set(fieldName, {
159
- fieldType,
57
+ model.allFields.set(field.key, {
58
+ fieldType: field.fieldType,
59
+ isOptional: field.isOptional === true,
160
60
  presentInVersions: new Set([version]),
161
- alwaysOptional: fieldType.type === TypeKind.OPTIONAL
61
+ alwaysOptional: field.isOptional === true,
62
+ everOptional: field.isOptional === true
162
63
  });
163
64
  } else {
164
65
  existing.presentInVersions.add(version);
165
- if (fieldType.type !== TypeKind.OPTIONAL) {
66
+ if (field.isOptional !== true) {
166
67
  existing.alwaysOptional = false;
167
68
  }
69
+ if (field.isOptional === true) {
70
+ existing.everOptional = true;
71
+ }
168
72
  }
169
73
  }
170
74
  }
@@ -172,32 +76,30 @@ function collectRecordModels(chain) {
172
76
 
173
77
  // Compute upgrade steps from version diffs
174
78
  for (let i = 1; i < chain.length; i++) {
175
- const prevVersion = chain[i - 1];
176
- const currVersion = chain[i];
177
- for (const [exportName, currItem] of Object.entries(currVersion.schema)) {
178
- if (!isRecordSchema(currItem)) continue;
179
- const prevItem = prevVersion.schema[exportName];
180
- if (prevItem == null || !isRecordSchema(prevItem)) continue;
181
- const model = allRecordModels.get(exportName);
79
+ const prevEntry = chain[i - 1];
80
+ const currEntry = chain[i];
81
+ for (const [modelKey, currModelDef] of Object.entries(currEntry.ir.models)) {
82
+ if (currModelDef.type !== "record") continue;
83
+ const prevModelDef = prevEntry.ir.models[modelKey];
84
+ if (prevModelDef == null || prevModelDef.type !== "record") continue;
85
+ const model = allRecordModels.get(modelKey);
182
86
  if (model == null) continue;
183
- const prevFields = new Set(Object.keys(prevItem.fields));
184
- const currFields = new Set(Object.keys(currItem.fields));
87
+ const prevFields = new Set(prevModelDef.record.fields.map(f => f.key));
88
+ const currFields = new Set(currModelDef.record.fields.map(f => f.key));
185
89
 
186
90
  // Fields added in this version
187
91
  const addedFields = new Map();
188
- const recordUpgrades = currVersion.migrations?.[exportName];
189
- for (const fieldName of currFields) {
190
- if (!prevFields.has(fieldName)) {
191
- const annotation = recordUpgrades?.[fieldName];
92
+ const recordUpgrades = currEntry.migrations?.[modelKey];
93
+ for (const fieldKey of currFields) {
94
+ if (!prevFields.has(fieldKey)) {
95
+ const annotation = recordUpgrades?.[fieldKey];
192
96
  if (annotation != null) {
193
- addedFields.set(fieldName, {
194
- derivedFrom: [...annotation.derivedFrom],
195
- forwardSource: annotation.forward.toString()
97
+ addedFields.set(fieldKey, {
98
+ derivedFrom: [...annotation.derivedFrom]
196
99
  });
197
100
  } else {
198
- addedFields.set(fieldName, {
199
- derivedFrom: [],
200
- forwardSource: "() => undefined"
101
+ addedFields.set(fieldKey, {
102
+ derivedFrom: []
201
103
  });
202
104
  }
203
105
  }
@@ -205,15 +107,14 @@ function collectRecordModels(chain) {
205
107
 
206
108
  // Fields removed in this version
207
109
  const removedFields = [];
208
- for (const fieldName of prevFields) {
209
- if (!currFields.has(fieldName)) {
210
- removedFields.push(fieldName);
110
+ for (const fieldKey of prevFields) {
111
+ if (!currFields.has(fieldKey)) {
112
+ removedFields.push(fieldKey);
211
113
  }
212
114
  }
213
115
  if (addedFields.size > 0 || removedFields.length > 0) {
214
116
  model.steps.push({
215
- name: `v${currVersion.version}`,
216
- addedInVersion: currVersion.version,
117
+ addedInVersion: currEntry.version,
217
118
  fields: addedFields,
218
119
  removedFields
219
120
  });
@@ -239,11 +140,11 @@ function collectRecordModels(chain) {
239
140
  function generateInternalTypes(allRecordModels) {
240
141
  let output = GENERATED_FILE_HEADER;
241
142
  output += "\n";
242
- for (const [exportName, model] of sortedEntries(allRecordModels)) {
143
+ for (const [modelKey, model] of sortedEntries(allRecordModels)) {
243
144
  output += `/** Internal representation containing all fields across all schema versions. */\n`;
244
- output += `export interface ${exportName}__Internal {\n`;
145
+ output += `export interface ${modelKey}__Internal {\n`;
245
146
  for (const [fieldName, fieldInfo] of sortedEntries(model.allFields)) {
246
- const tsType = convertTypeToTypeScript(fieldInfo.fieldType);
147
+ const tsType = convertFieldTypeToInternalTypeScript(fieldInfo.fieldType, fieldInfo.isOptional);
247
148
  const optional = fieldInfo.alwaysOptional ? "?" : "";
248
149
  output += ` readonly ${fieldName}${optional}: ${tsType};\n`;
249
150
  }
@@ -252,32 +153,78 @@ function generateInternalTypes(allRecordModels) {
252
153
  return output;
253
154
  }
254
155
 
156
+ /**
157
+ * Generate per-version internal interfaces (e.g. `ShapeBox__v1`, `ShapeBox__v2`).
158
+ *
159
+ * Each interface contains only the fields present in that version, with their
160
+ * actual optionality taken straight from that version's IR. The downstream
161
+ * `DocumentUpgradeFns` generator uses these so each upgrade function's
162
+ * parameter can `Pick` the prior version's fields and its return type can
163
+ * index the current version's field type precisely.
164
+ */
165
+ function generatePerVersionInternalTypes(chain) {
166
+ // Group by model so each model's versions appear together in ascending order.
167
+ const perModelVersions = new Map();
168
+ for (const {
169
+ version,
170
+ ir
171
+ } of chain) {
172
+ for (const [modelKey, modelDef] of Object.entries(ir.models)) {
173
+ if (modelDef.type !== "record") continue;
174
+ let list = perModelVersions.get(modelKey);
175
+ if (list == null) {
176
+ list = [];
177
+ perModelVersions.set(modelKey, list);
178
+ }
179
+ list.push({
180
+ version,
181
+ fields: modelDef.record.fields
182
+ });
183
+ }
184
+ }
185
+ let output = "";
186
+ const sortedModels = Array.from(perModelVersions.entries()).sort(([a], [b]) => a.localeCompare(b));
187
+ for (const [modelKey, versions] of sortedModels) {
188
+ for (const {
189
+ version,
190
+ fields
191
+ } of versions) {
192
+ output += `/** Internal representation of ${modelKey} at schema version ${version}. */\n`;
193
+ output += `export interface ${modelKey}__v${version} {\n`;
194
+ const sortedFields = [...fields].sort((a, b) => a.key.localeCompare(b.key));
195
+ for (const field of sortedFields) {
196
+ const tsType = convertFieldTypeToInternalTypeScript(field.fieldType, field.isOptional === true);
197
+ const optional = field.isOptional === true ? "?" : "";
198
+ output += ` readonly ${field.key}${optional}: ${tsType};\n`;
199
+ }
200
+ output += "}\n\n";
201
+ }
202
+ }
203
+ return output;
204
+ }
205
+
255
206
  /**
256
207
  * Generate _internal/upgrades.ts content.
257
208
  */
258
- function generateUpgrades(allRecordModels, latestSchema) {
209
+ function generateUpgrades(allRecordModels, latestIr) {
259
210
  let output = GENERATED_FILE_HEADER;
260
211
  const hasRecords = allRecordModels.size > 0;
261
- const hasUnions = Object.values(latestSchema).some(isUnionSchema);
212
+ const hasUnions = Object.values(latestIr.models).some(m => m.type === "union");
262
213
  const imports = [];
263
214
  if (hasRecords) imports.push("UpgradeRegistry");
264
215
  if (hasUnions) imports.push("UnionUpgradeRegistry");
265
216
  if (imports.length > 0) {
266
217
  output += `import type { ${imports.join(", ")} } from "@palantir/pack.document-schema.model-types";\n\n`;
267
218
  }
268
- for (const [exportName, model] of sortedEntries(allRecordModels)) {
269
- output += `export const ${exportName}Upgrades: UpgradeRegistry<"${exportName}"> = {\n`;
270
- output += ` modelName: "${exportName}",\n`;
219
+ for (const [modelKey, model] of sortedEntries(allRecordModels)) {
220
+ output += `export const ${modelKey}Upgrades: UpgradeRegistry<"${modelKey}"> = {\n`;
221
+ output += ` modelName: "${modelKey}",\n`;
271
222
 
272
223
  // allFields
273
224
  output += ` allFields: {\n`;
274
225
  for (const [fieldName, fieldInfo] of sortedEntries(model.allFields)) {
275
- const typeDescriptor = convertTypeToFieldTypeDescriptor(fieldInfo.fieldType, latestSchema);
276
- if (fieldInfo.default !== undefined) {
277
- output += ` ${fieldName}: { type: ${typeDescriptor}, default: ${JSON.stringify(fieldInfo.default)} },\n`;
278
- } else {
279
- output += ` ${fieldName}: { type: ${typeDescriptor} },\n`;
280
- }
226
+ const typeDescriptor = convertFieldTypeToDescriptor(fieldInfo.fieldType, fieldInfo.isOptional);
227
+ output += ` ${fieldName}: { type: ${typeDescriptor} },\n`;
281
228
  }
282
229
  output += ` },\n`;
283
230
 
@@ -285,13 +232,11 @@ function generateUpgrades(allRecordModels, latestSchema) {
285
232
  output += ` steps: [\n`;
286
233
  for (const step of model.steps) {
287
234
  output += ` {\n`;
288
- output += ` name: "${step.name}",\n`;
289
235
  output += ` addedInVersion: ${step.addedInVersion},\n`;
290
236
  output += ` fields: {\n`;
291
237
  for (const [fieldName, fieldMeta] of step.fields) {
292
238
  output += ` ${fieldName}: {\n`;
293
239
  output += ` derivedFrom: [${fieldMeta.derivedFrom.map(d => `"${d}"`).join(", ")}],\n`;
294
- output += ` forward: ${fieldMeta.forwardSource},\n`;
295
240
  if (fieldMeta.default !== undefined) {
296
241
  output += ` default: ${JSON.stringify(fieldMeta.default)},\n`;
297
242
  }
@@ -308,19 +253,15 @@ function generateUpgrades(allRecordModels, latestSchema) {
308
253
  }
309
254
 
310
255
  // Generate UnionUpgradeRegistry entries for union models
311
- for (const [exportName, item] of Object.entries(latestSchema)) {
312
- if (!isUnionSchema(item)) continue;
313
- output += `export const ${exportName}Upgrades: UnionUpgradeRegistry<"${exportName}"> = {\n`;
314
- output += ` modelName: "${exportName}",\n`;
315
- output += ` discriminant: "${item.discriminant}",\n`;
256
+ for (const [modelKey, modelDef] of Object.entries(latestIr.models)) {
257
+ if (modelDef.type !== "union") continue;
258
+ const union = modelDef.union;
259
+ output += `export const ${modelKey}Upgrades: UnionUpgradeRegistry<"${modelKey}"> = {\n`;
260
+ output += ` modelName: "${modelKey}",\n`;
261
+ output += ` discriminant: "${union.discriminant}",\n`;
316
262
  output += ` variants: {\n`;
317
- for (const [variantKey, variantField] of Object.entries(item.variants)) {
318
- if (variantField.type === "ref" && variantField.refType === "record" && variantField.name != null) {
319
- const variantExportName = findRecordExportName(variantField.name, latestSchema);
320
- if (variantExportName != null) {
321
- output += ` "${variantKey}": "${variantExportName}",\n`;
322
- }
323
- }
263
+ for (const [variantKey, variantModelKey] of Object.entries(union.variants)) {
264
+ output += ` "${variantKey}": "${variantModelKey}",\n`;
324
265
  }
325
266
  output += ` },\n`;
326
267
  output += `};\n\n`;
@@ -334,21 +275,13 @@ function generateUpgrades(allRecordModels, latestSchema) {
334
275
  function generateInternalSchemaContent(allRecordModels) {
335
276
  let output = GENERATED_FILE_HEADER;
336
277
  output += `import { z } from "zod";\n\n`;
337
- for (const [exportName, model] of sortedEntries(allRecordModels)) {
338
- output += `export const ${exportName}InternalSchema = z.object({\n`;
278
+ for (const [modelKey, model] of sortedEntries(allRecordModels)) {
279
+ output += `export const ${modelKey}InternalSchema = z.object({\n`;
339
280
  for (const [fieldName, fieldInfo] of sortedEntries(model.allFields)) {
340
- const zodType = convertTypeToZodSchema(fieldInfo.fieldType);
341
- // In internal schema, all fields that might be absent are optional
342
- if (fieldInfo.alwaysOptional) {
343
- // If the type already ends with .optional(), don't double-wrap
344
- if (zodType.endsWith(".optional()")) {
345
- output += ` ${fieldName}: ${zodType},\n`;
346
- } else {
347
- output += ` ${fieldName}: ${zodType}.optional(),\n`;
348
- }
349
- } else {
350
- output += ` ${fieldName}: ${zodType},\n`;
351
- }
281
+ // Use everOptional: a field optional in ANY version must stay optional
282
+ // in the internal schema because older documents may legitimately omit it.
283
+ const zodType = convertFieldTypeToInternalZod(fieldInfo.fieldType, fieldInfo.alwaysOptional || fieldInfo.everOptional);
284
+ output += ` ${fieldName}: ${zodType},\n`;
352
285
  }
353
286
  output += `}).passthrough();\n\n`;
354
287
  }
@@ -356,25 +289,103 @@ function generateInternalSchemaContent(allRecordModels) {
356
289
  }
357
290
 
358
291
  /**
359
- * Generate _internal/types.ts, _internal/upgrades.ts, and _internal/schema.ts
360
- * from a versioned schema chain.
292
+ * Generate _internal/upgradeFns.ts content: a typed `DocumentUpgradeFns`
293
+ * interface enumerating every upgrade function the app must supply at boot.
294
+ *
295
+ * For every `(modelName, v${version}, fieldName)` triple where `derivedFrom` is
296
+ * non-empty, emit a property typed
297
+ * `(oldFields: Pick<<Model>__v<prior>, derivedFrom[number]>) => <Model>__v<current>[fieldName]`.
298
+ * Additive fields (empty `derivedFrom`) are intentionally absent — they are
299
+ * handled by the structural `default` in `_internal/upgrades.ts`.
361
300
  *
362
- * @param schema - The schema definition (initial or versioned)
363
- * @returns Object containing generated code for each internal file
301
+ * The interface is consumed by the generated `DocumentModel` factory in
302
+ * `models.ts`, which requires it as a parameter when the schema has any
303
+ * derived fields. Schemas without derived fields emit an empty interface
304
+ * (still exported for type-uniformity in downstream code).
305
+ */
306
+ function generateUpgradeFns(chain, allRecordModels) {
307
+ const perModel = new Map();
308
+ const neededTypes = new Set();
309
+ for (const [modelKey, model] of sortedEntries(allRecordModels)) {
310
+ for (const step of model.steps) {
311
+ const currentIdx = chain.findIndex(c => c.version === step.addedInVersion);
312
+ if (currentIdx <= 0) continue;
313
+ const priorVersion = chain[currentIdx - 1].version;
314
+ const fields = [];
315
+ for (const [fieldName, fieldMeta] of step.fields) {
316
+ if (fieldMeta.derivedFrom.length === 0) continue;
317
+ fields.push({
318
+ fieldName,
319
+ derivedFrom: [...fieldMeta.derivedFrom]
320
+ });
321
+ }
322
+ if (fields.length === 0) continue;
323
+ let list = perModel.get(modelKey);
324
+ if (list == null) {
325
+ list = [];
326
+ perModel.set(modelKey, list);
327
+ }
328
+ list.push({
329
+ currentVersion: step.addedInVersion,
330
+ priorVersion,
331
+ fields
332
+ });
333
+ neededTypes.add(`${modelKey}__v${priorVersion}`);
334
+ neededTypes.add(`${modelKey}__v${step.addedInVersion}`);
335
+ }
336
+ }
337
+ let output = GENERATED_FILE_HEADER;
338
+ output += `\n`;
339
+ if (neededTypes.size > 0) {
340
+ const sorted = Array.from(neededTypes).sort();
341
+ output += `import type { ${sorted.join(", ")} } from "./types.js";\n\n`;
342
+ }
343
+ output += `/**\n`;
344
+ output += ` * Typed upgrade functions the application must supply at boot. Coverage is\n`;
345
+ output += ` * exhaustive: missing or extra entries fail type-check at the \`DocumentModel(...)\`\n`;
346
+ output += ` * call site. Additive fields (empty \`derivedFrom\`) are intentionally absent.\n`;
347
+ output += ` */\n`;
348
+ if (perModel.size === 0) {
349
+ output += `// eslint-disable-next-line @typescript-eslint/no-empty-object-type\n`;
350
+ output += `export interface DocumentUpgradeFns {}\n`;
351
+ } else {
352
+ output += `export interface DocumentUpgradeFns {\n`;
353
+ for (const [modelKey, steps] of Array.from(perModel.entries()).sort(([a], [b]) => a.localeCompare(b))) {
354
+ output += ` ${modelKey}: {\n`;
355
+ for (const step of steps) {
356
+ output += ` v${step.currentVersion}: {\n`;
357
+ for (const f of step.fields) {
358
+ const pickKeys = f.derivedFrom.map(d => `"${d}"`).join(" | ");
359
+ output += ` ${f.fieldName}: (oldFields: Pick<${modelKey}__v${step.priorVersion}, ${pickKeys}>) => ${modelKey}__v${step.currentVersion}["${f.fieldName}"];\n`;
360
+ }
361
+ output += ` };\n`;
362
+ }
363
+ output += ` };\n`;
364
+ }
365
+ output += `}\n`;
366
+ }
367
+ return output;
368
+ }
369
+
370
+ /**
371
+ * Generate _internal/types.ts, _internal/upgrades.ts, _internal/schema.ts and
372
+ * _internal/upgradeFns.ts from an already-resolved versioned IR chain.
364
373
  */
365
- export function generateInternalFromSchema(schema) {
374
+ export function generateInternalFromChain(resolved) {
366
375
  const {
367
376
  chain
368
- } = resolveSchemaChain(schema);
369
- const latestSchema = chain[chain.length - 1].schema;
377
+ } = resolved;
378
+ const latestIr = chain[chain.length - 1].ir;
370
379
  const allRecordModels = collectRecordModels(chain);
371
- const internalTypes = generateInternalTypes(allRecordModels);
372
- const upgrades = generateUpgrades(allRecordModels, latestSchema);
380
+ const internalTypes = generateInternalTypes(allRecordModels) + (chainHasDerivedFields(chain) ? generatePerVersionInternalTypes(chain) : "");
381
+ const upgrades = generateUpgrades(allRecordModels, latestIr);
373
382
  const internalSchema = generateInternalSchemaContent(allRecordModels);
383
+ const internalUpgradeFns = generateUpgradeFns(chain, allRecordModels);
374
384
  return {
375
385
  internalTypes,
376
386
  upgrades,
377
- internalSchema
387
+ internalSchema,
388
+ internalUpgradeFns
378
389
  };
379
390
  }
380
391
  //# sourceMappingURL=generateInternalFromSchema.js.map