@postxl/schema 1.4.0 → 1.5.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.
@@ -1,4 +1,4 @@
1
- export declare const zEnum: import("zod").ZodPipe<import("zod").ZodObject<{
1
+ export declare const zEnum: import("zod").ZodPipe<import("zod").ZodPipe<import("zod").ZodTransform<unknown, unknown>, import("zod").ZodObject<{
2
2
  name: import("zod").ZodString;
3
3
  description: import("zod").ZodDefault<import("zod").ZodOptional<import("zod").ZodString>>;
4
4
  schema: import("zod").ZodOptional<import("zod").ZodString>;
@@ -7,7 +7,7 @@ export declare const zEnum: import("zod").ZodPipe<import("zod").ZodObject<{
7
7
  value: import("zod").ZodString;
8
8
  description: import("zod").ZodOptional<import("zod").ZodString>;
9
9
  }, import("zod/v4/core").$strip>, import("zod").ZodString]>>;
10
- }, import("zod/v4/core").$strip>, import("zod").ZodTransform<{
10
+ }, import("zod/v4/core").$strip>>, import("zod").ZodTransform<{
11
11
  name: string & import("zod").$brand<"PXL.EnumName">;
12
12
  description: string;
13
13
  members: Map<string & import("zod").$brand<"PXL.EnumValue">, import("./enum.types").EnumMember>;
@@ -12,7 +12,7 @@ export declare const zEnumMemberJSON: z.ZodUnion<readonly [z.ZodObject<{
12
12
  }, z.core.$strip>, z.ZodString]>;
13
13
  export type EnumMemberJSON = z.infer<typeof zEnumMemberJSON>;
14
14
  export declare const zEnumNameJSON: z.ZodString;
15
- export declare const zEnumJSON: z.ZodObject<{
15
+ export declare const zEnumJSON: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodObject<{
16
16
  name: z.ZodString;
17
17
  description: z.ZodDefault<z.ZodOptional<z.ZodString>>;
18
18
  schema: z.ZodOptional<z.ZodString>;
@@ -21,5 +21,5 @@ export declare const zEnumJSON: z.ZodObject<{
21
21
  value: z.ZodString;
22
22
  description: z.ZodOptional<z.ZodString>;
23
23
  }, z.core.$strip>, z.ZodString]>>;
24
- }, z.core.$strip>;
24
+ }, z.core.$strip>>;
25
25
  export type EnumJSON = z.infer<typeof zEnumJSON>;
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.zEnumJSON = exports.zEnumNameJSON = exports.zEnumMemberJSON = exports.zEnumMemberCompact = exports.zEnumMemberJSONDetailed = exports.zEnumMemberDescriptionJSON = exports.zEnumMemberNameJSON = void 0;
4
4
  const zod_1 = require("zod");
5
5
  const utils_1 = require("@postxl/utils");
6
+ const normalize_named_collection_1 = require("../normalize-named-collection");
6
7
  exports.zEnumMemberNameJSON = zod_1.z
7
8
  //
8
9
  .string()
@@ -30,7 +31,16 @@ exports.zEnumNameJSON = zod_1.z
30
31
  },
31
32
  })
32
33
  .describe('Name of the enum.');
