fixed tests

This commit is contained in:
Ferdi Koomen 2025-12-22 20:05:37 +01:00
parent fc485636a4
commit f22a696a39
35 changed files with 131 additions and 75 deletions

View File

@ -1,5 +0,0 @@
dist
samples
test/generated
test/e2e/generated
node_modules

View File

@ -1,25 +0,0 @@
{
"parser": "@typescript-eslint/parser",
"extends": ["plugin:@typescript-eslint/recommended", "plugin:prettier/recommended", "prettier"],
"env": {
"es6": true,
"node": true,
"jest": true
},
"plugins": ["simple-import-sort"],
"rules": {
"@typescript-eslint/no-explicit-any": 0,
"@typescript-eslint/no-inferrable-types": 0,
"@typescript-eslint/no-non-null-assertion": 0,
"@typescript-eslint/no-var-requires": 0,
"@typescript-eslint/ban-ts-ignore": 0,
"@typescript-eslint/ban-ts-comment": 0,
"@typescript-eslint/explicit-function-return-type": 0,
"@typescript-eslint/explicit-module-boundary-types": 0,
"sort-imports": "off",
"import/order": "off",
"simple-import-sort/imports": "error",
"simple-import-sort/exports": "error",
"prettier/prettier": ["error"]
}
}

43
eslint.config.mjs Normal file
View File

@ -0,0 +1,43 @@
import javascript from '@eslint/js';
import prettierConfig from 'eslint-plugin-prettier/recommended';
import simpleImportSort from 'eslint-plugin-simple-import-sort';
import globals from 'globals';
import typescript from 'typescript-eslint';
export default [
{
ignores: ['dist', 'samples', 'test/generated', 'test/e2e/generated', 'node_modules'],
},
javascript.configs.recommended,
...typescript.configs.recommended,
prettierConfig,
{
languageOptions: {
globals: {
...globals.node,
...globals.browser,
...globals.jest,
...globals.es2019,
},
},
plugins: {
'simple-import-sort': simpleImportSort,
},
rules: {
'@typescript-eslint/no-explicit-any': 0,
'@typescript-eslint/no-inferrable-types': 0,
'@typescript-eslint/no-non-null-assertion': 0,
'@typescript-eslint/no-var-requires': 0,
'@typescript-eslint/no-require-imports': 0,
'@typescript-eslint/ban-ts-ignore': 0,
'@typescript-eslint/ban-ts-comment': 0,
'@typescript-eslint/explicit-function-return-type': 0,
'@typescript-eslint/explicit-module-boundary-types': 0,
'sort-imports': 'off',
'import/order': 'off',
'simple-import-sort/imports': 'error',
'simple-import-sort/exports': 'error',
'prettier/prettier': ['error'],
},
},
];

46
package-lock.json generated
View File

