openapi-sync 2.1.2 → 2.1.4

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.
@@ -15,7 +15,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
15
15
  const fs_1 = __importDefault(require("fs"));
16
16
  const path_1 = __importDefault(require("path"));
17
17
  const lodash_1 = __importDefault(require("lodash"));
18
- const helpers_1 = require("./components/helpers");
18
+ const helpers_1 = require("../helpers");
19
19
  const lodash_2 = require("lodash");
20
20
  const axios_1 = __importDefault(require("axios"));
21
21
  const axios_retry_1 = __importDefault(require("axios-retry"));
@@ -65,14 +65,15 @@ const OpenapiSync = (apiUrl, apiName, config, refetchInterval) => __awaiter(void
65
65
  : "";
66
66
  const getSharedComponentName = (componentName, componentType) => {
67
67
  var _a, _b;
68
+ const defaultName = (0, helpers_1.capitalize)(componentName);
68
69
  if ((_b = (_a = config === null || config === void 0 ? void 0 : config.types) === null || _a === void 0 ? void 0 : _a.name) === null || _b === void 0 ? void 0 : _b.format) {
69
70
  const formattedName = config === null || config === void 0 ? void 0 : config.types.name.format("shared", {
70
71
  name: componentName,
71
- });
72
+ }, defaultName);
72
73
  if (formattedName)
73
74
  return `${typePrefix}${formattedName}`;
74
75
  }
75
- return `${typePrefix}${(0, helpers_1.capitalize)(componentName)}`;
76
+ return `${typePrefix}${defaultName}`;
76
77
  };
77
78
  const parseSchemaToType = (apiDoc, schema, name, isRequired, options, indentLevel = 0) => {
78
79
  let overrideName = "";
@@ -552,7 +553,7 @@ const OpenapiSync = (apiUrl, apiName, config, refetchInterval) => __awaiter(void
552
553
  method,
553
554
  path: endpointPath,
554
555
  summary: eSpec === null || eSpec === void 0 ? void 0 : eSpec.summary,
555
- });
556
+ }, name);
556
557
  if (formattedName)
557
558
  name = formattedName;
558
559
  }
@@ -573,7 +574,7 @@ const OpenapiSync = (apiUrl, apiName, config, refetchInterval) => __awaiter(void
573
574
  method,
574
575
  path: endpointPath,
575
576
  summary: eSpec === null || eSpec === void 0 ? void 0 : eSpec.summary,
576
- });
577
+ }, name);
577
578
  if (formattedName)
578
579
  name = formattedName;
579
580
  }
@@ -599,7 +600,7 @@ const OpenapiSync = (apiUrl, apiName, config, refetchInterval) => __awaiter(void
599
600
  method,
600
601
  path: endpointPath,
601
602
  summary: eSpec === null || eSpec === void 0 ? void 0 : eSpec.summary,
602
- });
603
+ }, name);
603
604
  if (formattedName)
604
605
  name = formattedName;
605
606
  }
@@ -731,7 +732,7 @@ ${(0, curl_generator_1.CurlGenerator)({
731
732
  path: endpointPath,
732
733
  summary: eSpec === null || eSpec === void 0 ? void 0 : eSpec.summary,
733
734
  operationId: eSpec === null || eSpec === void 0 ? void 0 : eSpec.operationId,
734
- });
735
+ }, name);
735
736
  if (formattedName)
736
737
  name = formattedName;
737
738
  }
