swaggerjsontoapidocs 1.8.0 โ†’ 1.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -36,162 +36,168 @@ MSYS_NO_PATHCONV=1 npx swaggerjsontoapidocs [options]
36
36
 
37
37
  ### Available Arguments
38
38
 
39
- - `-s, --swagger <url>`: Specifies the URL of the Swagger JSON file.
40
- - `--bp <path>`: Base path to remove from endpoints (e.g., `/api/`).
41
- - `-o, --output <path>`: Path to the output folder destination.
42
- - `--skip-folder`: Generates flat files instead of nested folders.
43
- - `--fnl, --function-name-lowercase`: Force all function names to lowercase for consistency.
39
+ - `-s, --swagger <url>` : URL of the Swagger/OpenAPI JSON (required).
40
+ - `--bp <path>` : Base path to remove from endpoints (e.g. `/api/`) (required).
41
+ - `-o, --output <path>` : Destination folder for generated files (optional).
42
+ - `--skip-folder` : Generate flat files (no nested folders).
43
+ - `--fnl` : Force function names to lowercase.
44
+ - `-e, --ext <.ts|.js>` : Output file extension for generated files. Allowed values: `.ts` (default) or `.js`.
44
45
 
45
46
  ### Example Usage
46
47
 
47
48
  ```bash
48
- npx swaggerjsontoapidocs -s http://localhost:5033/swagger/v1/swagger.json --bp /api/
49
+ npx swaggerjsontoapidocs -s http://localhost:5033/swagger/v1/swagger.json --bp /api/v1/
49
50
  ```
50
51
 
51
52
  In this example:
52
53
 
53
54
  - `-s` points to the URL of the Swagger JSON file.
54
- - `--bp` defines the base path `/api/` to be removed from the endpoints.
55
+ - `--bp` defines the base path `/api/v1/` to be removed from the endpoints.
55
56
 
56
57
  <details>
57
58
  <summary>Swagger.json (Click to expand)</summary>
58
59
 
