swaggerjsontoapidocs 1.5.2 → 1.7.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
@@ -40,6 +40,7 @@ MSYS_NO_PATHCONV=1 npx swaggerjsontoapidocs [options]
40
40
  - `--bp <path>`: Base path to remove from endpoints (e.g., `/api/`).
41
41
  - `-o, --output <path>`: Path to the output folder destination.
42
42
  - `--skip-folder`: Generates flat files instead of nested folders.
43
+ - `--fnl, --function-name-lowercase`: Force all function names to lowercase for consistency.
43
44
 
44
45
  ### Example Usage
45
46
 
@@ -203,17 +204,37 @@ In this example:
203
204
 
204
205
  ```bash
205
206
  ├── api_docs
206
- │ ├── Users
207
- │ └── Users.ts
207
+ │ ├── products
208
+ │ └── products.ts
208
209
  ```
209
210
 
210
211
  ```typescript
211
- // Users.ts
212
- export const Users = () => `Users`;
212
+ // products.ts
213
213
  /**
214
+ * @endpoint /api/products
215
+ * @methods GET - POST
216
+ */
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}`;
225
+ ```
226
+
227
+ ### Result --function-name-lowercase
228
+
229
+ ```typescript
230
+ // products.ts
231
+ /**
232
+ * @endpoint /api/products/{id}/category/{categoryId}
233
+ * @methods GET - PUT - DELETE
214
234
  * @param id
215
235
  */
216
- export const Users_id = (id: any) => `Users/${id}`;
236
+ export const products_id_category_categoryid = (id: any) =>
237
+ `products/${id}/category/${categoryId}`;
217
238
  ```
218
239
 
219
240
  ### Advanced Usage
@@ -232,8 +253,8 @@ In this example:
232
253
  ```bash
233
254
  docs
234
255
  └── api_docs