33
- exports.zEnumJSON = zod_1.z.object({
34
+ exports.zEnumJSON = zod_1.z.preprocess((input) => {
35
+ if (typeof input === 'object' && input !== null) {
36
+ const original = input;
37
+ return {
38
+ ...original,
39
+ members: (0, normalize_named_collection_1.normalizeEnumMembers)(original.members),
40
+ };
41
+ }
42
+ return input;
43
+ }, zod_1.z.object({
34
44
  name: exports.zEnumNameJSON,
35
45
  description: zod_1.z
36
46
  //
@@ -51,4 +61,4 @@ exports.zEnumJSON = zod_1.z.object({
51
61
  //
52
62
  .array(exports.zEnumMemberJSON)
53
63
  .min(1, { error: 'Enum must have at least one member.' }),
54
- });
64
+ }));
@@ -52,7 +52,7 @@ export declare const zField: z.ZodRecord<z.ZodString, z.ZodAny>;
52
52
  /**
53
53
  * JSON Schema for an Discriminated Union field
54
54
  */
55
- export declare const zFieldDiscriminatedUnionJSON: z.ZodObject<{
55
+ export declare const zFieldDiscriminatedUnionJSON: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodObject<{
56
56
  name: z.ZodString;
57
57
  type: z.ZodUnion<[z.ZodLiteral<"DiscriminatedUnion">, z.ZodLiteral<"DiscriminatedUnion?">]>;
58
58
  label: z.ZodOptional<z.ZodString>;
@@ -66,7 +66,7 @@ export declare const zFieldDiscriminatedUnionJSON: z.ZodObject<{
66
66
  }, z.core.$strip>>;
67
67
  commonFields: z.ZodOptional<z.ZodArray<z.ZodRecord<z.ZodString, z.ZodAny>>>;
68
68
  isReadonly: z.ZodOptional<z.ZodBoolean>;
69
- }, z.core.$strip>;
69
+ }, z.core.$strip>>;
70
70
  export type FieldDiscriminatedUnionJSON = z.infer<typeof zFieldDiscriminatedUnionJSON>;
71
71
  export declare function fieldDiscriminatedUnionJSONTransformer(fieldInput: FieldDiscriminatedUnionJSON): {
72
72
  kind: "discriminatedUnion";
@@ -41,6 +41,7 @@ const zod_1 = require("zod");
41
41
  const utils_1 = require("@postxl/utils");
42
42
  const enum_1 = require("../enum");
43
43
  const model_1 = require("../model");
44
+ const normalize_named_collection_1 = require("../normalize-named-collection");
44
45
  const Branded = __importStar(require("./shared/brands"));
45
46
  const Decoders = __importStar(require("./shared/decoders"));
46
47
  const utils_2 = require("./shared/utils");
@@ -60,7 +61,26 @@ exports.zField = zod_1.z.record(zod_1.z.string(), zod_1.z.any());
60
61
  /**
61
62
  * JSON Schema for an Discriminated Union field
62
63
  */
63
- exports.zFieldDiscriminatedUnionJSON = zod_1.z.object({
64
+ exports.zFieldDiscriminatedUnionJSON = zod_1.z.preprocess((input) => {
65
+ if (typeof input === 'object' && input !== null) {
66
+ const original = input;
67
+ return {
68
+ ...original,
69
+ ...(original.commonFields !== undefined
70
+ ? { commonFields: (0, normalize_named_collection_1.normalizeNamedCollection)(original.commonFields) }
71
+ : {}),
72
+ members: Array.isArray(original.members)
73
+ ? original.members.map((member) => {
74
+ if (typeof member === 'object' && member !== null && 'fields' in member) {
75
+ return { ...member, fields: (0, normalize_named_collection_1.normalizeNamedCollection)(member.fields) };
76
+ }
77
+ return member;
78
+ })
79
+ : original.members,
80
+ };
81
+ }
82
+ return input;
83
+ }, zod_1.z.object({
64
84
  name: Decoders.zFieldPropertyName,
65
85
  type: zod_1.z //
66
86
  .literal('DiscriminatedUnion')
@@ -82,7 +102,7 @@ exports.zFieldDiscriminatedUnionJSON = zod_1.z.object({
82
102
  })),
83
103
  commonFields: zod_1.z.array(exports.zField).optional(),
84
104
  isReadonly: Decoders.zFieldPropertyIsReadonly,
85
- });
105
+ }));
86
106
  function fieldDiscriminatedUnionJSONTransformer(fieldInput) {
87
107
  const { isRequired } = (0, utils_2.isFieldRequired)(fieldInput.type);
88
108
  return {
@@ -128,7 +148,7 @@ const fieldDiscriminatedUnionTransformer = ({ fieldInput, model, projectSchema }
128
148
  }
129
149
  const decodedField = decodedFieldResult.data;
130
150
  const transformedField = Fields.fieldTransformer(decodedField, model, projectSchema, ctx);
131
- commonFields.set(transformedField.name, addDiscriminatedUnionParent(transformedField, fieldInput.name));
151
+ commonFields.set(transformedField.name, addDiscriminatedUnionParent(transformedField, fieldInput.name, fieldInput.excelName));
132
152
  }
133
153
  const members = new Map();
134
154
  for (const memberInput of fieldInput.members) {
@@ -153,7 +173,7 @@ const fieldDiscriminatedUnionTransformer = ({ fieldInput, model, projectSchema }
153
173
  return zod_1.z.NEVER;
154
174
  }
155
175
  const transformedField = Fields.fieldTransformer(decodedField, model, projectSchema, ctx);
156
- memberFields.set(transformedField.name, addDiscriminatedUnionParentMember(transformedField, fieldInput.name, discriminator));
176
+ memberFields.set(transformedField.name, addDiscriminatedUnionParentMember(transformedField, fieldInput.name, fieldInput.excelName, discriminator));
157
177
  }
158
178
  members.set(discriminator, {
159
179
  type: discriminator,
@@ -174,7 +194,7 @@ const fieldDiscriminatedUnionTransformer = ({ fieldInput, model, projectSchema }
174
194
  return result;
175
195
  };
176
196
  exports.fieldDiscriminatedUnionTransformer = fieldDiscriminatedUnionTransformer;
177
- function addDiscriminatedUnionParent(field, duFieldName) {
197
+ function addDiscriminatedUnionParent(field, duFieldName, duExcelName) {
178
198
  const result = {
179
199
  ...field,
180
200
  discriminatedUnionFieldName: duFieldName,
@@ -183,10 +203,16 @@ function addDiscriminatedUnionParent(field, duFieldName) {
183
203
  databaseName: field.databaseName,
184
204
  newName: `${duFieldName}${(0, utils_1.toPascalCase)(field.name)}`,
185
205
  }),
206
+ excelName: ensureCustomExcelName({
207
+ name: field.name,
208
+ label: field.label,
209
+ excelName: field.excelName,
210
+ newName: `${duExcelName} ${field.excelName}`,
211
+ }),
186
212
  };
187
213
  return result;
188
214
  }
189
- function addDiscriminatedUnionParentMember(field, duFieldName, duMemberType) {
215
+ function addDiscriminatedUnionParentMember(field, duFieldName, duExcelName, duMemberType) {
190
216
  const result = {
191
217
  ...field,
192
218
  discriminatedUnionFieldName: duFieldName,
@@ -196,9 +222,22 @@ function addDiscriminatedUnionParentMember(field, duFieldName, duMemberType) {
196
222
  databaseName: field.databaseName,
197
223
  newName: `${duFieldName}${(0, utils_1.toPascalCase)(duMemberType)}${(0, utils_1.toPascalCase)(field.name)}`,
198
224
  }),
225
+ excelName: ensureCustomExcelName({
226
+ name: field.name,
227
+ label: field.label,
228
+ excelName: field.excelName,
229
+ newName: `${duExcelName} ${(0, utils_1.toPascalCase)(duMemberType)} ${field.excelName}`,
230
+ }),
199
231
  };
200
232
  return result;
201
233
  }
234
+ function ensureCustomExcelName({ excelName, name, label, newName, }) {
235
+ // If the user explicitly set a custom excelName (different from the defaults), keep it
236
+ if (excelName !== name && excelName !== label && excelName !== (0, utils_1.toHumanReadable)(name)) {
237
+ return excelName;
238
+ }
239
+ return Branded.toExcelColumnName(newName);
240
+ }
202
241
  function ensureCustomDatabaseName({ databaseName, name, newName, }) {
203
242
  if (databaseName !== name && databaseName !== (0, utils_1.toSnakeCase)(name)) {
204
243
  return databaseName;
@@ -81,7 +81,7 @@ export declare const createFieldJSONDecoder: (params: {
81
81
  faker?: string | undefined;
82
82
  seed?: string | number | boolean | Date | (string | number | boolean | Date)[] | undefined;
83
83
  placeholder?: string | undefined;
84
- }>>, z.ZodPipe<z.ZodObject<{
84
+ }>>, z.ZodPipe<z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodObject<{
85
85
  name: z.ZodString;
86
86
  type: z.ZodUnion<[z.ZodLiteral<"DiscriminatedUnion">, z.ZodLiteral<"DiscriminatedUnion?">]>;
87
87
  label: z.ZodOptional<z.ZodString>;
@@ -95,7 +95,7 @@ export declare const createFieldJSONDecoder: (params: {
95
95
  }, z.core.$strip>>;
96
96
  commonFields: z.ZodOptional<z.ZodArray<z.ZodRecord<z.ZodString, z.ZodAny>>>;
97
97
  isReadonly: z.ZodOptional<z.ZodBoolean>;
98
- }, z.core.$strip>, z.ZodTransform<{
98
+ }, z.core.$strip>>, z.ZodTransform<{
99
99
  kind: "discriminatedUnion";
100
100
  name: string & z.core.$brand<"PXL.FieldName">;
101
101
  discriminatorFieldName: string & z.core.$brand<"PXL.FieldName">;
@@ -4,6 +4,7 @@ exports.zModelJSON = exports.zModelNameJSON = void 0;
4
4
  const zod_1 = require("zod");
5
5
  const utils_1 = require("@postxl/utils");
6
6
  const brands_1 = require("../field/shared/brands");
7
+ const normalize_named_collection_1 = require("../normalize-named-collection");
7
8
  exports.zModelNameJSON = zod_1.z
8
9
  //
9
10
  .string()
@@ -18,7 +19,11 @@ exports.zModelNameJSON = zod_1.z
18
19
  exports.zModelJSON = zod_1.z.preprocess((input) => {
19
20
  if (typeof input === 'object' && input !== null) {
20
21
  const original = input;
21
- const result = { ...original, source: { ...original } };
22
+ const result = {
23
+ ...original,
24
+ source: { ...original },
25
+ fields: (0, normalize_named_collection_1.normalizeNamedCollection)(original.fields),
26
+ };
22
27
  return result;
23
28
  }
24
29
  return input;
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Normalizes a collection that can be either an array of named objects or an object keyed by name.
3
+ *
4
+ * Array format (existing):
5
+ * [{ name: "User", ... }, { name: "Post", ... }]
6
+ *
7
+ * Object format (new):
8
+ * { "User": { ... }, "Post": { ... } }
9
+ *
10
+ * When given an object, converts it to an array by injecting the key as the specified name property.
11
+ * Arrays and undefined/null values are passed through unchanged.
12
+ *
13
+ * @param input - The collection input (array or object)
14
+ * @param nameKey - The property name to inject the key as (default: 'name')
15
+ * @returns The normalized array, or the input unchanged if already an array or undefined/null
16
+ */
17
+ export declare function normalizeNamedCollection(input: unknown, nameKey?: string): unknown;
18
+ /**
19
+ * Normalizes enum members that can be either an array or an object keyed by member value.
20
+ *
21
+ * Array format (existing):
22
+ * ["Draft", { value: "Published", description: "..." }]
23
+ *
24
+ * Object format (new):
25
+ * { "Draft": { description: "..." }, "Published": { description: "..." } }
26
+ * { "Draft": "description text", "Published": "description text" }
27
+ *
28
+ * When given an object, converts it to an array of enum member entries.
29
+ * String values are treated as descriptions.
30
+ * Object values get the key injected as the `value` property.
31
+ *
32
+ * @param input - The members input (array or object)
33
+ * @returns The normalized array, or the input unchanged if already an array or undefined/null
34
+ */
35
+ export declare function normalizeEnumMembers(input: unknown): unknown;
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.normalizeNamedCollection = normalizeNamedCollection;
4
+ exports.normalizeEnumMembers = normalizeEnumMembers;
5
+ /**
6
+ * Normalizes a collection that can be either an array of named objects or an object keyed by name.
7
+ *
8
+ * Array format (existing):
9
+ * [{ name: "User", ... }, { name: "Post", ... }]
10
+ *
11
+ * Object format (new):
12
+ * { "User": { ... }, "Post": { ... } }
13
+ *
14
+ * When given an object, converts it to an array by injecting the key as the specified name property.
15
+ * Arrays and undefined/null values are passed through unchanged.
16
+ *
17
+ * @param input - The collection input (array or object)
18
+ * @param nameKey - The property name to inject the key as (default: 'name')
19
+ * @returns The normalized array, or the input unchanged if already an array or undefined/null
20
+ */
21
+ function normalizeNamedCollection(input, nameKey = 'name') {
22
+ if (input === undefined || input === null || Array.isArray(input)) {
23
+ return input;
24
+ }
25
+ if (typeof input === 'object') {
26
+ return Object.entries(input).map(([key, value]) => {
27
+ if (typeof value === 'object' && value !== null) {
28
+ return { ...value, [nameKey]: key };
29
+ }
30
+ return value;
31
+ });
32
+ }
33
+ return input;
34
+ }
35
+ /**
36
+ * Normalizes enum members that can be either an array or an object keyed by member value.
37
+ *
38
+ * Array format (existing):
39
+ * ["Draft", { value: "Published", description: "..." }]
40
+ *
41
+ * Object format (new):
42
+ * { "Draft": { description: "..." }, "Published": { description: "..." } }
43
+ * { "Draft": "description text", "Published": "description text" }
44
+ *
45
+ * When given an object, converts it to an array of enum member entries.
46
+ * String values are treated as descriptions.
47
+ * Object values get the key injected as the `value` property.
48
+ *
49
+ * @param input - The members input (array or object)
50
+ * @returns The normalized array, or the input unchanged if already an array or undefined/null
51
+ */
52
+ function normalizeEnumMembers(input) {
53
+ if (input === undefined || input === null || Array.isArray(input)) {
54
+ return input;
55
+ }
56
+ if (typeof input === 'object') {
57
+ return Object.entries(input).map(([key, value]) => {
58
+ if (typeof value === 'string') {
59
+ // { "Draft": "description text" } → { value: "Draft", description: "description text" }
60
+ return { value: key, description: value };
61
+ }
62
+ if (typeof value === 'object' && value !== null) {
63
+ // { "Draft": { description: "..." } } → { value: "Draft", description: "..." }
64
+ return { ...value, value: key };
65
+ }
66
+ // { "Draft": null } or other → just the value name
67
+ return key;
68
+ });
69
+ }
70
+ return input;
71
+ }
@@ -33,7 +33,7 @@ export declare const zProjectSchemaJSON: z.ZodPipe<z.ZodTransform<unknown, unkno
33
33
  }, z.core.$strip>>;
34
34
  }, z.core.$strip>>>>;
35
35
  standardEnums: z.ZodOptional<z.ZodArray<z.ZodString>>;
36
- enums: z.ZodOptional<z.ZodArray<z.ZodObject<{
36
+ enums: z.ZodOptional<z.ZodArray<z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodObject<{
37
37
  name: z.ZodString;
38
38
  description: z.ZodDefault<z.ZodOptional<z.ZodString>>;
39
39
  schema: z.ZodOptional<z.ZodString>;
@@ -42,7 +42,7 @@ export declare const zProjectSchemaJSON: z.ZodPipe<z.ZodTransform<unknown, unkno
42
42
  value: z.ZodString;
43
43
  description: z.ZodOptional<z.ZodString>;
44
44
  }, z.core.$strip>, z.ZodString]>>;
45
- }, z.core.$strip>>>;
45
+ }, z.core.$strip>>>>;
46
46
  source: z.ZodRecord<z.ZodString, z.ZodUnknown>;
47
47
  }, z.core.$strip>>;
48
48
  /**
@@ -38,6 +38,7 @@ const zod_1 = require("zod");
38
38
  const utils_1 = require("@postxl/utils");
39
39
  const Enum = __importStar(require("../enum"));
40
40
  const Model = __importStar(require("../model"));
41
+ const normalize_named_collection_1 = require("../normalize-named-collection");
41
42
  exports.zSchemaName = zod_1.z
42
43
  //
43
44
  .string()
@@ -55,6 +56,8 @@ exports.zProjectSchemaJSON = zod_1.z
55
56
  const original = input;
56
57
  return {
57
58
  ...original,
59
+ models: (0, normalize_named_collection_1.normalizeNamedCollection)(original.models),
60
+ enums: (0, normalize_named_collection_1.normalizeNamedCollection)(original.enums),
58
61
  // We omit models from the source fields as we keep the original input in model.source
59
62
  // as part of the model schema.
60
63
  source: (0, utils_1.omit)(original, 'models'),
@@ -38,7 +38,7 @@ export declare const zProjectSchema: z.ZodPipe<z.ZodPipe<z.ZodTransform<unknown,
38
38
  }, z.core.$strip>>;
39
39
  }, z.core.$strip>>>>;
40
40
  standardEnums: z.ZodOptional<z.ZodArray<z.ZodString>>;
41
- enums: z.ZodOptional<z.ZodArray<z.ZodObject<{
41
+ enums: z.ZodOptional<z.ZodArray<z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodObject<{
42
42
  name: z.ZodString;
43
43
  description: z.ZodDefault<z.ZodOptional<z.ZodString>>;
44
44
  schema: z.ZodOptional<z.ZodString>;
@@ -47,7 +47,7 @@ export declare const zProjectSchema: z.ZodPipe<z.ZodPipe<z.ZodTransform<unknown,
47
47
  value: z.ZodString;
48
48
  description: z.ZodOptional<z.ZodString>;
49
49
  }, z.core.$strip>, z.ZodString]>>;
50
- }, z.core.$strip>>>;
50
+ }, z.core.$strip>>>>;
51
51
  source: z.ZodRecord<z.ZodString, z.ZodUnknown>;
52
52
  }, z.core.$strip>>, z.ZodTransform<ProjectSchema, {
53
53
  name: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@postxl/schema",
3
- "version": "1.4.0",
3
+ "version": "1.5.0",
4
4
  "description": "Decoders for PXL Schema definitions and validation for PXL code generation framework",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",
@@ -36,7 +36,7 @@
36
36
  "directory": "packages/schema"
37
37
  },
38
38
  "dependencies": {
39
- "@postxl/utils": "^1.3.1"
39
+ "@postxl/utils": "^1.3.3"
40
40
  },
41
41
  "devDependencies": {},
42
42
  "wallaby": {