59
60
  ```json
60
61
  {
61
- "openapi": "3.0.1",
62
+ "swagger": "2.0",
62
63
  "info": {
63
- "title": "fakeApi",
64
- "version": "1.0"
64
+ "version": "1.2.0",
65
+ "title": "Extended Sample API with Multiple Path Parameters",
66
+ "description": "Test Swagger specification including endpoints with multiple path parameters."
65
67
  },
66
68
  "paths": {
67
- "/api/Users": {
69
+ "/api/v1/users/{userId}/orders/{orderId}": {
68
70
  "get": {
69
- "tags": ["Users"],
70
- "responses": {
71
- "200": {
72
- "description": "OK",
73
- "content": {
74
- "text/plain": {
75
- "schema": {
76
- "type": "array",
77
- "items": {
78
- "$ref": "#/components/schemas/Usuario"
79
- }
80
- }
81
- },
82
- "application/json": {
83
- "schema": {
84
- "type": "array",
85
- "items": {
86
- "$ref": "#/components/schemas/Usuario"
87
- }
88
- }
89
- },
90
- "text/json": {
91
- "schema": {
92
- "type": "array",
93
- "items": {
94
- "$ref": "#/components/schemas/Usuario"
95
- }
96
- }
97
- }
98
- }
71
+ "tags": ["Order Processing"],
72
+ "summary": "Get a specific order for a user",
73
+ "parameters": [
74
+ {
75
+ "name": "userId",
76
+ "in": "path",
77
+ "required": true,
78
+ "type": "string"
79
+ },
80
+ {
81
+ "name": "orderId",
82
+ "in": "path",
83
+ "required": true,
84
+ "type": "string"
99
85
  }
86
+ ],
87
+ "responses": {
88
+ "200": { "description": "Order details" },
89
+ "404": { "description": "Order not found" }
100
90
  }
91
+ },
92
+ "put": {
93
+ "tags": ["Order Processing"],
94
+ "summary": "Update a specific order for a user",
95
+ "parameters": [
96
+ {
97
+ "name": "userId",
98
+ "in": "path",
99
+ "required": true,
100
+ "type": "string"
101
+ },
102
+ {
103
+ "name": "orderId",
104
+ "in": "path",
105
+ "required": true,
106
+ "type": "string"
107
+ },
108
+ {
109
+ "name": "body",
110
+ "in": "body",
111
+ "required": true,
112
+ "schema": { "$ref": "#/definitions/Order" }
113
+ }
114
+ ],
115
+ "responses": { "200": { "description": "Order updated" } }
101
116
  }
102
117
  },
103
- "/api/Users/{id}": {
104
- "get": {
105
- "tags": ["Users"],
118
+ "/api/v1/Products/{productId}/Reviews/{reviewId}/Comments/{commentId}": {
119
+ "delete": {
120
+ "tags": ["Reviews"],
121
+ "summary": "Delete a specific comment on a review",
106
122
  "parameters": [
107
123
  {
108
- "name": "id",
124
+ "name": "productId",
109
125
  "in": "path",
110
126
  "required": true,
111
- "schema": {
112
- "type": "string"
113
- }
127
+ "type": "string"
128
+ },
129
+ {
130
+ "name": "reviewId",
131
+ "in": "path",
132
+ "required": true,
133
+ "type": "string"
134
+ },
135
+ {
136
+ "name": "commentId",
137
+ "in": "path",
138
+ "required": true,
139
+ "type": "string"
114
140
  }
115
141
  ],
116
142
  "responses": {
117
- "200": {
118
- "description": "OK",
119
- "content": {
120
- "text/plain": {
121
- "schema": {
122
- "$ref": "#/components/schemas/Usuario"
123
- }
124
- },
125
- "application/json": {
126
- "schema": {
127
- "$ref": "#/components/schemas/Usuario"
128
- }
129
- },
130
- "text/json": {
131
- "schema": {
132
- "$ref": "#/components/schemas/Usuario"
133
- }
134
- }
135
- }
136
- }
143
+ "200": { "description": "Comment deleted" },
144
+ "404": { "description": "Comment not found" }
137
145
  }
138
- },
146
+ }
147
+ },
148
+ "/api/v1/admin/{section}/{entityId}/actions/{actionId}": {
139
149
  "post": {
140
- "tags": ["Users"],
150
+ "tags": ["Administration"],
151
+ "summary": "Perform an admin action on an entity",
141
152
  "parameters": [
142
153
  {
143
- "name": "id",
154
+ "name": "section",
155
+ "in": "path",
156
+ "required": true,
157
+ "type": "string"
158
+ },
159
+ {
160
+ "name": "entityId",
144
161
  "in": "path",
145
162
  "required": true,
163
+ "type": "string"
164
+ },
165
+ {
166
+ "name": "actionId",
167
+ "in": "path",
168
+ "required": true,
169
+ "type": "string"
170
+ },
171
+ {
172
+ "name": "body",
173
+ "in": "body",
174
+ "required": false,
146
175
  "schema": {
147
- "type": "string"
176
+ "type": "object",
177
+ "properties": {
178
+ "reason": { "type": "string" },
179
+ "timestamp": { "type": "string", "format": "date-time" }
180
+ }
148
181
  }
149
182
  }
150
183
  ],
151
184
  "responses": {
152
- "200": {
153
- "description": "OK",
154
- "content": {
155
- "text/plain": {
156
- "schema": {
157
- "$ref": "#/components/schemas/Usuario"
158
- }
159
- },
160
- "application/json": {
161
- "schema": {
162
- "$ref": "#/components/schemas/Usuario"
163
- }
164
- },
165
- "text/json": {
166
- "schema": {
167
- "$ref": "#/components/schemas/Usuario"
168
- }
169
- }
170
- }
171
- }
185
+ "200": { "description": "Action executed successfully" },
186
+ "400": { "description": "Invalid action" }
172
187
  }
173
188
  }
174
189
  }
175
190
  },
176
- "components": {
177
- "schemas": {
178
- "Usuario": {
179
- "type": "object",
180
- "properties": {
181
- "id": {
182
- "type": "string",
183
- "nullable": true
184
- },
185
- "nombre": {
186
- "type": "string",
187
- "nullable": true
188
- },
189
- "email": {
190
- "type": "string",
191
- "nullable": true
192
- }
193
- },
194
- "additionalProperties": false
191
+ "definitions": {
192
+ "Order": {
193
+ "type": "object",
194
+ "properties": {
195
+ "id": { "type": "string" },
196
+ "status": { "type": "string" },
197
+ "items": {
198
+ "type": "array",
199
+ "items": { "type": "string" }
200
+ }
195
201
  }
196
202
  }
197
203
  }
@@ -203,44 +209,52 @@ In this example:
203
209
  ### Result
204
210
 
205
211
  ```bash
206
- โ”œโ”€โ”€ api_docs
207
- โ”‚ โ”œโ”€โ”€ products
208
- โ”‚ โ””โ”€โ”€ products.ts
212
+ api_docs/
213
+ โ”œโ”€โ”€ admin
214
+ โ”‚ โ””โ”€โ”€ admin.ts
215
+ โ”œโ”€โ”€ products
216
+ โ”‚ โ””โ”€โ”€ products.ts
217
+ โ””โ”€โ”€ users
218
+ โ””โ”€โ”€ users.ts
209
219
  ```
210
220
 
211
221
  ```typescript