235
- ├── Users.ts
236
- └── WeatherForecast.ts
256
+ ├── products.ts
257
+ └── weatherforecast.ts
237
258
  ```
238
259
 
239
260
  ## License
package/bin/index.js CHANGED
@@ -4,7 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  return (mod && mod.__esModule) ? mod : { "default": mod };
5
5
  };
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
- const fs_1 = require("fs");
7
+ const node_fs_1 = require("node:fs");
8
8
  const chalk_1 = __importDefault(require("chalk"));
9
9
  const node_path_1 = __importDefault(require("node:path"));
10
10
  const yargs_1 = __importDefault(require("yargs"));
@@ -33,6 +33,12 @@ const argv = (0, yargs_1.default)((0, helpers_1.hideBin)(process.argv))
33
33
  describe: "Flat files",
34
34
  default: false,
35
35
  },
36
+ "function-name-lowercase": {
37
+ alias: "fnl",
38
+ type: "boolean",
39
+ describe: "Force all function names to lowercase for consistency",
40
+ default: false,
41
+ },
36
42
  })
37
43
  .version()
38
44
  .help()
@@ -45,6 +51,7 @@ async function main() {
45
51
  const basePath = argv.bp;
46
52
  const skipFolder = argv.skipFolder;
47
53
  const output = argv.output;
54
+ const functionNameLowercase = argv.functionNameLowercase;
48
55
  console.log(chalk_1.default.blue(`Swagger Path: ${swaggerPath}`));
49
56
  console.log(chalk_1.default.blue(`Basepath: ${basePath}`));
50
57
  if (skipFolder) {
@@ -53,13 +60,16 @@ async function main() {
53
60
  if (output) {
54
61
  console.log(chalk_1.default.blue(`output folder: ${output}api_docs`));
55
62
  }
56
- (0, fs_1.writeFile)(node_path_1.default.join(__dirname, "config.json"), `{"BASEPATH": "${basePath.trim()}","PATH": "${swaggerPath.trim()}"}`, "utf8", (err) => {
63
+ if (functionNameLowercase) {
64
+ console.log(chalk_1.default.blue(`functionNameLowercase: ${functionNameLowercase}`));
65
+ }
66
+ (0, node_fs_1.writeFile)(node_path_1.default.join(__dirname, "config.json"), `{"BASEPATH": "${basePath.trim()}","PATH": "${swaggerPath.trim()}"}`, "utf8", (err) => {
57
67
  if (err) {
58
68
  console.error(chalk_1.default.red("Error writing the configuration file:"), err);
59
69
  }
60
70
  else {
61
71
  console.log(chalk_1.default.green("Configuration file created successfully."));
62
- const params = { skipFolder, output };
72
+ const params = { skipFolder, output, functionNameLowercase };
63
73
  (0, jsonToApiDocs_1.initScript)(params);
64
74
  }
65
75
  });
@@ -4,18 +4,20 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.initScript = initScript;
7
- const promises_1 = require("fs/promises");
7
+ const promises_1 = require("node:fs/promises");
8
8
  const fs_extra_1 = require("fs-extra");
9
- const path_1 = require("path");
9
+ const node_path_1 = require("node:path");
10
10
  const chalk_1 = __importDefault(require("chalk"));
11
11
  const prettier_1 = require("prettier");
12
- const os_1 = __importDefault(require("os"));
13
- const child_process_1 = require("child_process");
14
12
  const folderName = "api_docs";
15
- const mainFolderOutPut = (0, path_1.join)(__dirname, folderName);
13
+ const mainFolderOutPut = (0, node_path_1.join)(__dirname, folderName);
16
14
  let urlSwaggerJson = "";
17
15
  let basepath = "";
18
- let paramsConfig = { skipFolder: false, output: undefined };
16
+ let paramsConfig = {
17
+ skipFolder: false,
18
+ output: undefined,
19
+ functionNameLowercase: false,
20
+ };
19
21
  async function cleanFolderOutPut() {
20
22
  await (0, promises_1.rm)(mainFolderOutPut, {
21
23
  recursive: true,
@@ -25,7 +27,7 @@ async function cleanFolderOutPut() {
25
27
  async function initScript(params) {
26
28
  paramsConfig = params;
27
29
  await cleanFolderOutPut();
28
- const raw = await (0, promises_1.readFile)((0, path_1.join)(__dirname, "config.json"), "utf8");
30
+ const raw = await (0, promises_1.readFile)((0, node_path_1.join)(__dirname, "config.json"), "utf8");
29
31
  const config = await JSON.parse(raw);
30
32
  urlSwaggerJson = config.PATH;
31
33
  basepath = config.BASEPATH;
@@ -33,7 +35,7 @@ async function initScript(params) {
33
35
  const response = await fetch(urlSwaggerJson);
34
36
  const data = await response.json();
35
37
  try {
36
- await (0, promises_1.writeFile)((0, path_1.join)(__dirname, "paths.json"), `${JSON.stringify(data, null, 2)}`, "utf8");
38
+ await (0, promises_1.writeFile)((0, node_path_1.join)(__dirname, "paths.json"), `${JSON.stringify(data, null, 2)}`, "utf8");
37
39
  await filterPathsObject();
38
40
  }
39
41
  catch (err) {
@@ -53,17 +55,23 @@ async function initScript(params) {
53
55
  }
54
56
  }
55
57
  async function filterPathsObject() {
56
- const raw = await (0, promises_1.readFile)((0, path_1.join)(__dirname, "paths.json"), "utf8");
58
+ const raw = await (0, promises_1.readFile)((0, node_path_1.join)(__dirname, "paths.json"), "utf8");
57
59
  const pathsObj = await JSON.parse(raw);
58
- const endpoints = Object.keys(pathsObj.paths).map((endpoint) => endpoint.split(basepath)[1]);
59
- const foldersName = endpoints.map((endpoint) => endpoint.split("/")[0]);
60
+ const regexStartWithSlash = /^\//;
61
+ const apiEndpoints = Object.entries(pathsObj.paths).map((path) => ({
62
+ endpoint: path[0].replace(basepath, "").replace(regexStartWithSlash, ""),
63
+ methods: Object.keys(path[1]),
64
+ apiEndpoint: path[0],
65
+ }));
66
+ const endpoints = apiEndpoints.map(({ endpoint }) => endpoint);
67
+ const foldersName = endpoints.map((endpoint) => endpoint.split("/")[0].toLocaleLowerCase());
60
68
  await makeFolders(foldersName);
61
- await makeFileContainer(endpoints, foldersName);
69
+ await makeFileContainer(apiEndpoints, foldersName);
62
70
  if (paramsConfig.output) {
63
71
  await moveFolderToChoosePath();
64
72
  }
65
73
  else {
66
- await openFileManager(mainFolderOutPut);
74
+ await destinationPath(mainFolderOutPut);
67
75
  }
68
76
  await cleanFileAndConfig();
69
77
  }
@@ -73,50 +81,65 @@ async function cleanFileAndConfig() {
73
81
  console.log("🧹 Cleaned.");
74
82
  }
75
83
  async function cleanFile() {
76
- await (0, promises_1.rm)((0, path_1.join)(__dirname, "paths.json"), { force: true });
84
+ await (0, promises_1.rm)((0, node_path_1.join)(__dirname, "paths.json"), { force: true });
77
85
  }
78
86
  async function cleanConfig() {
79
- await (0, promises_1.rm)((0, path_1.join)(__dirname, "config.json"), { force: true });
87
+ await (0, promises_1.rm)((0, node_path_1.join)(__dirname, "config.json"), { force: true });
80
88
  }
81
89
  async function makeFolders(foldersName) {
82
90
  await (0, promises_1.mkdir)(mainFolderOutPut, { recursive: true });
83
91
  if (!paramsConfig.skipFolder) {
84
- for (const folder of [...new Set(foldersName)]) {
85
- const folderPath = (0, path_1.join)(mainFolderOutPut, folder);
92
+ for (const folder of new Set(foldersName)) {
93
+ const folderPath = (0, node_path_1.join)(mainFolderOutPut, folder);
86
94
  await (0, promises_1.mkdir)(folderPath, { recursive: true });
87
95
  }
88
96
  }
89
97
  }
90
- async function makeFileContainer(endpoints, foldersName) {
91
- for (const folder of [...new Set(foldersName)]) {
92
- if (paramsConfig.skipFolder) {
93
- await (0, promises_1.appendFile)(`${mainFolderOutPut}/${folder}.ts`, "");
94
- }
95
- else {
96
- await (0, promises_1.appendFile)(`${mainFolderOutPut}/${folder}/${folder}.ts`, "");
97
- }
98
+ const getFilePath = (folder) => {
99
+ return paramsConfig.skipFolder
100
+ ? `${mainFolderOutPut}/${folder}.ts`
101
+ : `${mainFolderOutPut}/${folder}/${folder}.ts`;
102
+ };
103
+ function normalizeEndpoint(endpoint, toLowercase) {
104
+ let name = endpoint
105
+ .replace(/[/|{}]/g, "_")
106
+ .replace(/_+/g, "_")
107
+ .replace(/(^_)|(_$)/g, "");
108
+ return toLowercase ? name.toLowerCase() : name;
109
+ }
110
+ const formatEndpointNames = (endpoint) => {
111
+ const name = normalizeEndpoint(endpoint, paramsConfig.functionNameLowercase);
112
+ const templatePath = endpoint.replace(/\{/g, "${");
113
+ return { name, templatePath };
114
+ };
115
+ const generateDocumentation = (endpoint, methods, apiEndpoint) => {
116
+ const paramsMatch = endpoint.match(/\{([^{}]+)\}/g) || [];
117
+ const args = paramsMatch
118
+ .map((p) => `${p.replace(/[{}]/g, "")}:any`)
119
+ .join(", ");
120
+ const paramsDoc = paramsMatch
121
+ .map((p) => `* @param ${p.replace(/[{}]/g, "")}`)
122
+ .join("\n");
123
+ const endpointLine = apiEndpoint ? `\n* @endpoint ${apiEndpoint}\n` : "";
124
+ const methodsLine = methods
125
+ ? `* @methods ${methods.join(" - ").toUpperCase()}\n`
126
+ : "";
127
+ const paramsLine = paramsDoc ? `${paramsDoc}\n` : "";
128
+ const jsDoc = `/**${endpointLine}${methodsLine}${paramsLine}*/\n`;
129
+ return {
130
+ args,
131
+ jsDoc,
132
+ };
133
+ };
134
+ async function makeFileContainer(apiEndpoints, foldersName) {
135
+ for (const folder of new Set(foldersName)) {
136
+ await (0, promises_1.appendFile)(getFilePath(folder), "");
98
137
  }
99
138
  for (const [index, folder] of foldersName.entries()) {
100
- const endpoint = endpoints[index];
101
- const filePath = paramsConfig.skipFolder
102
- ? `${mainFolderOutPut}/${folder}.ts`
103
- : `${mainFolderOutPut}/${folder}/${folder}.ts`;
104
- const paramsMatch = endpoint.match(/\{([^}]+)\}/g);
105
- const args = paramsMatch
106
- ? paramsMatch.map((p) => p.replace(/[{}]/g, "").concat(":any")).join(", ")
107
- : "";
108
- let jsDoc = "";
109
- if (paramsMatch?.length) {
110
- const paramsDoc = paramsMatch
111
- .map((p) => ` * @param ${p.replace(/[{}]/g, "")}`)
112
- .join("\n");
113
- jsDoc = `/**\n${paramsDoc}\n */\n`;
114
- }
115
- const name = endpoint
116
- .replace(/[/|{}]/g, "_")
117
- .replace(/_+/g, "_")
118
- .replace(/^_|_$/g, "");
119
- const templatePath = endpoint.replace(/\{/g, "${");
139
+ const { endpoint, methods, apiEndpoint } = apiEndpoints[index];
140
+ const filePath = getFilePath(folder);
141
+ const { name, templatePath } = formatEndpointNames(endpoint);
142
+ const { args, jsDoc } = generateDocumentation(endpoint, methods, apiEndpoint);
120
143
  const line = `${jsDoc} export const ${name} = (${args}) => \`${templatePath}\`;\n`;