@@ -0,0 +1,145 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.renderTypeRefMD = exports.JSONStringify = exports.getEndpointDetails = exports.capitalize = exports.yamlStringToJson = exports.isYamlString = exports.isJson = void 0;
27
+ exports.getNestedValue = getNestedValue;
28
+ const regex_1 = require("./regex");
29
+ const yaml = __importStar(require("js-yaml"));
30
+ const isJson = (value) => {
31
+ return ["object"].includes(typeof value) && !(value instanceof Blob);
32
+ };
33
+ exports.isJson = isJson;
34
+ const isYamlString = (fileContent) => {
35
+ try {
36
+ yaml.load(fileContent);
37
+ return true;
38
+ }
39
+ catch (en) {
40
+ const e = en;
41
+ if (e instanceof yaml.YAMLException) {
42
+ return false;
43
+ }
44
+ else {
45
+ throw e;
46
+ }
47
+ }
48
+ };
49
+ exports.isYamlString = isYamlString;
50
+ const yamlStringToJson = (fileContent) => {
51
+ if ((0, exports.isYamlString)(fileContent)) {
52
+ const content = yaml.load(fileContent);
53
+ const jsonString = JSON.stringify(content, null, 2);
54
+ const json = JSON.parse(jsonString);
55
+ return json;
56
+ }
57
+ };
58
+ exports.yamlStringToJson = yamlStringToJson;
59
+ const capitalize = (text) => {
60
+ const capitalizedWord = text.substring(0, 1).toUpperCase() + text.substring(1);
61
+ return capitalizedWord;
62
+ };
63
+ exports.capitalize = capitalize;
64
+ const getEndpointDetails = (path, method) => {
65
+ const pathParts = path.split("/");
66
+ let name = `${(0, exports.capitalize)(method)}`;
67
+ const variables = [];
68
+ pathParts.forEach((part) => {
69
+ // check if part is a variable
70
+ //api/{userId}
71
+ if (part[0] === "{" && part[part.length - 1] === "}") {
72
+ const s = part.replace(/{/, "").replace(/}/, "");
73
+ variables.push(s);
74
+ part = `$${s}`;
75
+ }
76
+ //api/<userId>
77
+ else if (part[0] === "<" && part[part.length - 1] === ">") {
78
+ const s = part.replace(/</, "").replace(/>/, "");
79
+ variables.push(s);
80
+ part = `$${s}`;
81
+ }
82
+ //api/:userId
83
+ else if (part[0] === ":") {
84
+ const s = part.replace(/:/, "");
85
+ variables.push(s);
86
+ part = `$${s}`;
87
+ }
88
+ // parse to variable name
89
+ let partVal = "";
90
+ part.split("").forEach((char) => {
91
+ let c = char;
92
+ if (!regex_1.variableNameChar.test(char))
93
+ c = "/";
94
+ partVal += c;
95
+ });
96
+ partVal.split("/").forEach((val) => {
97
+ name += (0, exports.capitalize)(val);
98
+ });
99
+ });
100
+ return { name, variables, pathParts };
101
+ };
102
+ exports.getEndpointDetails = getEndpointDetails;
103
+ const JSONStringify = (obj, indent = 1) => {
104
+ let result = "{";
105
+ const keys = Object.keys(obj);
106
+ for (let i = 0; i < keys.length; i++) {
107
+ const key = keys[i];
108
+ const value = obj[key];
109
+ result += "\n" + " ".repeat(indent) + key + ": ";
110
+ if (typeof value === "object" && value !== null) {
111
+ result += "" + (0, exports.JSONStringify)(value, indent + 1);
112
+ }
113
+ else {
114
+ result += value
115
+ .split("\n")
116
+ .filter((line) => line.trim() !== "")
117
+ .join(`\n${" ".repeat(indent)}`);
118
+ }
119
+ if (i < keys.length - 1) {
120
+ result += ", ";
121
+ }
122
+ }
123
+ result += `\n${" ".repeat(indent - 1)}}`;
124
+ return result;
125
+ };
126
+ exports.JSONStringify = JSONStringify;
127
+ const renderTypeRefMD = (typeRef, indent = 1) => {
128
+ return `\n\`\`\`typescript\n${" ".repeat(indent)} ${typeRef
129
+ .split("\n")
130
+ .filter((line) => line.trim() !== "")
131
+ .join(`\n${" ".repeat(indent)} `)}\n\`\`\``;
132
+ };
133
+ exports.renderTypeRefMD = renderTypeRefMD;
134
+ function getNestedValue(obj, path) {
135
+ // Split the path string into an array of keys
136
+ const keys = path.split(".");
137
+ // Use the reduce method to navigate the object
138
+ return keys.reduce((currentObj, key) => {
139
+ // If the current object is not null or undefined,
140
+ // return the value of the next key. Otherwise, return undefined.
141
+ return currentObj && currentObj[key] !== undefined
142
+ ? currentObj[key]
143
+ : undefined;
144
+ }, obj);
145
+ }
package/dist/index.js CHANGED
@@ -16,25 +16,41 @@ exports.Init = void 0;
16
16
  const Openapi_sync_1 = __importDefault(require("./Openapi-sync"));