212
222
  // products.ts
213
223
  /**
214
- * @endpoint /api/products
215
- * @methods GET - POST
224
+ * ##### METHODS
225
+ * **DELETE**: Delete a specific comment on a review
226
+ *
227
+ * ---
228
+ * **Endpoint**: `/api/v1/Products/{productId}/Reviews/{reviewId}/Comments/{commentId}`
229
+ *
230
+ * ---
231
+ * ##### PATH PARAMETERS
232
+ * @param productId - any
233
+ * @param reviewId - any
234
+ * @param commentId - any
216
235
  */
217
- export const products = () => `products`;
218
- /**
219
- * @endpoint /api/products/{id}/category/{categoryId}
220
- * @methods GET - PUT - DELETE
221
- * @param id
222
- */
223
- export const products_id_category_categoryId = (id: any) =>
224
- `products/${id}/category/${categoryId}`;
236
+ export const Products_productId_Reviews_reviewId_Comments_commentId = (
237
+ productId: any,
238
+ reviewId: any,
239
+ commentId: any,
240
+ ) => `Products/${productId}/Reviews/${reviewId}/Comments/${commentId}`;
225
241
  ```
226
242
 
227
243
  ### Result --function-name-lowercase
228
244
 
229
245
  ```typescript
230
246
  // products.ts
231
- /**
232
- * @endpoint /api/products/{id}/category/{categoryId}
233
- * @methods GET - PUT - DELETE
234
- * @param id
235
- */
236
- export const products_id_category_categoryid = (id: any) =>
237
- `products/${id}/category/${categoryId}`;
247
+ export const products_productId_reviews_reviewId_comments_commentId = (
248
+ productId: any,
249
+ reviewId: any,
250
+ commentId: any,
251
+ ) => `Products/${productId}/Reviews/${reviewId}/Comments/${commentId}`;
238
252
  ```
239
253
 
240
254
  ### Advanced Usage
241
255
 
242
256
  ```bash
243
- npx swaggerjsontoapidocs -s http://localhost:5033/swagger/v1/swagger.json --bp /api/ -o ./docs/ --skip-folder
257
+ npx swaggerjsontoapidocs -s http://localhost:5033/swagger/v1/swagger.json --bp /api/v1/ -o ./docs/ --skip-folder
244
258
  ```
245
259
 
246
260
  In this example:
@@ -251,10 +265,11 @@ In this example:
251
265
  ### Result --skip-folder
252
266
 
253
267
  ```bash
254
- docs
268
+ docs/
255
269
  โ””โ”€โ”€ api_docs
270
+ โ”œโ”€โ”€ admin.ts
256
271
  โ”œโ”€โ”€ products.ts