121
144
  try {
122
145
  await (0, promises_1.appendFile)(filePath, line);
@@ -128,31 +151,14 @@ async function makeFileContainer(endpoints, foldersName) {
128
151
  }
129
152
  }
130
153
  }
131
- async function openFileManager(fullPath) {
132
- const platform = os_1.default.platform();
133
- let command = "";
134
- switch (platform) {
135
- case "win32":
136
- command = `explorer`;
137
- break;
138
- case "darwin":
139
- command = `open`;
140
- break;
141
- case "linux":
142
- command = `xdg-open`;
143
- break;
144
- default:
145
- console.error(`Platform ${platform} is not supported.`);
146
- return;
147
- }
148
- (0, child_process_1.exec)(`${command} "${fullPath}"`);
154
+ async function destinationPath(fullPath) {
149
155
  console.log("💾 show result --->", fullPath);
150
156
  }
151
157
  async function moveFolderToChoosePath() {
152
158
  await (0, fs_extra_1.move)(mainFolderOutPut, `${paramsConfig.output}${folderName}`, {
153
159
  overwrite: true,
154
160
  });
155
- await openFileManager((0, path_1.resolve)(`${paramsConfig.output}${folderName}`));
161
+ await destinationPath((0, node_path_1.resolve)(`${paramsConfig.output}${folderName}`));
156
162
  }
157
163
  async function formatWithPrettier(filePath) {
158
164
  const content = await (0, promises_1.readFile)(filePath, "utf8");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "swaggerjsontoapidocs",
3
- "version": "1.5.2",
3
+ "version": "1.7.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",