Skip to content

Commit

Permalink
fix(msw): simplify combine
Browse files Browse the repository at this point in the history
  • Loading branch information
AllieJonsson committed Jan 13, 2025
1 parent 9643099 commit 295377f
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 136 deletions.
179 changes: 55 additions & 124 deletions packages/mock/src/faker/getters/combine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,143 +67,74 @@ export const combineSchemasMock = ({
includedProperties.push(...(itemResolvedValue?.includedProperties ?? []));
combineImports.push(...(itemResolvedValue?.imports ?? []));

const value = (item[separator] ?? []).reduce((acc, val, index, arr) => {
if (
'$ref' in val &&
existingReferencedProperties.includes(pascal(val.$ref.split('/').pop()!))
) {
if (arr.length === 1) {
return 'undefined';
}

return acc;
}

// the required fields in this schema need to be considered
// in the sub schema under the allOf key
if (separator === 'allOf' && item.required) {
if (isSchema(val) && val.required) {
val = { ...val, required: [...item.required, ...val.required] };
} else {
val = { ...val, required: item.required };
}
}

const resolvedValue = resolveMockValue({
schema: {
...val,
name: item.name,
path: item.path ? item.path : '#',
},
combine: {
separator,
includedProperties:
separator !== 'oneOf'
? includedProperties
: itemResolvedValue?.includedProperties ?? [],
},
mockOptions,
operationId,
tags,
context,
imports,
existingReferencedProperties,
splitMockImplementations,
});

combineImports.push(...resolvedValue.imports);
includedProperties.push(...(resolvedValue.includedProperties ?? []));

const isLastElement = index === arr.length - 1;

let currentValue = resolvedValue.value;

if (itemResolvedValue?.value && separator === 'oneOf') {
const splitValues = resolvedValue.value.split('},{');
const joined = splitValues.join(`,${itemResolvedValue.value}},{`);
currentValue = `${joined.slice(0, -1)},${itemResolvedValue.value}}`;
}

if (itemResolvedValue?.value && separator !== 'oneOf' && isLastElement) {
currentValue = `${currentValue ? `${currentValue},` : ''}${itemResolvedValue.value}`;
}

if (
resolvedValue.type === undefined &&
currentValue &&
separator === 'allOf'
) {
currentValue = `...${currentValue}`;
}

const isObjectBounds =
!combine ||
(['oneOf', 'anyOf'].includes(combine.separator) && separator === 'allOf');

if (!index && isObjectBounds) {
const value = (item[separator] ?? []).reduce(
(acc, val, _, arr) => {
if (
resolvedValue.enums ||
separator === 'oneOf' ||
separator === 'anyOf' ||
resolvedValue.type === 'array'
'$ref' in val &&
existingReferencedProperties.includes(
pascal(val.$ref.split('/').pop()!),
)
) {
if (arr.length === 1) {
return `faker.helpers.arrayElement([${currentValue}])`;
return 'undefined';
}
return `faker.helpers.arrayElement([${currentValue},`;
}

if (arr.length === 1) {
if (resolvedValue.type && resolvedValue.type !== 'object') {
return currentValue;
}
return `{${currentValue}}`;
}

if (currentValue) {
return `{${currentValue},`;
return acc;
}
return '{';
}

if (isLastElement) {
if (
resolvedValue.enums ||
separator === 'oneOf' ||
separator === 'anyOf' ||
resolvedValue.type === 'array'
) {
return `${acc}${currentValue}${!combine ? '])' : ''}`;
}

if (currentValue === '{}') {
currentValue = '';

if (acc.toString().endsWith(',')) {
acc = acc.toString().slice(0, -1);
// the required fields in this schema need to be considered
// in the sub schema under the allOf key
if (separator === 'allOf' && item.required) {
if (isSchema(val) && val.required) {
val = { ...val, required: [...item.required, ...val.required] };
} else {
val = { ...val, required: item.required };
}
}

return `${acc}${currentValue}${isObjectBounds ? '}' : ''}`;
}

if (currentValue === '{}') {
currentValue = '';

if (acc.toString().endsWith(',')) {
acc = acc.toString().slice(0, -1);
const resolvedValue = resolveMockValue({
schema: {
...val,
name: item.name,
path: item.path ? item.path : '#',
},
combine: {
separator,
includedProperties:
separator !== 'oneOf'
? includedProperties
: itemResolvedValue?.includedProperties ?? [],
},
mockOptions,
operationId,
tags,
context,
imports,
existingReferencedProperties,
splitMockImplementations,
});

combineImports.push(...resolvedValue.imports);
includedProperties.push(...(resolvedValue.includedProperties ?? []));

if (resolvedValue.value === '{}') return acc;
if (resolvedValue.value.startsWith('{')) {
return `${acc}${separator === 'allOf' ? '...' : ''}${resolvedValue.value},`;
}
}

if (!currentValue) {
return acc;
}

return `${acc}${currentValue},`;
}, '');
return `${acc}${resolvedValue.value},`;
},
`${combine ? '...' : ''}${separator === 'allOf' ? '{' : 'faker.helpers.arrayElement(['}`,
);
let finalValue =
value === 'undefined'
? value
: `${value}${separator === 'allOf' ? '}' : '])'}`;
if (itemResolvedValue) {
finalValue = `{${finalValue.startsWith('...') ? '' : '...'}${finalValue}, ${itemResolvedValue.value}}`;
}

return {
value: value,
value: finalValue,
imports: combineImports,
name: item.name,
includedProperties,
Expand Down
5 changes: 1 addition & 4 deletions packages/mock/src/faker/resolvers/value.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,10 +141,7 @@ export const resolveMockValue = ({
}

const args = `${overrideVarName}: ${type} = {}`;
const value = newSchema.oneOf
? `faker.helpers.arrayElement([${scalar.value}])`
: scalar.value;
const func = `export const ${funcName} = (${args}): ${newSchema.name} => ({...${value}, ...${overrideVarName}});`;
const func = `export const ${funcName} = (${args}): ${newSchema.name} => ({${scalar.value.startsWith('...') ? '' : '...'}${scalar.value}, ...${overrideVarName}});`;
splitMockImplementations?.push(func);
}

Expand Down
8 changes: 8 additions & 0 deletions tests/configs/default.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,14 @@ export default defineConfig({
target: '../generated/default/default-status/endpoints.ts',
},
},
'all-of-one-of': {
input: '../specifications/all-of-one-of.yaml',
output: {
schemas: '../generated/default/all-of-one-of/model',
target: '../generated/default/all-of-one-of/endpoints.ts',
mock: true,
},
},
'circular-v2': {
input: '../specifications/circular-v2.yaml',
output: {
Expand Down
38 changes: 38 additions & 0 deletions tests/specifications/all-of-one-of.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
openapi: 3.0.1
info:
version: 1.0.0
title: any-of-one-of
paths:
/something:
post:
responses:
'200':
description: Something
content:
application/json:
schema:
type: object
properties:
uploads:
type: array
items:
allOf:
- type: object
properties:
file_type:
type: string
- oneOf:
- type: object
properties:
type:
type: string
enum:
- a
- type: object
properties:
type:
type: string
enum:
- b
other:
type: string
30 changes: 22 additions & 8 deletions tests/specifications/all-of.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -65,17 +65,31 @@ components:
allOf:
- $ref: '#/components/schemas/Pet'
- $ref: '#/components/schemas/PetDetail'
Pet:
NestedPet:
allOf:
- $ref: '#/components/schemas/DoublyNestedPet'
- type: object
properties:
nest:
type: integer
DoublyNestedPet:
type: object
required:
- id
- name
properties:
id:
doubleNest:
type: integer
format: int64
name:
type: string
Pet:
allOf:
- $ref: '#/components/schemas/NestedPet'
- type: object
required:
- id
- name
properties:
id:
type: integer
format: int64
name:
type: string
PetDetail:
type: object
required:
Expand Down

0 comments on commit 295377f

Please sign in to comment.