257
- โ””โ”€โ”€ weatherforecast.ts
272
+ โ””โ”€โ”€ users.ts
258
273
  ```
259
274
 
260
275
  ## License
package/bin/index.js CHANGED
@@ -39,19 +39,27 @@ const argv = (0, yargs_1.default)((0, helpers_1.hideBin)(process.argv))
39
39
  describe: 'Force all function names to lowercase for consistency',
40
40
  default: false,
41
41
  },
42
+ ext: {
43
+ alias: 'e',
44
+ type: 'string',
45
+ choices: ['.ts', '.js'],
46
+ describe: 'Choose generated file extension: .ts or .js',
47
+ default: '.ts',
48
+ },
42
49
  })
43
50
  .version()
44
51
  .help()
45
52
  .alias('help', 'h')
46
53
  .strict()
47
54
  .parseSync();
48
- async function main() {
55
+ function main() {
49
56
  console.log(chalk_1.default.green('CONFIGURING THE SCRIPT WITH THE PROVIDED ARGUMENTS...'));
50
57
  const swaggerPath = argv.swagger;
51
58
  const basePath = argv.bp;
52
59
  const skipFolder = argv.skipFolder;
53
60
  const output = argv.output;
54
61
  const functionNameLowercase = argv.functionNameLowercase;
62
+ const ext = argv.ext;
55
63
  console.log(chalk_1.default.blue(`Swagger Path: ${swaggerPath}`));
56
64
  console.log(chalk_1.default.blue(`Basepath: ${basePath}`));
57
65
  if (skipFolder) {
@@ -63,13 +71,21 @@ async function main() {
63
71
  if (functionNameLowercase) {
64
72
  console.log(chalk_1.default.blue(`functionNameLowercase: ${functionNameLowercase}`));
65
73
  }
74
+ if (ext) {
75
+ console.log(chalk_1.default.blue(`file extension: ${ext}`));
76
+ }
66
77
  (0, node_fs_1.writeFile)(node_path_1.default.join(__dirname, 'config.json'), `{"BASEPATH": "${basePath.trim()}","PATH": "${swaggerPath.trim()}"}`, 'utf8', (err) => {
67
78
  if (err) {
68
79
  console.error(chalk_1.default.red('Error writing the configuration file:'), err);
69
80
  }
70
81
  else {
71
82
  console.log(chalk_1.default.green('Configuration file created successfully.'));
72
- const params = { skipFolder, output, functionNameLowercase };
83
+ const params = {
84
+ skipFolder,
85
+ output,
86
+ functionNameLowercase,
87
+ ext,
88
+ };
73
89
  (0, jsonToApiDocs_1.initScript)(params);
74
90
  }
75
91
  });
@@ -17,6 +17,7 @@ let paramsConfig = {
17
17
  skipFolder: false,
18
18
  output: undefined,
19
19
  functionNameLowercase: false,
20
+ ext: '.ts',
20
21
  };
21
22
  async function cleanFolderOutPut() {
22
23
  await (0, promises_1.rm)(mainFolderOutPut, {
@@ -48,7 +49,7 @@ async function initScript(params) {
48
49
  chalk_1.default.red('Could not connect: The server is off or the URL is incorrect.'));
49
50
  }
50
51
  else {
51
- console.log(chalk_1.default.red(`โœ˜ unknown error: ${error}`));
52
+ console.log(chalk_1.default.red(`unknown error: ${error}`));
52
53
  }
53
54
  await cleanFileAndConfig();
54
55
  return null;
@@ -81,7 +82,7 @@ async function filterPathsObject() {
81
82
  async function cleanFileAndConfig() {
82
83
  await cleanFile();
83
84
  await cleanConfig();
84
- console.log('๐Ÿงน Cleaned.');
85
+ console.log('Cleaned.');
85
86
  }
86
87
  async function cleanFile() {
87
88
  await (0, promises_1.rm)((0, node_path_1.join)(__dirname, 'paths.json'), { force: true });
@@ -99,9 +100,10 @@ async function makeFolders(foldersName) {
99
100
  }
100
101
  }
101
102
  const getFilePath = (folder) => {
103
+ const ext = paramsConfig.ext ?? '.ts';
102
104
  return paramsConfig.skipFolder
103
- ? `${mainFolderOutPut}/${folder}.ts`
104
- : `${mainFolderOutPut}/${folder}/${folder}.ts`;
105
+ ? `${mainFolderOutPut}/${folder}${ext}`
106
+ : `${mainFolderOutPut}/${folder}/${folder}${ext}`;
105
107
  };
106
108
  function normalizeEndpoint(endpoint, toLowercase) {
107
109
  const name = endpoint
@@ -126,24 +128,37 @@ const formatEndpointNames = (endpoint) => {
126
128
  const generateDocumentation = (endpoint, methods, apiEndpoint) => {
127
129
  const paramsMatch = endpoint.match(/\{([^{}]+)\}/g) || [];
128
130
  const args = paramsMatch
129
- .map((p) => `${p.replace(/[{}]/g, '')}:any`)
131
+ .map((p) => {
132
+ const name = p.replace(/[{}]/g, '');
133
+ return paramsConfig.ext === '.ts' ? `${name}: any` : name;
134
+ })
130
135
  .join(', ');
131
136
  const paramsDoc = paramsMatch
132
- .map((p) => `* @param ${p.replace(/[{}]/g, '')}`)
137
+ .map((p) => `* @param ${p.replace(/[{}]/g, '')} - any`)
133
138
  .join('\n');
134
- const endpointLine = apiEndpoint ? `\n* @endpoint ${apiEndpoint}\n` : '';
139
+ const endpointLine = apiEndpoint
140
+ ? `*\n* ---\n* **Endpoint**: \`${apiEndpoint}\``
141
+ : '*';
135
142
  const methodsDoc = methods