@ -34,6 +34,7 @@
"@babel/core": "7.28.5",
"@babel/preset-env": "7.28.5",
"@babel/preset-typescript": "7.28.5",
"@eslint/js": "9.39.2",
"@rollup/plugin-commonjs": "29.0.0",
"@rollup/plugin-node-resolve": "16.0.3",
"@rollup/plugin-terser": "0.4.4",
@ -58,6 +59,7 @@
"express": "5.2.1",
"form-data": "4.0.5",
"glob": "13.0.0",
"globals": "16.5.0",
"jest": "30.2.0",
"jest-cli": "30.2.0",
"node-fetch": "2.7.0",
@ -70,6 +72,7 @@
"ts-node": "10.9.2",
"tslib": "2.8.1",
"typescript": "5.9.3",
"typescript-eslint": "8.50.1",
"zone.js": "0.16.0"
}
},
@ -3837,6 +3840,19 @@
"concat-map": "0.0.1"
}
},
"node_modules/@eslint/eslintrc/node_modules/globals": {
"version": "14.0.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz",
"integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/@eslint/eslintrc/node_modules/ignore": {
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
@ -12091,9 +12107,9 @@
}
},
"node_modules/globals": {
"version": "14.0.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz",
"integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==",
"version": "16.5.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-16.5.0.tgz",
"integrity": "sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==",
"dev": true,
"license": "MIT",
"engines": {
@ -18572,6 +18588,30 @@
"node": ">=14.17"
}
},
"node_modules/typescript-eslint": {
"version": "8.50.1",
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.50.1.tgz",
"integrity": "sha512-ytTHO+SoYSbhAH9CrYnMhiLx8To6PSSvqnvXyPUgPETCvB6eBKmTI9w6XMPS3HsBRGkwTVBX+urA8dYQx6bHfQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/eslint-plugin": "8.50.1",
"@typescript-eslint/parser": "8.50.1",
"@typescript-eslint/typescript-estree": "8.50.1",
"@typescript-eslint/utils": "8.50.1"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
},
"peerDependencies": {
"eslint": "^8.57.0 || ^9.0.0",
"typescript": ">=4.8.4 <6.0.0"
}
},
"node_modules/uglify-js": {
"version": "3.19.3",
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz",

View File

@ -82,6 +82,7 @@
"@babel/core": "7.28.5",
"@babel/preset-env": "7.28.5",
"@babel/preset-typescript": "7.28.5",
"@eslint/js": "9.39.2",
"@rollup/plugin-commonjs": "29.0.0",
"@rollup/plugin-node-resolve": "16.0.3",
"@rollup/plugin-terser": "0.4.4",
@ -105,6 +106,7 @@
"eslint-plugin-simple-import-sort": "12.1.1",
"express": "5.2.1",
"form-data": "4.0.5",
"globals": "16.5.0",
"glob": "13.0.0",
"jest": "30.2.0",
"jest-cli": "30.2.0",
@ -118,6 +120,7 @@
"ts-node": "10.9.2",
"tslib": "2.8.1",
"typescript": "5.9.3",
"typescript-eslint": "8.50.1",
"zone.js": "0.16.0"
}
}

View File

