@postxl/schema 1.4.1 → 1.6.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.
- package/dist/enum/enum.d.ts +2 -2
- package/dist/enum/enum.json-decoder.d.ts +2 -2
- package/dist/enum/enum.json-decoder.js +12 -2
- package/dist/extract-inline-enums.d.ts +19 -0
- package/dist/extract-inline-enums.js +195 -0
- package/dist/field/discriminated-union.d.ts +2 -2
- package/dist/field/discriminated-union.js +22 -2
- package/dist/field/field.d.ts +2 -2
- package/dist/model/model.json-decoder.js +6 -1
- package/dist/normalize-named-collection.d.ts +35 -0
- package/dist/normalize-named-collection.js +71 -0
- package/dist/project-schema/project-schema.json-decoder.d.ts +2 -2
- package/dist/project-schema/project-schema.json-decoder.js +12 -3
- package/dist/project-schema/project-schema.transformer.d.ts +2 -2
- package/package.json +2 -2
package/dist/enum/enum.d.ts
CHANGED
|
@@ -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
|
|
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.
|
|
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
|
+
}));
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extracts inline enum definitions from model fields and promotes them to top-level enums.
|
|
3
|
+
*
|
|
4
|
+
* When a field's `type` is an object or array (instead of a string), it is treated as an
|
|
5
|
+
* inline enum definition. The enum members are extracted, a name is generated as
|
|
6
|
+
* `{ModelName}{PascalCase(fieldName)}`, and the field's `type` is replaced with that name.
|
|
7
|
+
*
|
|
8
|
+
* Inline enum format examples:
|
|
9
|
+
*
|
|
10
|
+
* Object format:
|
|
11
|
+
* "type": { "Draft": "description", "Published": "description" }
|
|
12
|
+
*
|
|
13
|
+
* Array format:
|
|
14
|
+
* "type": ["Draft", { "value": "Published", "description": "..." }]
|
|
15
|
+
*
|
|
16
|
+
* The field's `description` is copied to the enum and also kept on the field.
|
|
17
|
+
* The enum's database schema is derived from the parent model's `schema` property.
|
|
18
|
+
*/
|
|
19
|
+
export declare function extractInlineEnumDefinitions(input: Record<string, unknown>): Record<string, unknown>;
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.extractInlineEnumDefinitions = extractInlineEnumDefinitions;
|
|
4
|
+
const utils_1 = require("@postxl/utils");
|
|
5
|
+
/**
|
|
6
|
+
* Extracts inline enum definitions from model fields and promotes them to top-level enums.
|
|
7
|
+
*
|
|
8
|
+
* When a field's `type` is an object or array (instead of a string), it is treated as an
|
|
9
|
+
* inline enum definition. The enum members are extracted, a name is generated as
|
|
10
|
+
* `{ModelName}{PascalCase(fieldName)}`, and the field's `type` is replaced with that name.
|
|
11
|
+
*
|
|
12
|
+
* Inline enum format examples:
|
|
13
|
+
*
|
|
14
|
+
* Object format:
|
|
15
|
+
* "type": { "Draft": "description", "Published": "description" }
|
|
16
|
+
*
|
|
17
|
+
* Array format:
|
|
18
|
+
* "type": ["Draft", { "value": "Published", "description": "..." }]
|
|
19
|
+
*
|
|
20
|
+
* The field's `description` is copied to the enum and also kept on the field.
|
|
21
|
+
* The enum's database schema is derived from the parent model's `schema` property.
|
|
22
|
+
*/
|
|
23
|
+
function extractInlineEnumDefinitions(input) {
|
|
24
|
+
const models = input.models;
|
|
25
|
+
if (!models || typeof models !== 'object') {
|
|
26
|
+
return input;
|
|
27
|
+
}
|
|
28
|
+
const extractedEnums = [];
|
|
29
|
+
const existingEnumNames = getExistingEnumNames(input.enums);
|
|
30
|
+
const generatedEnumNames = new Set();
|
|
31
|
+
let modelsModified = false;
|
|
32
|
+
const createProcessField = (modelSchema) => (modelName, fieldName, fieldDef) => {
|
|
33
|
+
const type = fieldDef.type;
|
|
34
|
+
if (type === undefined || type === null || typeof type === 'string') {
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
37
|
+
// type is an object or array — this is an inline enum definition
|
|
38
|
+
const enumName = modelName + (0, utils_1.toPascalCase)(fieldName);
|
|
39
|
+
if (existingEnumNames.has(enumName)) {
|
|
40
|
+
throw new Error(`Inline enum "${enumName}" generated from field "${modelName}.${fieldName}" conflicts with an existing top-level enum of the same name. ` +
|
|
41
|
+
`Rename the field or define the enum in the top-level "enums" section instead.`);
|
|
42
|
+
}
|
|
43
|
+
if (generatedEnumNames.has(enumName)) {
|
|
44
|
+
throw new Error(`Inline enum "${enumName}" generated from field "${modelName}.${fieldName}" conflicts with another inline enum of the same name. ` +
|
|
45
|
+
`Rename one of the fields to avoid the collision.`);
|
|
46
|
+
}
|
|
47
|
+
generatedEnumNames.add(enumName);
|
|
48
|
+
const enumDef = {
|
|
49
|
+
name: enumName,
|
|
50
|
+
members: type,
|
|
51
|
+
};
|
|
52
|
+
// Copy description to the enum (it stays on the field as well)
|
|
53
|
+
if (fieldDef.description !== undefined) {
|
|
54
|
+
enumDef.description = fieldDef.description;
|
|
55
|
+
}
|
|
56
|
+
// Use the parent model's schema for the enum
|
|
57
|
+
if (modelSchema !== undefined) {
|
|
58
|
+
enumDef.schema = modelSchema;
|
|
59
|
+
}
|
|
60
|
+
extractedEnums.push(enumDef);
|
|
61
|
+
// Build the modified field: replace type with enum name, remove schema (not a field property)
|
|
62
|
+
const modifiedField = {};
|
|
63
|
+
for (const [key, value] of Object.entries(fieldDef)) {
|
|
64
|
+
if (key === 'type') {
|
|
65
|
+
modifiedField.type = enumName;
|
|
66
|
+
}
|
|
67
|
+
else if (key === 'schema') {
|
|
68
|
+
// schema is not a field property — skip it
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
modifiedField[key] = value;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return modifiedField;
|
|
76
|
+
};
|
|
77
|
+
let newModels = models;
|
|
78
|
+
if (Array.isArray(models)) {
|
|
79
|
+
const modifiedModels = models.map((model) => {
|
|
80
|
+
if (!model || typeof model !== 'object' || !model.name) {
|
|
81
|
+
return model;
|
|
82
|
+
}
|
|
83
|
+
const modelSchema = model.schema;
|
|
84
|
+
const newFields = processFields(model.name, model.fields, createProcessField(modelSchema));
|
|
85
|
+
if (newFields === undefined) {
|
|
86
|
+
return model;
|
|
87
|
+
}
|
|
88
|
+
modelsModified = true;
|
|
89
|
+
return { ...model, fields: newFields };
|
|
90
|
+
});
|
|
91
|
+
if (modelsModified) {
|
|
92
|
+
newModels = modifiedModels;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
const modifiedModels = {};
|
|
97
|
+
for (const [modelName, modelDef] of Object.entries(models)) {
|
|
98
|
+
if (!modelDef || typeof modelDef !== 'object') {
|
|
99
|
+
modifiedModels[modelName] = modelDef;
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
const model = modelDef;
|
|
103
|
+
const modelSchema = model.schema;
|
|
104
|
+
const newFields = processFields(modelName, model.fields, createProcessField(modelSchema));
|
|
105
|
+
if (newFields === undefined) {
|
|
106
|
+
modifiedModels[modelName] = modelDef;
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
modelsModified = true;
|
|
110
|
+
modifiedModels[modelName] = { ...model, fields: newFields };
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
if (modelsModified) {
|
|
114
|
+
newModels = modifiedModels;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
if (extractedEnums.length === 0) {
|
|
118
|
+
return input;
|
|
119
|
+
}
|
|
120
|
+
return {
|
|
121
|
+
...input,
|
|
122
|
+
models: newModels,
|
|
123
|
+
enums: mergeEnums(input.enums, extractedEnums),
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
function processFields(modelName, fields, processField) {
|
|
127
|
+
if (!fields || typeof fields !== 'object') {
|
|
128
|
+
return undefined;
|
|
129
|
+
}
|
|
130
|
+
let anyModified = false;
|
|
131
|
+
if (Array.isArray(fields)) {
|
|
132
|
+
const modifiedFields = fields.map((field) => {
|
|
133
|
+
if (!field || typeof field !== 'object' || !field.name) {
|
|
134
|
+
return field;
|
|
135
|
+
}
|
|
136
|
+
const result = processField(modelName, field.name, field);
|
|
137
|
+
if (result === undefined) {
|
|
138
|
+
return field;
|
|
139
|
+
}
|
|
140
|
+
anyModified = true;
|
|
141
|
+
return result;
|
|
142
|
+
});
|
|
143
|
+
return anyModified ? modifiedFields : undefined;
|
|
144
|
+
}
|
|
145
|
+
const modifiedFields = {};
|
|
146
|
+
for (const [fieldName, fieldDef] of Object.entries(fields)) {
|
|
147
|
+
if (!fieldDef || typeof fieldDef !== 'object') {
|
|
148
|
+
modifiedFields[fieldName] = fieldDef;
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
const result = processField(modelName, fieldName, fieldDef);
|
|
152
|
+
if (result === undefined) {
|
|
153
|
+
modifiedFields[fieldName] = fieldDef;
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
anyModified = true;
|
|
157
|
+
modifiedFields[fieldName] = result;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return anyModified ? modifiedFields : undefined;
|
|
161
|
+
}
|
|
162
|
+
function getExistingEnumNames(enums) {
|
|
163
|
+
const names = new Set();
|
|
164
|
+
if (Array.isArray(enums)) {
|
|
165
|
+
for (const e of enums) {
|
|
166
|
+
if (e && typeof e === 'object' && typeof e.name === 'string') {
|
|
167
|
+
names.add(e.name);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
else if (enums && typeof enums === 'object') {
|
|
172
|
+
for (const key of Object.keys(enums)) {
|
|
173
|
+
names.add(key);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
return names;
|
|
177
|
+
}
|
|
178
|
+
function mergeEnums(existing, extracted) {
|
|
179
|
+
if (existing === undefined || existing === null) {
|
|
180
|
+
return extracted;
|
|
181
|
+
}
|
|
182
|
+
if (Array.isArray(existing)) {
|
|
183
|
+
return [...existing, ...extracted];
|
|
184
|
+
}
|
|
185
|
+
if (typeof existing === 'object') {
|
|
186
|
+
// Existing enums are in object format — convert extracted enums to object format and merge
|
|
187
|
+
const result = { ...existing };
|
|
188
|
+
for (const enumDef of extracted) {
|
|
189
|
+
const { name, ...rest } = enumDef;
|
|
190
|
+
result[name] = rest;
|
|
191
|
+
}
|
|
192
|
+
return result;
|
|
193
|
+
}
|
|
194
|
+
return existing;
|
|
195
|
+
}
|
|
@@ -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.
|
|
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 {
|
package/dist/field/field.d.ts
CHANGED
|
@@ -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
|
|
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 = {
|
|
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
|
/**
|
|
@@ -37,7 +37,9 @@ exports.zProjectSchemaJSON = exports.zSchemaName = void 0;
|
|
|
37
37
|
const zod_1 = require("zod");
|
|
38
38
|
const utils_1 = require("@postxl/utils");
|
|
39
39
|
const Enum = __importStar(require("../enum"));
|
|
40
|
+
const extract_inline_enums_1 = require("../extract-inline-enums");
|
|
40
41
|
const Model = __importStar(require("../model"));
|
|
42
|
+
const normalize_named_collection_1 = require("../normalize-named-collection");
|
|
41
43
|
exports.zSchemaName = zod_1.z
|
|
42
44
|
//
|
|
43
45
|
.string()
|
|
@@ -53,11 +55,18 @@ exports.zProjectSchemaJSON = zod_1.z
|
|
|
53
55
|
.preprocess((input) => {
|
|
54
56
|
if (typeof input === 'object' && input !== null) {
|
|
55
57
|
const original = input;
|
|
58
|
+
// Extract inline enum definitions from model fields before normalization.
|
|
59
|
+
// This converts inline enum types (objects/arrays in field.type) to top-level enums
|
|
60
|
+
// and replaces the field type with the generated enum name.
|
|
61
|
+
const withExtractedEnums = (0, extract_inline_enums_1.extractInlineEnumDefinitions)(original);
|
|
56
62
|
return {
|
|
57
|
-
...
|
|
63
|
+
...withExtractedEnums,
|
|
64
|
+
models: (0, normalize_named_collection_1.normalizeNamedCollection)(withExtractedEnums.models),
|
|
65
|
+
enums: (0, normalize_named_collection_1.normalizeNamedCollection)(withExtractedEnums.enums),
|
|
58
66
|
// We omit models from the source fields as we keep the original input in model.source
|
|
59
|
-
// as part of the model schema.
|
|
60
|
-
|
|
67
|
+
// as part of the model schema. We use the post-extraction data so that source.enums
|
|
68
|
+
// reflects the extracted inline enums.
|
|
69
|
+
source: (0, utils_1.omit)(withExtractedEnums, 'models'),
|
|
61
70
|
};
|
|
62
71
|
}
|
|
63
72
|
return input;
|
|
@@ -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.
|
|
3
|
+
"version": "1.6.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.
|
|
39
|
+
"@postxl/utils": "^1.3.3"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {},
|
|
42
42
|
"wallaby": {
|