17
17
  const dotenv_1 = __importDefault(require("dotenv"));
18
18
  const path_1 = __importDefault(require("path"));
19
+ const fs_1 = __importDefault(require("fs"));
19
20
  const state_1 = require("./Openapi-sync/state");
20
21
  dotenv_1.default.config();
21
22
  const rootUsingCwd = process.cwd();
22
23
  const Init = (options) => __awaiter(void 0, void 0, void 0, function* () {
23
24
  // Load config file
24
- let configJS, configJson;
25
+ let configJS;
26
+ // Register TypeScript loader before requiring the file
25
27
  try {
26
- configJS = require(path_1.default.join(rootUsingCwd, "openapi.sync.js"));
28
+ require("esbuild-register");
27
29
  }
28
- catch (e) {
29
- // console.log(e);
30
+ catch (registerError) {
31
+ throw registerError;
30
32
  }
33
+ const jsConfigPath = path_1.default.join(rootUsingCwd, "openapi.sync.");
34
+ const tsConfigPath = path_1.default.join(rootUsingCwd, "openapi.sync.ts");
35
+ const jsonConfigPath = path_1.default.join(rootUsingCwd, "openapi.sync.json");
36
+ const configPaths = [jsConfigPath, tsConfigPath, jsonConfigPath];
31
37
  try {
32
- configJson = require(path_1.default.join(rootUsingCwd, "openapi.sync.json"));
38
+ for (const configPath of configPaths) {
39
+ if (fs_1.default.existsSync(configPath)) {
40
+ configJS = require(configPath);
41
+ if (Object.keys(configJS).length === 1 && configJS.default) {
42
+ configJS = configJS.default;
43
+ }
44
+ }
45
+ }
33
46
  }
34
47
  catch (e) {
35
- // console.log(e);
48
+ console.log(e);
49
+ }
50
+ const config = configJS;
51
+ if (!config) {
52
+ throw new Error("No config found");
36
53
  }
37
- const config = configJS || configJson;
38
54
  const apiNames = Object.keys(config.api);
39
55
  const refetchInterval = options &&
40
56
  "refetchInterval" in options &&
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ // TypeScript config file for openapi-sync
3
+ // To use this file, install a TypeScript loader:
4
+ // npm install --save-dev esbuild-register (recommended - fastest & lightest)
5
+ // or: npm install --save-dev tsx
6
+ // or: npm install --save-dev @swc/register
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ const config = {
9
+ refetchInterval: 5000,
10
+ folder: "/inputed/path/",
11
+ api: {
12
+ example1: "https://raw.githubusercontent.com/OAI/OpenAPI-Specification/main/examples/v3.0/petstore.json",
13
+ example2: "https://raw.githubusercontent.com/OAI/OpenAPI-Specification/main/examples/v3.0/petstore.yaml",
14
+ },
15
+ server: 0,
16
+ types: {
17
+ name: {
18
+ prefix: "",
19
+ format: (source, data) => {
20
+ if (source === "shared") {
21
+ return `${data.name}`;
22
+ }
23
+ else if (source === "endpoint") {
24
+ return `${data.method.toLowerCase()}${data
25
+ .path.replace(/\//g, "_")
26
+ .replace(/{|}/g, "")}${data.code}${data.type}`;
27
+ }
28
+ },
29
+ },
30
+ doc: {
31
+ disable: true,
32
+ },
33
+ },
34
+ endpoints: {
35
+ value: {
36
+ replaceWords: [
37
+ {
38
+ replace: "/api/v\\d/",
39
+ with: "",
40
+ },
41
+ ],
42
+ includeServer: true,
43
+ type: "object",
44
+ },
45
+ name: {
46
+ prefix: "",
47
+ useOperationId: true,
48
+ format: ({ method, path, summary, operationId }) => {
49
+ if (path === "/")
50
+ return "root";
51
+ return path.replace(/\//g, "_").replace(/{|}/g, "");
52
+ },
53
+ },
54
+ doc: {
55
+ disable: false,
56
+ showCurl: true,
57
+ },
58
+ },
59
+ };
60
+ module.exports = config;
package/dist/regex.js ADDED
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.variableNameChar = exports.variableName = void 0;
4
+ exports.variableName = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
5
+ exports.variableNameChar = /[A-Za-z0-9_$]/;
package/helpers.ts ADDED
@@ -0,0 +1,128 @@
1
+ import { variableNameChar } from "./regex";
2
+ import * as yaml from "js-yaml";
3
+
4
+ export const isJson = (value: any) => {
5
+ return ["object"].includes(typeof value) && !(value instanceof Blob);
6
+ };
7
+
8
+ export const isYamlString = (fileContent: string) => {
9
+ try {
10
+ yaml.load(fileContent);
11
+ return true;
12
+ } catch (en) {
13
+ const e = en as any;
14
+ if (e instanceof yaml.YAMLException) {
15
+ return false;
16
+ } else {
17
+ throw e;
18
+ }
19
+ }
20
+ };
21
+
22
+ export const yamlStringToJson = (fileContent: string) => {
23
+ if (isYamlString(fileContent)) {
24
+ const content = yaml.load(fileContent);
25
+
26
+ const jsonString = JSON.stringify(content, null, 2);
27
+ const json = JSON.parse(jsonString);
28
+ return json;
29
+ }
30
+ };
31
+
32
+ export const capitalize = (text: string) => {
33
+ const capitalizedWord =
34
+ text.substring(0, 1).toUpperCase() + text.substring(1);
35
+ return capitalizedWord;
36
+ };
37
+
38
+ export const getEndpointDetails = (path: string, method: string) => {
39
+ const pathParts = path.split("/");
40
+ let name = `${capitalize(method)}`;
41
+ const variables: string[] = [];
42
+ pathParts.forEach((part) => {
43
+ // check if part is a variable
44
+ //api/{userId}
45
+ if (part[0] === "{" && part[part.length - 1] === "}") {
46
+ const s = part.replace(/{/, "").replace(/}/, "");
47
+ variables.push(s);
48
+ part = `$${s}`;
49
+ }
50
+
51
+ //api/<userId>
52
+ else if (part[0] === "<" && part[part.length - 1] === ">") {
53
+ const s = part.replace(/</, "").replace(/>/, "");
54
+ variables.push(s);
55
+ part = `$${s}`;
56
+ }
57
+
58
+ //api/:userId
59
+ else if (part[0] === ":") {
60
+ const s = part.replace(/:/, "");
61
+ variables.push(s);
62
+ part = `$${s}`;
63
+ }
64
+
65
+ // parse to variable name
66
+ let partVal = "";
67
+ part.split("").forEach((char) => {
68
+ let c = char;
69
+ if (!variableNameChar.test(char)) c = "/";
70
+ partVal += c;
71
+ });
72
+
73
+ partVal.split("/").forEach((val) => {
74
+ name += capitalize(val);
75
+ });
76
+ });
77
+
78
+ return { name, variables, pathParts };
79
+ };
80
+
81
+ export const JSONStringify = (obj: Record<string, any>, indent = 1) => {
82
+ let result = "{";
83
+ const keys = Object.keys(obj);
84
+
85
+ for (let i = 0; i < keys.length; i++) {
86
+ const key = keys[i];
87
+ const value = obj[key];
88
+
89
+ result += "\n" + " ".repeat(indent) + key + ": ";
90
+
91
+ if (typeof value === "object" && value !== null) {
92
+ result += "" + JSONStringify(value, indent + 1);
93
+ } else {
94
+ result += value
95
+ .split("\n")
96
+ .filter((line: string) => line.trim() !== "")
97
+ .join(`\n${" ".repeat(indent)}`);
98
+ }
99
+
100
+ if (i < keys.length - 1) {
101
+ result += ", ";
102
+ }
103
+ }
104
+
105
+ result += `\n${" ".repeat(indent - 1)}}`;
106
+ return result;
107
+ };
108
+
109
+ export const renderTypeRefMD = (typeRef: string, indent = 1) => {
110
+ return `\n\`\`\`typescript\n${" ".repeat(indent)} ${typeRef
111
+ .split("\n")
112
+ .filter((line) => line.trim() !== "")
113
+ .join(`\n${" ".repeat(indent)} `)}\n\`\`\``;
114
+ };
115
+
116
+ export function getNestedValue<T>(obj: object, path: string): T | undefined {
117
+ // Split the path string into an array of keys
118
+ const keys = path.split(".");
119
+
120
+ // Use the reduce method to navigate the object
121
+ return keys.reduce((currentObj: any, key: string) => {
122
+ // If the current object is not null or undefined,
123
+ // return the value of the next key. Otherwise, return undefined.
124
+ return currentObj && currentObj[key] !== undefined
125
+ ? currentObj[key]
126
+ : undefined;
127
+ }, obj) as T | undefined;
128
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openapi-sync",
3
- "version": "2.1.2",
3
+ "version": "2.1.4",
4
4
  "description": "A developer-friendly tool designed to keep your API up-to-date by leveraging OpenAPI schemas. It automates the generation of endpoint URIs and type definitions, including shared types, directly from your OpenAPI specification.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -25,6 +25,8 @@
25
25
  "dist",
26
26
  "db.json",
27
27
  "types.ts",
28
+ "helpers.ts",
29
+ "regex.ts",
28
30
  "LICENSE",
29
31
  "README.md",
30
32
  "package.json"
@@ -47,6 +49,7 @@
47
49
  "@redocly/openapi-core": "^1.19.0",
48
50
  "axios": "^1.7.3",
49
51
  "axios-retry": "^4.5.0",
52
+ "esbuild-register": "^3.6.0",
50
53
  "curl-generator": "^0.4.2",
51
54
  "dotenv": "^16.4.5",
52
55
  "js-yaml": "^4.1.0",
package/regex.ts ADDED
@@ -0,0 +1,2 @@
1
+ export const variableName = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
2
+ export const variableNameChar = /[A-Za-z0-9_$]/;
package/types.ts CHANGED
@@ -89,7 +89,8 @@ export type IConfig = {
89
89
  method?: Method;
90
90
  path?: string;
91
91
  summary?: string;
92
- }
92
+ },
93
+ defaultName: string
93
94
  ) => string | null | undefined;
94
95
  };
95
96
  doc?: IConfigDoc;
@@ -101,12 +102,15 @@ export type IConfig = {
101
102
  type?: "string" | "object";
102
103
  };
103
104
  name?: {
104
- format?: (data: {
105
- method: Method;
106
- path: string;
107
- summary: string;
108
- operationId: string;
109
- }) => string | null;
105
+ format?: (
106
+ data: {
107
+ method: Method;
108
+ path: string;
109
+ summary: string;
110
+ operationId: string;
111
+ },
112
+ defaultName: string
113
+ ) => string | null;
110
114
  prefix?: string;
111
115
  useOperationId?: boolean;
112
116
  };