136
- .map((method) => {
137
- let doc = '* @method ' + method.verb.toUpperCase();
138
- if (method.summary) {
139
- doc += ` - ${method.summary}`;
143
+ .map((method, index) => {
144
+ let doc = '* **' + method.verb.toUpperCase() + '**: ';
145
+ doc += method.summary ? `${method.summary}` : `without summary`;
146
+ if (index + 1 !== methods.length) {
147
+ doc += '\n*';
140
148
  }
141
149
  return doc;
142
150
  })
143
151
  .join('\n');
144
- const methodsLine = methodsDoc ? `${methodsDoc}\n` : '';
145
- const paramsLine = paramsDoc ? `${paramsDoc}\n` : '';
146
- const jsDoc = `/**${endpointLine}${methodsLine}${paramsLine}*/\n`;
152
+ const methodsLine = methodsDoc ? `* ##### METHODS\n${methodsDoc}` : '*';
153
+ const paramsLine = paramsDoc
154
+ ? `*\n* ---\n* ##### PATH PARAMETERS\n${paramsDoc}`
155
+ : '*';
156
+ const jsDoc = `
157
+ /**
158
+ ${methodsLine}
159
+ ${endpointLine}
160
+ ${paramsLine}
161
+ */\n`;
147
162
  return {
148
163
  args,
149
164
  jsDoc,
@@ -162,15 +177,15 @@ async function makeFileContainer(apiEndpoints, foldersName) {
162
177
  try {
163
178
  await (0, promises_1.appendFile)(filePath, line);
164
179
  await formatWithPrettier(filePath);
165
- console.log(`โœ… Generated: ${name}`);
180
+ console.log(`Generated: ${name}`);
166
181
  }
167
182
  catch (error) {
168
- console.error(`โŒ Error occurred while writing to ${filePath}:`, error);
183
+ console.error(`Error occurred while writing to ${filePath}:`, error);
169
184
  }
170
185
  }
171
186
  }
172
187
  async function destinationPath(fullPath) {
173
- console.log('๐Ÿ’พ show result --->', fullPath);
188
+ console.log('show result --->', fullPath);
174
189
  }
175
190
  async function moveFolderToChoosePath() {
176
191
  await (0, fs_extra_1.move)(mainFolderOutPut, `${paramsConfig.output}${folderName}`, {
@@ -180,8 +195,9 @@ async function moveFolderToChoosePath() {
180
195
  }
181
196
  async function formatWithPrettier(filePath) {
182
197
  const content = await (0, promises_1.readFile)(filePath, 'utf8');
198
+ const parser = filePath.endsWith('.ts') ? 'typescript' : 'babel';
183
199
  const formatted = await (0, prettier_1.format)(content, {
184
- parser: 'typescript',
200
+ parser,
185
201
  filepath: filePath,
186
202
  semi: true,
187
203
  singleQuote: true,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "swaggerjsontoapidocs",
3
- "version": "1.8.0",
3
+ "version": "1.10.0",
4
4
  "description": "script to convert swagger json to api docs, this help us to consume functions and center all endpoints in one place",
5
5
  "keywords": [
6
6
  "swagger",
@@ -31,7 +31,18 @@
31
31
  "api": "ts-node ./src/index.ts",
32
32
  "dist": "node ./bin/index.js",
33
33
  "lint": "eslint .",
34
- "prepublishOnly": "npm run build"
34
+ "prepublishOnly": "npm run build",
35
+ "prepare": "simple-git-hooks"
36
+ },
37
+ "simple-git-hooks": {
38
+ "pre-commit": "npx lint-staged",
39
+ "commit-msg": "npx commitlint --edit $1"
40
+ },
41
+ "lint-staged": {
42
+ "*.{js,jsx,ts,tsx}": [
43
+ "prettier --write",
44
+ "eslint --quiet"
45
+ ]
35
46
  },
36
47
  "bin": {
37
48
  "swaggerjsontoapidocs": "bin/index.js"
@@ -43,6 +54,8 @@
43
54
  "yargs": "18.0.0"
44
55
  },
45
56
  "devDependencies": {
57
+ "@commitlint/cli": "^20.4.1",
58
+ "@commitlint/config-conventional": "^20.4.1",
46
59
  "@eslint/js": "9.39.2",
47
60
  "@semantic-release/changelog": "^6.0.3",
48
61
  "@semantic-release/git": "^10.0.1",
@@ -54,7 +67,9 @@
54
67
  "eslint": "9.39.2",
55
68
  "globals": "17.0.0",
56
69
  "jiti": "2.6.1",
70
+ "lint-staged": "^16.2.7",
57
71
  "semantic-release": "^25.0.2",
72
+ "simple-git-hooks": "^2.13.1",
58
73
  "ts-node": "10.9.2",
59
74
  "typescript": "5.9.3",
60
75
  "typescript-eslint": "8.52.0"