diff --git a/README.md b/README.md index b851329a8..3ea47d5a7 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,10 @@ > Node.js library that generates Typescript clients based on the OpenAPI specification. +## Differences from the [original library](https://github.com/ferdikoomen/openapi-typescript-codegen) +- Service name excluded from operationId (format `ServiceName_OperationName`) + - operation with tag `Simple` and operationId `Simple_GetList` with generate `getList()` method in service `SimpleService` + ## Why? - Frontend ❤️ OpenAPI, but we do not want to use JAVA codegen in our builds - Quick, lightweight, robust and framework-agnostic 🚀 @@ -94,13 +98,13 @@ Support - [Angular support](docs/angular-support.md) - [Node-Fetch support](docs/node-fetch-support.md) -[npm-url]: https://npmjs.org/package/openapi-typescript-codegen -[npm-image]: https://img.shields.io/npm/v/openapi-typescript-codegen.svg +[npm-url]: https://npmjs.org/package/@neisvestney/openapi-typescript-codegen +[npm-image]: https://img.shields.io/npm/v/@neisvestney/openapi-typescript-codegen.svg [license-url]: LICENSE -[license-image]: http://img.shields.io/npm/l/openapi-typescript-codegen.svg -[coverage-url]: https://codecov.io/gh/ferdikoomen/openapi-typescript-codegen -[coverage-image]: https://img.shields.io/codecov/c/github/ferdikoomen/openapi-typescript-codegen.svg -[downloads-url]: http://npm-stat.com/charts.html?package=openapi-typescript-codegen -[downloads-image]: http://img.shields.io/npm/dm/openapi-typescript-codegen.svg -[build-url]: https://circleci.com/gh/ferdikoomen/openapi-typescript-codegen/tree/master -[build-image]: https://circleci.com/gh/ferdikoomen/openapi-typescript-codegen/tree/master.svg?style=svg +[license-image]: http://img.shields.io/npm/l/@neisvestney/openapi-typescript-codegen.svg +[coverage-url]: https://codecov.io/gh/neisvestney/openapi-typescript-codegen +[coverage-image]: https://img.shields.io/codecov/c/github/neisvestney/openapi-typescript-codegen.svg +[downloads-url]: http://npm-stat.com/charts.html?package=@neisvestney/openapi-typescript-codegen +[downloads-image]: http://img.shields.io/npm/dm/@neisvestney/openapi-typescript-codegen.svg +[build-url]: https://circleci.com/gh/neisvestney/openapi-typescript-codegen/tree/master +[build-image]: https://circleci.com/gh/neisvestney/openapi-typescript-codegen/tree/master.svg?style=svg diff --git a/package-lock.json b/package-lock.json index 050f5e79a..a1786c744 100644 --- a/package-lock.json +++ b/package-lock.json @@ -63,7 +63,7 @@ "jest-cli": "29.7.0", "node-fetch": "2.7.0", "prettier": "3.1.1", - "puppeteer": "21.6.1", + "puppeteer": "21.6.0", "qs": "6.11.2", "rimraf": "5.0.5", "rollup": "4.7.0", @@ -6430,9 +6430,9 @@ } }, "node_modules/basic-ftp": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.4.tgz", - "integrity": "sha512-8PzkB0arJFV4jJWSGOYR+OEic6aeKMu/osRhBULN6RY0ykby6LKhbmuQ5ublvaas5BOwboah5D87nrHyuh8PPA==", + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.3.tgz", + "integrity": "sha512-QHX8HLlncOLpy54mh+k/sWIFd0ThmRqwe9ZjELybGZK+tZ8rUb9VO0saKJUROTbE+KhzDUT7xziGpGrW8Kmd+g==", "dev": true, "engines": { "node": ">=10.0.0" @@ -15341,15 +15341,15 @@ } }, "node_modules/puppeteer": { - "version": "21.6.1", - "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-21.6.1.tgz", - "integrity": "sha512-O+pbc61oj8ln6m8EJKncrsQFmytgRyFYERtk190PeLbJn5JKpmmynn2p1PiFrlhCitAQXLJ0MOy7F0TeyCRqBg==", + "version": "21.6.0", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-21.6.0.tgz", + "integrity": "sha512-u6JhSF7xaPYZ2gd3tvhYI8MwVAjLc3Cazj7UWvMV95A07/y7cIjBwYUiMU9/jm4z0FSUORriLX/RZRaiASNWPw==", "dev": true, "hasInstallScript": true, "dependencies": { "@puppeteer/browsers": "1.9.0", "cosmiconfig": "8.3.6", - "puppeteer-core": "21.6.1" + "puppeteer-core": "21.6.0" }, "bin": { "puppeteer": "lib/esm/puppeteer/node/cli.js" @@ -15359,9 +15359,9 @@ } }, "node_modules/puppeteer-core": { - "version": "21.6.1", - "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-21.6.1.tgz", - "integrity": "sha512-0chaaK/RL9S1U3bsyR4fUeUfoj51vNnjWvXgG6DcsyMjwYNpLcAThv187i1rZCo7QhJP0wZN8plQkjNyrq2h+A==", + "version": "21.6.0", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-21.6.0.tgz", + "integrity": "sha512-1vrzbp2E1JpBwtIIrriWkN+A0afUxkqRuFTC3uASc5ql6iuK9ppOdIU/CPGKwOyB4YFIQ16mRbK0PK19mbXnaQ==", "dev": true, "dependencies": { "@puppeteer/browsers": "1.9.0", @@ -15369,7 +15369,7 @@ "cross-fetch": "4.0.0", "debug": "4.3.4", "devtools-protocol": "0.0.1203626", - "ws": "8.15.1" + "ws": "8.14.2" }, "engines": { "node": ">=16.13.2" @@ -16774,9 +16774,9 @@ "dev": true }, "node_modules/streamx": { - "version": "2.15.6", - "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.15.6.tgz", - "integrity": "sha512-q+vQL4AAz+FdfT137VF69Cc/APqUbxy+MDOImRrMvchJpigHj9GksgDU2LYbO9rx7RX6osWgxJB2WxhYv4SZAw==", + "version": "2.15.5", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.15.5.tgz", + "integrity": "sha512-9thPGMkKC2GctCzyCUjME3yR03x2xNo0GPKGkRw2UMYN+gqWa9uqpyNWhmsNCutU5zHmkUum0LsCRQTXUgUCAg==", "dev": true, "dependencies": { "fast-fifo": "^1.1.0", @@ -18784,9 +18784,9 @@ "dev": true }, "node_modules/ws": { - "version": "8.15.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.15.1.tgz", - "integrity": "sha512-W5OZiCjXEmk0yZ66ZN82beM5Sz7l7coYxpRkzS+p9PP+ToQry8szKh+61eNktr7EA9DOwvFGhfC605jDHbP6QQ==", + "version": "8.14.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.14.2.tgz", + "integrity": "sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==", "dev": true, "engines": { "node": ">=10.0.0" diff --git a/package.json b/package.json index b27985db5..3bd39c619 100644 --- a/package.json +++ b/package.json @@ -1,15 +1,15 @@ { - "name": "openapi-typescript-codegen", - "version": "0.26.0", + "name": "@neisvestney/openapi-typescript-codegen", + "version": "0.27.3", "description": "Library that generates Typescript clients based on the OpenAPI specification.", "author": "Ferdi Koomen", - "homepage": "https://github.com/ferdikoomen/openapi-typescript-codegen", + "homepage": "https://github.com/neisvestney/openapi-typescript-codegen", "repository": { "type": "git", - "url": "git+https://github.com/ferdikoomen/openapi-typescript-codegen.git" + "url": "git+https://github.com/neisvestney/openapi-typescript-codegen.git" }, "bugs": { - "url": "https://github.com/ferdikoomen/openapi-typescript-codegen/issues" + "url": "https://github.com/neisvestney/openapi-typescript-codegen/issues" }, "license": "MIT", "keywords": [ @@ -26,6 +26,10 @@ "node" ], "maintainers": [ + { + "name": "Neisvestney", + "url": "https://github.com/Neisvestney" + }, { "name": "Ferdi Koomen", "email": "info@madebyferdi.com" @@ -111,7 +115,7 @@ "jest-cli": "29.7.0", "node-fetch": "2.7.0", "prettier": "3.1.1", - "puppeteer": "21.6.1", + "puppeteer": "21.6.0", "qs": "6.11.2", "rimraf": "5.0.5", "rollup": "4.7.0", diff --git a/rollup.config.mjs b/rollup.config.mjs index b25ca8442..39523b644 100644 --- a/rollup.config.mjs +++ b/rollup.config.mjs @@ -8,6 +8,8 @@ import { dirname, extname, resolve } from 'path'; const { precompile } = handlebars; +const isDev = process.env.NODE_ENV === 'development' + /** * Custom plugin to parse handlebar imports and precompile * the template on the fly. This reduces runtime by about @@ -56,9 +58,10 @@ const getPlugins = () => { handlebarsPlugin(), typescript({ module: 'esnext', + sourceMap: isDev, }), ]; - if (process.env.NODE_ENV === 'development') { + if (isDev) { return plugins; } return [...plugins, terser()]; @@ -70,6 +73,7 @@ export default { exports: 'named', file: './dist/index.js', format: 'cjs', + sourcemap: isDev, }, external: ['camelcase', 'commander', 'fs-extra', 'handlebars', '@apidevtools/json-schema-ref-parser'], plugins: getPlugins(), diff --git a/src/openApi/v3/parser/getOperation.ts b/src/openApi/v3/parser/getOperation.ts index aee4bd0c2..2217c2682 100644 --- a/src/openApi/v3/parser/getOperation.ts +++ b/src/openApi/v3/parser/getOperation.ts @@ -23,7 +23,7 @@ export const getOperation = ( pathParams: OperationParameters ): Operation => { const serviceName = getServiceName(tag); - const operationName = getOperationName(url, method, op.operationId); + const operationName = getOperationName(url, method, op.operationId, tag); // Create a new operation object for this method. const operation: Operation = { diff --git a/src/openApi/v3/parser/getOperationName.ts b/src/openApi/v3/parser/getOperationName.ts index 124bf66bd..4c8809693 100644 --- a/src/openApi/v3/parser/getOperationName.ts +++ b/src/openApi/v3/parser/getOperationName.ts @@ -5,14 +5,21 @@ import camelCase from 'camelcase'; * This will use the operation ID - if available - and otherwise fallback * on a generated name from the URL */ -export const getOperationName = (url: string, method: string, operationId?: string): string => { +export const getOperationName = (url: string, method: string, operationId?: string, tag?: string): string => { if (operationId) { - return camelCase( - operationId - .replace(/^[^a-zA-Z]+/g, '') - .replace(/[^\w\-]+/g, '-') - .trim() - ); + let transformedOperationId = operationId + + if (tag) { + transformedOperationId = transformedOperationId + .replace(new RegExp(`^${tag}_`), "") + } + + transformedOperationId = transformedOperationId + .replace(/^[^a-zA-Z]+/g, '') + .replace(/[^\w\-]+/g, '-') + .trim() + + return camelCase(transformedOperationId); } const urlWithoutPlaceholders = url diff --git a/src/utils/formatCode.ts b/src/utils/formatCode.ts index 9d0e8e69b..b33e3c3c5 100644 --- a/src/utils/formatCode.ts +++ b/src/utils/formatCode.ts @@ -2,7 +2,7 @@ import { EOL } from 'os'; export const formatCode = (s: string): string => { let indent: number = 0; - let lines = s.split(/[\r\n]+/); + let lines = s.replace(/[\r\n]+$/, '').split(/[\r\n]/); lines = lines.map(line => { line = line.trim().replace(/^\*/g, ' *'); let i = indent; diff --git a/src/utils/registerHandlebarHelpers.ts b/src/utils/registerHandlebarHelpers.ts index 88f47c19b..697c059a2 100644 --- a/src/utils/registerHandlebarHelpers.ts +++ b/src/utils/registerHandlebarHelpers.ts @@ -94,7 +94,7 @@ export const registerHandlebarHelpers = (root: { return value .replace(/\*\//g, '*') .replace(/\/\*/g, '*') - .replace(/\r?\n(.*)/g, (_, w) => `${EOL} * ${w.trim()}`); + .replace(/\r?\n(.*)/g, (_, w) => `\n * ${w.trim()}`); }); Handlebars.registerHelper('escapeDescription', function (value: string): string { diff --git a/test/index.js b/test/index.js index 6d276c412..cad89cb63 100644 --- a/test/index.js +++ b/test/index.js @@ -57,8 +57,8 @@ const generateRealWorldSpecs = async () => { }; const main = async () => { - await generate('./test/spec/v2.json', './test/generated/v2/'); - await generate('./test/spec/v3.json', './test/generated/v3/'); + await generate(`${__dirname}/spec/v2.json`, `${__dirname}/generated/v2/`); + await generate(`${__dirname}/spec/v3.json`, `${__dirname}/generated/v3/`); // await generateRealWorldSpecs(); }; diff --git a/test/spec/v3.json b/test/spec/v3.json index cb590d0b7..95b311892 100644 --- a/test/spec/v3.json +++ b/test/spec/v3.json @@ -21,7 +21,7 @@ "tags": [ "Simple" ], - "operationId": "GetCallWithoutParametersAndResponse" + "operationId": "Simple_GetCallWithoutParametersAndResponse" }, "put": { "tags": [