Skip to content

Commit

Permalink
fix: make order of imports and object properties deterministic (#965)
Browse files Browse the repository at this point in the history
  • Loading branch information
GMierzwa authored Oct 19, 2023
1 parent 8a12c3d commit a4cca88
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 87 deletions.
22 changes: 21 additions & 1 deletion packages/core/src/generators/imports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,9 @@ const generateDependency = ({
deps
.filter((e) => !e.default && !e.syntheticDefaultImport)
.map(({ name, alias }) => (alias ? `${name} as ${alias}` : name)),
).join(',\n ');
)
.sort()
.join(',\n ');

let importString = '';

Expand Down Expand Up @@ -246,6 +248,11 @@ export const addDependency = ({
.join('\n');
};

const getLibName = (code: string) => {
const splitString = code.split(' from ');
return splitString[splitString.length - 1].split(';')[0].trim();
};

export const generateDependencyImports = (
implementation: string,
imports: {
Expand All @@ -267,6 +274,19 @@ export const generateDependencyImports = (
}),
)
.filter(Boolean)
.sort((a, b) => {
const aLib = getLibName(a!);
const bLib = getLibName(b!);

if (aLib === bLib) {
return 0;
}

if (aLib.startsWith("'.") && !bLib.startsWith("'.")) {
return 1;
}
return aLib < bLib ? -1 : 1;
})
.join('\n');

return dependencies ? dependencies + '\n' : '';
Expand Down
162 changes: 83 additions & 79 deletions packages/core/src/getters/object.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,90 +58,94 @@ export const getObject = ({
}

if (item.properties && Object.entries(item.properties).length > 0) {
return Object.entries(item.properties).reduce(
(
acc,
[key, schema]: [string, ReferenceObject | SchemaObject],
index,
arr,
) => {
const isRequired = (
Array.isArray(item.required) ? item.required : []
).includes(key);

let propName = '';

if (name) {
const isKeyStartWithUnderscore = key.startsWith('_');

propName += pascal(
`${isKeyStartWithUnderscore ? '_' : ''}${name}_${key}`,
return Object.entries(item.properties)
.sort((a, b) => {
return a[0].localeCompare(b[0]);
})
.reduce(
(
acc,
[key, schema]: [string, ReferenceObject | SchemaObject],
index,
arr,
) => {
const isRequired = (
Array.isArray(item.required) ? item.required : []
).includes(key);

let propName = '';

if (name) {
const isKeyStartWithUnderscore = key.startsWith('_');

propName += pascal(
`${isKeyStartWithUnderscore ? '_' : ''}${name}_${key}`,
);
}

const allSpecSchemas =
context.specs[context.target]?.components?.schemas ?? {};

const isNameAlreadyTaken = Object.keys(allSpecSchemas).some(
(schemaName) => pascal(schemaName) === propName,
);
}

const allSpecSchemas =
context.specs[context.target]?.components?.schemas ?? {};

const isNameAlreadyTaken = Object.keys(allSpecSchemas).some(
(schemaName) => pascal(schemaName) === propName,
);

if (isNameAlreadyTaken) {
propName = propName + 'Property';
}

const resolvedValue = resolveObject({
schema,
propName,
context,
});

const isReadOnly = item.readOnly || (schema as SchemaObject).readOnly;
if (!index) {
acc.value += '{';
}

const doc = jsDoc(schema as SchemaObject, true);

acc.hasReadonlyProps ||= isReadOnly || false;
acc.imports.push(...resolvedValue.imports);
acc.value += `\n ${doc ? `${doc} ` : ''}${
isReadOnly ? 'readonly ' : ''
}${getKey(key)}${isRequired ? '' : '?'}: ${resolvedValue.value};`;
acc.schemas.push(...resolvedValue.schemas);

if (arr.length - 1 === index) {
if (item.additionalProperties) {
if (isBoolean(item.additionalProperties)) {
acc.value += `\n [key: string]: any;\n }`;

if (isNameAlreadyTaken) {
propName = propName + 'Property';
}

const resolvedValue = resolveObject({
schema,
propName,
context,
});

const isReadOnly = item.readOnly || (schema as SchemaObject).readOnly;
if (!index) {
acc.value += '{';
}

const doc = jsDoc(schema as SchemaObject, true);

acc.hasReadonlyProps ||= isReadOnly || false;
acc.imports.push(...resolvedValue.imports);
acc.value += `\n ${doc ? `${doc} ` : ''}${
isReadOnly ? 'readonly ' : ''
}${getKey(key)}${isRequired ? '' : '?'}: ${resolvedValue.value};`;
acc.schemas.push(...resolvedValue.schemas);

if (arr.length - 1 === index) {
if (item.additionalProperties) {
if (isBoolean(item.additionalProperties)) {
acc.value += `\n [key: string]: any;\n }`;
} else {
const resolvedValue = resolveValue({
schema: item.additionalProperties,
name,
context,
});
acc.value += `\n [key: string]: ${resolvedValue.value};\n}`;
}
} else {
const resolvedValue = resolveValue({
schema: item.additionalProperties,
name,
context,
});
acc.value += `\n [key: string]: ${resolvedValue.value};\n}`;
acc.value += '\n}';
}
} else {
acc.value += '\n}';
}

acc.value += nullable;
}
acc.value += nullable;
}

return acc;
},
{
imports: [],
schemas: [],
value: '',
isEnum: false,
type: 'object' as SchemaType,
isRef: false,
schema: {},
hasReadonlyProps: false,
} as ScalarValue,
);
return acc;
},
{
imports: [],
schemas: [],
value: '',
isEnum: false,
type: 'object' as SchemaType,
isRef: false,
schema: {},
hasReadonlyProps: false,
} as ScalarValue,
);
}

if (item.additionalProperties) {
Expand Down
3 changes: 3 additions & 0 deletions packages/msw/src/getters/object.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ export const getMockObject = ({
let imports: GeneratorImport[] = [];
let includedProperties: string[] = [];
value += Object.entries(item.properties)
.sort((a, b) => {
return a[0].localeCompare(b[0]);
})
.map(([key, prop]: [string, ReferenceObject | SchemaObject]) => {
if (combine?.includedProperties.includes(key)) {
return undefined;
Expand Down
18 changes: 11 additions & 7 deletions packages/msw/src/getters/scalar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,17 @@ export const getMockScalar = ({
return operationProperty;
}

const overrideTag = Object.entries(mockOptions?.tags ?? {}).reduce<{
properties: Record<string, string>;
}>(
(acc, [tag, options]) =>
tags.includes(tag) ? mergeDeep(acc, options) : acc,
{} as { properties: Record<string, string> },
);
const overrideTag = Object.entries(mockOptions?.tags ?? {})
.sort((a, b) => {
return a[0].localeCompare(b[0]);
})
.reduce<{
properties: Record<string, string>;
}>(
(acc, [tag, options]) =>
tags.includes(tag) ? mergeDeep(acc, options) : acc,
{} as { properties: Record<string, string> },
);

const tagProperty = resolveMockOverride(overrideTag?.properties, item);

Expand Down

1 comment on commit a4cca88

@vercel
Copy link

@vercel vercel bot commented on a4cca88 Oct 19, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.