@ -12,7 +12,7 @@ export type GetModelFn = typeof getModel;
export const getModelProperties = (openApi: OpenApi, definition: OpenApiSchema, getModel: GetModelFn): Model[] => {
const models: Model[] = [];
for (const propertyName in definition.properties) {
if (definition.properties.hasOwnProperty(propertyName)) {
if (Object.prototype.hasOwnProperty.call(definition.properties, propertyName)) {
const property = definition.properties[propertyName];
const propertyRequired = !!definition.required?.includes(propertyName);
if (property.$ref) {

View File

@ -7,7 +7,7 @@ import { getType } from './getType';
export const getModels = (openApi: OpenApi): Model[] => {
const models: Model[] = [];
for (const definitionName in openApi.definitions) {
if (openApi.definitions.hasOwnProperty(definitionName)) {
if (Object.prototype.hasOwnProperty.call(openApi.definitions, definitionName)) {
const definition = openApi.definitions[definitionName];
const definitionType = getType(definitionName);
const model = getModel(openApi, definition, true, definitionType.base.replace(reservedWords, '_$1'));

View File

@ -10,7 +10,7 @@ export const getOperationName = (url: string, method: string, operationId?: stri
return camelCase(
operationId
.replace(/^[^a-zA-Z]+/g, '')
.replace(/[^\w\-]+/g, '-')
.replace(/[^\w-]+/g, '-')
.trim()
);
}

View File

@ -33,7 +33,7 @@ export const getOperationParameterDefault = (
case 'object':
try {
return JSON.stringify(parameter.default, null, 4);
} catch (e) {
} catch {
// Ignore
}
}

View File

@ -9,7 +9,7 @@ import { reservedWords } from '../../../utils/reservedWords';
export const getOperationParameterName = (value: string): string => {
const clean = value
.replace(/^[^a-zA-Z]+/g, '')
.replace(/[^\w\-]+/g, '-')
.replace(/[^\w-]+/g, '-')
.trim();
return camelCase(clean).replace(reservedWords, '_$1');
};

View File

@ -85,7 +85,7 @@ export const getOperationResponse = (
// fetch and XHR client just support string types.
if (response.headers) {
for (const name in response.headers) {
if (response.headers.hasOwnProperty(name)) {
if (Object.prototype.hasOwnProperty.call(response.headers, name)) {
operationResponse.in = 'header';
operationResponse.name = name;
operationResponse.type = 'string';

View File

@ -12,7 +12,7 @@ export const getOperationResponses = (openApi: OpenApi, responses: OpenApiRespon
// Iterate over each response code and get the
// status code and response message (if any).
for (const code in responses) {
if (responses.hasOwnProperty(code)) {
if (Object.prototype.hasOwnProperty.call(responses, code)) {
const responseOrReference = responses[code];
const response = getRef<OpenApiResponse>(openApi, responseOrReference);
const responseCode = getOperationResponseCode(code);

View File

@ -20,7 +20,7 @@ export const getRef = <T>(openApi: OpenApi, item: T & OpenApiReference): T => {
const decodedPath = decodeURIComponent(
path.replace(ESCAPED_REF_SLASH, '/').replace(ESCAPED_REF_TILDE, '~')
);
if (result.hasOwnProperty(decodedPath)) {
if (Object.prototype.hasOwnProperty.call(result, decodedPath)) {
result = result[decodedPath];
} else {
throw new Error(`Could not find reference: "${item.$ref}"`);

View File

@ -7,7 +7,7 @@ import camelCase from 'camelcase';
export const getServiceName = (value: string): string => {
const clean = value
.replace(/^[^a-zA-Z]+/g, '')
.replace(/[^\w\-]+/g, '-')
.replace(/[^\w-]+/g, '-')
.trim();
return camelCase(clean, { pascalCase: true });
};

View File

@ -10,14 +10,14 @@ import { getOperationParameters } from './getOperationParameters';
export const getServices = (openApi: OpenApi): Service[] => {
const services = new Map<string, Service>();
for (const url in openApi.paths) {
if (openApi.paths.hasOwnProperty(url)) {
if (Object.prototype.hasOwnProperty.call(openApi.paths, url)) {
// Grab path and parse any global path parameters
const path = openApi.paths[url];
const pathParams = getOperationParameters(openApi, path.parameters || []);
// Parse all the methods for this path
for (const method in path) {
if (path.hasOwnProperty(method)) {
if (Object.prototype.hasOwnProperty.call(path, method)) {
switch (method) {
case 'get':
case 'put':
@ -25,7 +25,7 @@ export const getServices = (openApi: OpenApi): Service[] => {
case 'delete':
case 'options':
case 'head':
case 'patch':
case 'patch': {
// Each method contains an OpenAPI operation, we parse the operation
const op = path[method]!;
const tags = op.tags?.length ? op.tags.filter(unique) : ['Default'];
@ -46,6 +46,7 @@ export const getServices = (openApi: OpenApi): Service[] => {
services.set(operation.service, service);
});
break;
}
}
}
}

View File

@ -30,7 +30,7 @@ export const getModelDefault = (definition: OpenApiSchema, model?: Model): strin
case 'object':
try {
return JSON.stringify(definition.default, null, 4);
} catch (e) {
} catch {
// Ignore
}
}

View File

@ -19,7 +19,7 @@ export const getModelProperties = (
const models: Model[] = [];
const discriminator = findOneOfParentDiscriminator(openApi, parent);
for (const propertyName in definition.properties) {
if (definition.properties.hasOwnProperty(propertyName)) {
if (Object.prototype.hasOwnProperty.call(definition.properties, propertyName)) {
const property = definition.properties[propertyName];
const propertyRequired = !!definition.required?.includes(propertyName);
const propertyValues: Omit<

View File

@ -8,7 +8,7 @@ export const getModels = (openApi: OpenApi): Model[] => {
const models: Model[] = [];
if (openApi.components) {
for (const definitionName in openApi.components.schemas) {
if (openApi.components.schemas.hasOwnProperty(definitionName)) {
if (Object.prototype.hasOwnProperty.call(openApi.components.schemas, definitionName)) {
const definition = openApi.components.schemas[definitionName];
const definitionType = getType(definitionName);
const model = getModel(openApi, definition, true, definitionType.base.replace(reservedWords, '_$1'));
@ -16,7 +16,7 @@ export const getModels = (openApi: OpenApi): Model[] => {
}
}
for (const definitionName in openApi.components.parameters) {
if (openApi.components.parameters.hasOwnProperty(definitionName)) {
if (Object.prototype.hasOwnProperty.call(openApi.components.parameters, definitionName)) {
const definition = openApi.components.parameters[definitionName];
const definitionType = getType(definitionName);
const schema = definition.schema;

View File

@ -10,7 +10,7 @@ export const getOperationName = (url: string, method: string, operationId?: stri
return camelCase(
operationId
.replace(/^[^a-zA-Z]+/g, '')
.replace(/[^\w\-]+/g, '-')
.replace(/[^\w-]+/g, '-')
.trim()
);
}

View File

@ -10,7 +10,7 @@ export const getOperationParameterName = (value: string): string => {
const clean = value
.replace(/^[^a-zA-Z]+/g, '')
.replace('[]', 'Array')
.replace(/[^\w\-]+/g, '-')
.replace(/[^\w-]+/g, '-')
.trim();
return camelCase(clean).replace(reservedWords, '_$1');
};

View File

@ -84,7 +84,7 @@ export const getOperationResponse = (
// fetch and XHR client just support string types.
if (response.headers) {
for (const name in response.headers) {
if (response.headers.hasOwnProperty(name)) {
if (Object.prototype.hasOwnProperty.call(response.headers, name)) {
operationResponse.in = 'header';
operationResponse.name = name;
operationResponse.type = 'string';

View File

@ -12,7 +12,7 @@ export const getOperationResponses = (openApi: OpenApi, responses: OpenApiRespon
// Iterate over each response code and get the
// status code and response message (if any).
for (const code in responses) {
if (responses.hasOwnProperty(code)) {
if (Object.prototype.hasOwnProperty.call(responses, code)) {
const responseOrReference = responses[code];
const response = getRef<OpenApiResponse>(openApi, responseOrReference);
const responseCode = getOperationResponseCode(code);

View File

@ -20,7 +20,7 @@ export const getRef = <T>(openApi: OpenApi, item: T & OpenApiReference): T => {
const decodedPath = decodeURIComponent(
path.replace(ESCAPED_REF_SLASH, '/').replace(ESCAPED_REF_TILDE, '~')
);
if (result.hasOwnProperty(decodedPath)) {
if (Object.prototype.hasOwnProperty.call(result, decodedPath)) {
result = result[decodedPath];
} else {
throw new Error(`Could not find reference: "${item.$ref}"`);

View File

@ -5,7 +5,7 @@ export const getServer = (openApi: OpenApi): string => {
const variables = server?.variables || {};
let url = server?.url || '';
for (const variable in variables) {
if (variables.hasOwnProperty(variable)) {
if (Object.prototype.hasOwnProperty.call(variables, variable)) {
url = url.replace(`{${variable}}`, variables[variable].default);
}
}

View File

@ -7,7 +7,7 @@ import camelCase from 'camelcase';
export const getServiceName = (value: string): string => {
const clean = value
.replace(/^[^a-zA-Z]+/g, '')
.replace(/[^\w\-]+/g, '-')
.replace(/[^\w-]+/g, '-')
.trim();
return camelCase(clean, { pascalCase: true });
};

View File

@ -10,14 +10,14 @@ import { getOperationParameters } from './getOperationParameters';
export const getServices = (openApi: OpenApi): Service[] => {
const services = new Map<string, Service>();
for (const url in openApi.paths) {
if (openApi.paths.hasOwnProperty(url)) {
if (Object.prototype.hasOwnProperty.call(openApi.paths, url)) {
// Grab path and parse any global path parameters
const path = openApi.paths[url];
const pathParams = getOperationParameters(openApi, path.parameters || []);
// Parse all the methods for this path
for (const method in path) {
if (path.hasOwnProperty(method)) {
if (Object.prototype.hasOwnProperty.call(path, method)) {
switch (method) {
case 'get':
case 'put':
@ -25,7 +25,7 @@ export const getServices = (openApi: OpenApi): Service[] => {
case 'delete':
case 'options':
case 'head':
case 'patch':
case 'patch': {
// Each method contains an OpenAPI operation, we parse the operation
const op = path[method]!;
const tags = op.tags?.length ? op.tags.filter(unique) : ['Default'];
@ -46,6 +46,7 @@ export const getServices = (openApi: OpenApi): Service[] => {
services.set(operation.service, service);
});
break;
}
}
}
}

View File

@ -15,7 +15,7 @@ const inverseDictionary = (map: Dictionary<string>): Dictionary<string> => {
export const findOneOfParentDiscriminator = (openApi: OpenApi, parent?: Model): OpenApiDiscriminator | undefined => {
if (openApi.components && parent) {
for (const definitionName in openApi.components.schemas) {
if (openApi.components.schemas.hasOwnProperty(definitionName)) {
if (Object.prototype.hasOwnProperty.call(openApi.components.schemas, definitionName)) {
const schema = openApi.components.schemas[definitionName];
if (
schema.discriminator &&

View File

@ -10,7 +10,6 @@ describe('getPattern', () => {
expect(getPattern('\\')).toEqual('\\\\');
expect(getPattern('\\/')).toEqual('\\\\/');
expect(getPattern('\\/\\/')).toEqual('\\\\/\\\\/');
// eslint-disable-next-line prettier/prettier
expect(getPattern("'")).toEqual("\\'");
});
});

View File

@ -9,6 +9,5 @@
* @param pattern
*/
export const getPattern = (pattern?: string): string | undefined => {
// eslint-disable-next-line prettier/prettier
return pattern?.replace(/\\/g, '\\\\').replace(/'/g, "\\'");
};

View File

@ -13,7 +13,7 @@ export const readSpecFromDisk = async (input: string): Promise<string> => {
try {
const content = await readFile(filePath, 'utf8');
return content.toString();
} catch (e) {
} catch {
throw new Error(`Could not read OpenApi spec: "${filePath}"`);
}
}

View File

@ -57,7 +57,7 @@ describe('v3.axios', () => {
'valuePath',
{
prop: 'valueBody',
},
}
);
expect(result).toBeDefined();
});
@ -104,7 +104,7 @@ describe('v3.axios', () => {
status: 500,
message: 'hello world',
},
}),
})
);
});
@ -136,7 +136,7 @@ describe('v3.axios', () => {
status: 409,
message: 'hello world',
},
}),
})
);
});

View File

@ -126,7 +126,7 @@ describe('v3.babel', () => {
status: 500,
message: 'hello world',
},
}),
})
);
});
@ -162,7 +162,7 @@ describe('v3.babel', () => {
status: 409,
message: 'hello world',
},
}),
})
);
});

View File

@ -69,7 +69,7 @@ describe('v3.fetch', () => {
'valuePath',
{
prop: 'valueBody',
},
}
);
});
expect(result).toBeDefined();
@ -122,7 +122,7 @@ describe('v3.fetch', () => {
status: 500,
message: 'hello world',
},
}),
})
);
});
@ -156,7 +156,7 @@ describe('v3.fetch', () => {
status: 409,
message: 'hello world',
},
}),
})
);
});

View File

@ -57,7 +57,7 @@ describe('v3.node', () => {
'valuePath',
{
prop: 'valueBody',
},
}
);
expect(result).toBeDefined();
});
@ -104,7 +104,7 @@ describe('v3.node', () => {
status: 500,
message: 'hello world',
},
}),
})
);
});
@ -136,7 +136,7 @@ describe('v3.node', () => {
status: 409,
message: 'hello world',
},
}),
})
);
});

View File

@ -43,7 +43,7 @@ const generateRealWorldSpecs = async () => {
return {
name: name
.replace(/^[^a-zA-Z]+/g, '')
.replace(/[^\w\-]+/g, '-')
.replace(/[^\w-]+/g, '-')
.trim()
.toLowerCase(),
url: latestVersion.swaggerYamlUrl || latestVersion.swaggerUrl,