Skip to content

Commit 3221aae

Browse files
authored
fix: reintroduce fix for native enums (#1957)
* fix: reintroduce fix for native enums * fix: try not including previous imports * update samples * update samples
1 parent 82675a4 commit 3221aae

File tree

6 files changed

+102
-83
lines changed

6 files changed

+102
-83
lines changed

packages/core/src/getters/combine.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,18 @@ const combineValues = ({
5151
}
5252

5353
if (separator === 'allOf') {
54-
const joined = `${resolvedData.values.join(` & `)}${
54+
let resolvedDataValue = resolvedData.values.join(` & `);
55+
if (resolvedData.originalSchema.length > 0 && resolvedValue) {
56+
const discriminatedPropertySchemas = resolvedData.originalSchema.filter(
57+
(s) =>
58+
s?.discriminator &&
59+
resolvedValue.value.includes(` ${s.discriminator.propertyName}:`),
60+
) as SchemaObject[];
61+
if (discriminatedPropertySchemas.length > 0) {
62+
resolvedDataValue = `Omit<${resolvedDataValue}, '${discriminatedPropertySchemas.map((s) => s.discriminator?.propertyName).join("' | '")}'>`;
63+
}
64+
}
65+
const joined = `${resolvedDataValue}${
5566
resolvedValue ? ` & ${resolvedValue.value}` : ''
5667
}`;
5768

packages/core/src/getters/object.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ export const getObject = ({
128128
isReadOnly && !context.output.override.suppressReadonlyModifier
129129
? 'readonly '
130130
: ''
131-
}${getKey(key)}${isRequired ? '' : '?'}: ${resolvedValue.isEnum && context.output.override.useNativeEnums ? `(keyof typeof ${resolvedValue.value})` : resolvedValue.value};`;
131+
}${getKey(key)}${isRequired ? '' : '?'}: ${resolvedValue.value};`;
132132
acc.schemas.push(...resolvedValue.schemas);
133133

134134
if (arr.length - 1 === index) {

packages/core/src/resolvers/object.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,7 @@ const resolveObjectOriginal = ({
6969
);
7070

7171
return {
72-
value: context.output.override.useNativeEnums
73-
? `(keyof typeof ${propName})`
74-
: propName,
72+
value: propName,
7573
imports: [{ name: propName }],
7674
schemas: [
7775
...resolvedValue.schemas,

packages/mock/src/faker/getters/scalar.ts

Lines changed: 77 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -141,29 +141,13 @@ export const getMockScalar = ({
141141
);
142142
let numberImports: GeneratorImport[] = [];
143143
if (item.enum) {
144-
// By default the value isn't a reference, so we don't have the object explicitly defined.
145-
// So we have to create an array with the enum values and force them to be a const.
146-
const joinedEnumValues = item.enum.filter(Boolean).join(',');
147-
148-
let enumValue = `[${joinedEnumValues}] as const`;
149-
150-
// But if the value is a reference, we can use the object directly via the imports and using Object.values.
151-
if (item.isRef) {
152-
enumValue = `Object.values(${item.name})`;
153-
numberImports = [
154-
{
155-
name: item.name,
156-
values: true,
157-
...(!isRootKey(context.specKey, context.target)
158-
? { specKey: context.specKey }
159-
: {}),
160-
},
161-
];
162-
}
163-
164-
value = item.path?.endsWith('[]')
165-
? `faker.helpers.arrayElements(${enumValue})`
166-
: `faker.helpers.arrayElement(${enumValue})`;
144+
value = getEnum(
145+
item,
146+
numberImports,
147+
context,
148+
existingReferencedProperties,
149+
'number',
150+
);
167151
} else if ('const' in item) {
168152
value = '' + (item as SchemaObject31).const;
169153
}
@@ -205,7 +189,6 @@ export const getMockScalar = ({
205189
value,
206190
enums,
207191
imports: resolvedImports,
208-
name,
209192
} = resolveMockValue({
210193
schema: {
211194
...item.items,
@@ -223,32 +206,9 @@ export const getMockScalar = ({
223206
});
224207

225208
if (enums) {
226-
if (!isReference(item.items)) {
227-
return {
228-
value,
229-
imports: resolvedImports,
230-
name: item.name,
231-
};
232-
}
233-
234-
const enumImp = imports.find(
235-
(imp) => name.replace('[]', '') === imp.name,
236-
);
237-
const enumValue = enumImp?.name || name;
238209
return {
239-
value: `faker.helpers.arrayElements(Object.values(${enumValue}))`,
240-
imports: enumImp
241-
? [
242-
...resolvedImports,
243-
{
244-
...enumImp,
245-
values: true,
246-
...(!isRootKey(context.specKey, context.target)
247-
? { specKey: context.specKey }
248-
: {}),
249-
},
250-
]
251-
: resolvedImports,
210+
value,
211+
imports: resolvedImports,
252212
name: item.name,
253213
};
254214
}
@@ -272,35 +232,16 @@ export const getMockScalar = ({
272232

273233
case 'string': {
274234
let value = 'faker.string.alpha(20)';
275-
let imports: GeneratorImport[] = [];
235+
let stringImports: GeneratorImport[] = [];
276236

277237
if (item.enum) {
278-
// By default the value isn't a reference, so we don't have the object explicitly defined.
279-
// So we have to create an array with the enum values and force them to be a const.
280-
const joindEnumValues = item.enum
281-
.filter(Boolean)
282-
.map((e) => escape(e))
283-
.join("','");
284-
285-
let enumValue = `['${joindEnumValues}'] as const`;
286-
287-
// But if the value is a reference, we can use the object directly via the imports and using Object.values.
288-
if (item.isRef) {
289-
enumValue = `Object.values(${item.name})`;
290-
imports = [
291-
{
292-
name: item.name,
293-
values: true,
294-
...(!isRootKey(context.specKey, context.target)
295-
? { specKey: context.specKey }
296-
: {}),
297-
},
298-
];
299-
}
300-
301-
value = item.path?.endsWith('[]')
302-
? `faker.helpers.arrayElements(${enumValue})`
303-
: `faker.helpers.arrayElement(${enumValue})`;
238+
value = getEnum(
239+
item,
240+
stringImports,
241+
context,
242+
existingReferencedProperties,
243+
'string',
244+
);
304245
} else if (item.pattern) {
305246
value = `faker.helpers.fromRegExp('${item.pattern}')`;
306247
} else if ('const' in item) {
@@ -311,7 +252,7 @@ export const getMockScalar = ({
311252
value: getNullable(value, item.nullable),
312253
enums: item.enum,
313254
name: item.name,
314-
imports,
255+
imports: stringImports,
315256
};
316257
}
317258

@@ -355,3 +296,62 @@ function getItemType(item: MockSchemaObject) {
355296
if (!type) return;
356297
return ['string', 'number'].includes(type) ? type : undefined;
357298
}
299+
300+
const getEnum = (
301+
item: MockSchemaObject,
302+
imports: GeneratorImport[],
303+
context: ContextSpecs,
304+
existingReferencedProperties: string[],
305+
type: 'string' | 'number',
306+
) => {
307+
if (!item.enum) return '';
308+
const joindEnumValues =
309+
type === 'string'
310+
? `'${item.enum
311+
.filter((e) => e !== null)
312+
.map((e) => escape(e))
313+
.join("','")}'`
314+
: item.enum.filter((e) => e !== null).join(',');
315+
316+
let enumValue = `[${joindEnumValues}]`;
317+
if (context.output.override.useNativeEnums) {
318+
if (item.isRef || existingReferencedProperties.length === 0) {
319+
enumValue += ` as ${item.name}${item.name.endsWith('[]') ? '' : '[]'}`;
320+
imports.push({
321+
name: item.name,
322+
...(!isRootKey(context.specKey, context.target)
323+
? { specKey: context.specKey }
324+
: {}),
325+
});
326+
} else {
327+
enumValue += ` as ${existingReferencedProperties[existingReferencedProperties.length - 1]}['${item.name}']`;
328+
if (!item.path?.endsWith('[]')) enumValue += '[]';
329+
imports.push({
330+
name: existingReferencedProperties[
331+
existingReferencedProperties.length - 1
332+
],
333+
...(!isRootKey(context.specKey, context.target)
334+
? { specKey: context.specKey }
335+
: {}),
336+
});
337+
}
338+
} else {
339+
enumValue += ' as const';
340+
}
341+
342+
// But if the value is a reference, we can use the object directly via the imports and using Object.values.
343+
if (item.isRef && type === 'string') {
344+
enumValue = `Object.values(${item.name})`;
345+
imports.push({
346+
name: item.name,
347+
values: true,
348+
...(!isRootKey(context.specKey, context.target)
349+
? { specKey: context.specKey }
350+
: {}),
351+
});
352+
}
353+
354+
return item.path?.endsWith('[]')
355+
? `faker.helpers.arrayElements(${enumValue})`
356+
: `faker.helpers.arrayElement(${enumValue})`;
357+
};

tests/configs/swr.config.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,9 @@ export default defineConfig({
212212
schemas: '../generated/swr/enums/model',
213213
client: 'swr',
214214
mock: true,
215+
override: {
216+
useNativeEnums: true,
217+
},
215218
},
216219
input: {
217220
target: '../specifications/enums.yaml',

tests/specifications/enums.yaml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ paths:
1212
content:
1313
application/json:
1414
schema:
15-
$ref: '#/components/schemas/Cat'
15+
type: array
16+
items:
17+
$ref: '#/components/schemas/DogGroup'
1618
/api/required-cat:
1719
get:
1820
summary: sample required cat
@@ -75,6 +77,11 @@ components:
7577
type: array
7678
items:
7779
type: string
80+
x-enumNames:
81+
- Black
82+
- Brown
83+
- White
84+
- Grey
7885
enum:
7986
- BLACK
8087
- BROWN

0 commit comments

Comments
 (0)