openapi-sync 1.0.25 → 2.0.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/dist/Openapi-sync/components/helpers.js +17 -124
- package/dist/Openapi-sync/index.js +256 -27
- package/dist/index.js +15 -2
- package/package.json +3 -2
- package/types.ts +93 -0
- /package/dist/{Openapi-sync/types.js → types.js} +0 -0
|
@@ -22,14 +22,10 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
22
22
|
__setModuleDefault(result, mod);
|
|
23
23
|
return result;
|
|
24
24
|
};
|
|
25
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
-
};
|
|
28
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
-
exports.
|
|
26
|
+
exports.JSONStringify = exports.getEndpointDetails = exports.capitalize = exports.yamlStringToJson = exports.isYamlString = exports.isJson = void 0;
|
|
30
27
|
const regex_1 = require("./regex");
|
|
31
28
|
const yaml = __importStar(require("js-yaml"));
|
|
32
|
-
const lodash_1 = __importDefault(require("lodash"));
|
|
33
29
|
const isJson = (value) => {
|
|
34
30
|
return ["object"].includes(typeof value) && !(value instanceof Blob);
|
|
35
31
|
};
|
|
@@ -64,8 +60,6 @@ const capitalize = (text) => {
|
|
|
64
60
|
return capitalizedWord;
|
|
65
61
|
};
|
|
66
62
|
exports.capitalize = capitalize;
|
|
67
|
-
const getSharedComponentName = (componentName, componentType) => `IApi${(0, exports.capitalize)(componentName)}`;
|
|
68
|
-
exports.getSharedComponentName = getSharedComponentName;
|
|
69
63
|
const getEndpointDetails = (path, method) => {
|
|
70
64
|
const pathParts = path.split("/");
|
|
71
65
|
let name = `${(0, exports.capitalize)(method)}`;
|
|
@@ -105,125 +99,24 @@ const getEndpointDetails = (path, method) => {
|
|
|
105
99
|
return { name, variables, pathParts };
|
|
106
100
|
};
|
|
107
101
|
exports.getEndpointDetails = getEndpointDetails;
|
|
108
|
-
const
|
|
109
|
-
let
|
|
110
|
-
|
|
111
|
-
let
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
pathToComponentParts.shift();
|
|
118
|
-
const pathToComponent = pathToComponentParts.join(".");
|
|
119
|
-
const component = lodash_1.default.get(apiDoc, pathToComponent, null);
|
|
120
|
-
// console.log("Type schema 3", pathToComponentParts);
|
|
121
|
-
if (component) {
|
|
122
|
-
if (component === null || component === void 0 ? void 0 : component.name) {
|
|
123
|
-
overrideName = component.name;
|
|
124
|
-
}
|
|
125
|
-
componentName = pathToComponentParts[pathToComponentParts.length - 1];
|
|
126
|
-
// Reference component via import instead of parsing
|
|
127
|
-
type += `${(options === null || options === void 0 ? void 0 : options.noSharedImport) ? "" : "Shared."}${(0, exports.getSharedComponentName)(componentName)}`;
|
|
128
|
-
// type += `${parseSchemaToType(apiDoc, component, "", isRequired)}`;
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
else {
|
|
132
|
-
type += "";
|
|
133
|
-
//TODO $ref is a uri - use axios to fetch doc
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
else if (schema.anyOf) {
|
|
137
|
-
type += `(${schema.anyOf
|
|
138
|
-
.map((v) => (0, exports.parseSchemaToType)(apiDoc, v, "", isRequired, options))
|
|
139
|
-
.join("|")})`;
|
|
140
|
-
}
|
|
141
|
-
else if (schema.oneOf) {
|
|
142
|
-
type += `(${schema.oneOf
|
|
143
|
-
.map((v) => (0, exports.parseSchemaToType)(apiDoc, v, "", isRequired, options))
|
|
144
|
-
.join("|")})`;
|
|
145
|
-
}
|
|
146
|
-
else if (schema.allOf) {
|
|
147
|
-
type += `(${schema.allOf
|
|
148
|
-
.map((v) => (0, exports.parseSchemaToType)(apiDoc, v, "", isRequired, options))
|
|
149
|
-
.join("&")})`;
|
|
150
|
-
}
|
|
151
|
-
else if (schema.items) {
|
|
152
|
-
type += `${(0, exports.parseSchemaToType)(apiDoc, schema.items, "", false, options)}[]`;
|
|
102
|
+
const JSONStringify = (obj) => {
|
|
103
|
+
let result = "{";
|
|
104
|
+
const keys = Object.keys(obj);
|
|
105
|
+
for (let i = 0; i < keys.length; i++) {
|
|
106
|
+
const key = keys[i];
|
|
107
|
+
const value = obj[key];
|
|
108
|
+
result += key + ": ";
|
|
109
|
+
if (typeof value === "object" && value !== null) {
|
|
110
|
+
result += (0, exports.JSONStringify)(value);
|
|
153
111
|
}
|
|
154
|
-
else
|
|
155
|
-
|
|
156
|
-
const objKeys = Object.keys(schema.properties);
|
|
157
|
-
const requiredKeys = schema.required || [];
|
|
158
|
-
let typeCnt = "";
|
|
159
|
-
objKeys.forEach((key) => {
|
|
160
|
-
var _a;
|
|
161
|
-
typeCnt += `${(0, exports.parseSchemaToType)(apiDoc, (_a = schema.properties) === null || _a === void 0 ? void 0 : _a[key], key, requiredKeys.includes(key), options)}`;
|
|
162
|
-
});
|
|
163
|
-
if (typeCnt.length > 0) {
|
|
164
|
-
type += `{\n${typeCnt}}`;
|
|
165
|
-
}
|
|
166
|
-
else {
|
|
167
|
-
type += "{[k: string]: any}";
|
|
168
|
-
}
|
|
112
|
+
else {
|
|
113
|
+
result += value;
|
|
169
114
|
}
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
if (schema.enum.length > 1)
|
|
173
|
-
type += "(";
|
|
174
|
-
type += schema.enum
|
|
175
|
-
.map((v) => `"${v}"`)
|
|
176
|
-
.join("|")
|
|
177
|
-
.toString();
|
|
178
|
-
if (schema.enum.length > 1)
|
|
179
|
-
type += ")";
|
|
180
|
-
}
|
|
181
|
-
else if (["string", "integer", "number", "array", "boolean"].includes(schema.type)) {
|
|
182
|
-
if (["integer", "number"].includes(schema.type)) {
|
|
183
|
-
type += `number`;
|
|
184
|
-
}
|
|
185
|
-
else if (schema.type === "array") {
|
|
186
|
-
//Since we would have already parsed the arrays keys above "schema.items" if it exists
|
|
187
|
-
type += "any[]";
|
|
188
|
-
/* if (schema.items) {
|
|
189
|
-
type += `${parseSchemaToType(
|
|
190
|
-
apiDoc,
|
|
191
|
-
schema.items,
|
|
192
|
-
"",
|
|
193
|
-
false,
|
|
194
|
-
options
|
|
195
|
-
)}[]`;
|
|
196
|
-
} else {
|
|
197
|
-
type += "any[]";
|
|
198
|
-
} */
|
|
199
|
-
}
|
|
200
|
-
else {
|
|
201
|
-
type += schema.type;
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
else if (schema.type === "object") {
|
|
205
|
-
//Since we would have already parsed the object keys above "schema.properties" if it exists
|
|
206
|
-
if (schema.additionalProperties) {
|
|
207
|
-
type += `{[k: string]: ${(0, exports.parseSchemaToType)(apiDoc, schema.additionalProperties, "", true, options) || "any"}}`;
|
|
208
|
-
}
|
|
209
|
-
else {
|
|
210
|
-
type += "{[k: string]: any}";
|
|
211
|
-
}
|
|
212
|
-
}
|
|
115
|
+
if (i < keys.length - 1) {
|
|
116
|
+
result += ", ";
|
|
213
117
|
}
|
|
214
118
|
}
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
type = "string";
|
|
218
|
-
}
|
|
219
|
-
let _name = overrideName || name;
|
|
220
|
-
if ((options === null || options === void 0 ? void 0 : options.useComponentName) && !_name) {
|
|
221
|
-
_name = componentName;
|
|
222
|
-
}
|
|
223
|
-
let typeName = _name ? `\t"${_name}"${isRequired ? "" : "?"}: ` : "";
|
|
224
|
-
const nullable = (schema === null || schema === void 0 ? void 0 : schema.nullable) ? " | null" : "";
|
|
225
|
-
return type.length > 0
|
|
226
|
-
? `${typeName}${type}${nullable}${_name ? ";\n" : ""}`
|
|
227
|
-
: "";
|
|
119
|
+
result += "}";
|
|
120
|
+
return result;
|
|
228
121
|
};
|
|
229
|
-
exports.
|
|
122
|
+
exports.JSONStringify = JSONStringify;
|
|
@@ -14,8 +14,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
15
|
const fs_1 = __importDefault(require("fs"));
|
|
16
16
|
const path_1 = __importDefault(require("path"));
|
|
17
|
+
const lodash_1 = __importDefault(require("lodash"));
|
|
17
18
|
const helpers_1 = require("./components/helpers");
|
|
18
|
-
const
|
|
19
|
+
const lodash_2 = require("lodash");
|
|
19
20
|
const axios_1 = __importDefault(require("axios"));
|
|
20
21
|
const axios_retry_1 = __importDefault(require("axios-retry"));
|
|
21
22
|
const openapi_core_1 = require("@redocly/openapi-core");
|
|
@@ -37,7 +38,8 @@ const apiClient = axios_1.default.create({
|
|
|
37
38
|
return retryCount * 1000; // Exponential back-off: 1s, 2s, 3s, etc.
|
|
38
39
|
},
|
|
39
40
|
});
|
|
40
|
-
const OpenapiSync = (apiUrl, apiName, refetchInterval) => __awaiter(void 0, void 0, void 0, function* () {
|
|
41
|
+
const OpenapiSync = (apiUrl, apiName, config, refetchInterval) => __awaiter(void 0, void 0, void 0, function* () {
|
|
42
|
+
var _a, _b, _c, _d;
|
|
41
43
|
const specResponse = yield apiClient.get(apiUrl);
|
|
42
44
|
const redoclyConfig = yield (0, openapi_core_1.createConfig)({
|
|
43
45
|
extends: ["minimal"],
|
|
@@ -49,10 +51,160 @@ const OpenapiSync = (apiUrl, apiName, refetchInterval) => __awaiter(void 0, void
|
|
|
49
51
|
source,
|
|
50
52
|
config: redoclyConfig,
|
|
51
53
|
});
|
|
52
|
-
// Load config file
|
|
53
|
-
const config = require(path_1.default.join(rootUsingCwd, "openapi.sync.json"));
|
|
54
54
|
const folderPath = path_1.default.join(config.folder || "", apiName);
|
|
55
55
|
const spec = lintResults.bundle.parsed;
|
|
56
|
+
const typePrefix = typeof ((_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.prefix) === "string"
|
|
57
|
+
? config.types.name.prefix
|
|
58
|
+
: "I";
|
|
59
|
+
const endpointPrefix = typeof ((_d = (_c = config === null || config === void 0 ? void 0 : config.endpoints) === null || _c === void 0 ? void 0 : _c.name) === null || _d === void 0 ? void 0 : _d.prefix) === "string"
|
|
60
|
+
? config.endpoints.name.prefix
|
|
61
|
+
: "";
|
|
62
|
+
const getSharedComponentName = (componentName, componentType) => {
|
|
63
|
+
var _a, _b;
|
|
64
|
+
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) {
|
|
65
|
+
const formattedName = config.types.name.format("shared", {
|
|
66
|
+
name: componentName,
|
|
67
|
+
});
|
|
68
|
+
if (formattedName)
|
|
69
|
+
return `${typePrefix}${formattedName}`;
|
|
70
|
+
}
|
|
71
|
+
return `${typePrefix}${(0, helpers_1.capitalize)(componentName)}`;
|
|
72
|
+
};
|
|
73
|
+
const parseSchemaToType = (apiDoc, schema, name, isRequired, options) => {
|
|
74
|
+
let overrideName = "";
|
|
75
|
+
let componentName = "";
|
|
76
|
+
let type = "";
|
|
77
|
+
if (schema) {
|
|
78
|
+
if (schema.$ref) {
|
|
79
|
+
if (schema.$ref[0] === "#") {
|
|
80
|
+
let pathToComponentParts = (schema.$ref || "").split("/");
|
|
81
|
+
pathToComponentParts.shift();
|
|
82
|
+
const partsClone = [...pathToComponentParts];
|
|
83
|
+
partsClone.pop();
|
|
84
|
+
const pathToComponent = pathToComponentParts;
|
|
85
|
+
const component = lodash_1.default.get(apiDoc, pathToComponent, null);
|
|
86
|
+
if (component) {
|
|
87
|
+
if (component === null || component === void 0 ? void 0 : component.name) {
|
|
88
|
+
overrideName = component.name;
|
|
89
|
+
}
|
|
90
|
+
componentName =
|
|
91
|
+
pathToComponentParts[pathToComponentParts.length - 1];
|
|
92
|
+
let name = getSharedComponentName(componentName);
|
|
93
|
+
if (name.includes(".")) {
|
|
94
|
+
const nameParts = name.split(".");
|
|
95
|
+
name = nameParts
|
|
96
|
+
.map((part, i) => {
|
|
97
|
+
if (i === 0) {
|
|
98
|
+
return part;
|
|
99
|
+
}
|
|
100
|
+
return `["${part}"]`;
|
|
101
|
+
})
|
|
102
|
+
.join("");
|
|
103
|
+
}
|
|
104
|
+
// Reference component via import instead of parsing
|
|
105
|
+
type += `${(options === null || options === void 0 ? void 0 : options.noSharedImport) ? "" : "Shared."}${name}`;
|
|
106
|
+
// type += `${parseSchemaToType(apiDoc, component, "", isRequired)}`;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
type += "";
|
|
111
|
+
//TODO $ref is a uri - use axios to fetch doc
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
else if (schema.anyOf) {
|
|
115
|
+
type += `(${schema.anyOf
|
|
116
|
+
.map((v) => parseSchemaToType(apiDoc, v, "", isRequired, options))
|
|
117
|
+
.join("|")})`;
|
|
118
|
+
}
|
|
119
|
+
else if (schema.oneOf) {
|
|
120
|
+
type += `(${schema.oneOf
|
|
121
|
+
.map((v) => parseSchemaToType(apiDoc, v, "", isRequired, options))
|
|
122
|
+
.join("|")})`;
|
|
123
|
+
}
|
|
124
|
+
else if (schema.allOf) {
|
|
125
|
+
type += `(${schema.allOf
|
|
126
|
+
.map((v) => parseSchemaToType(apiDoc, v, "", isRequired, options))
|
|
127
|
+
.join("&")})`;
|
|
128
|
+
}
|
|
129
|
+
else if (schema.items) {
|
|
130
|
+
type += `${parseSchemaToType(apiDoc, schema.items, "", false, options)}[]`;
|
|
131
|
+
}
|
|
132
|
+
else if (schema.properties) {
|
|
133
|
+
//parse object key one at a time
|
|
134
|
+
const objKeys = Object.keys(schema.properties);
|
|
135
|
+
const requiredKeys = schema.required || [];
|
|
136
|
+
let typeCnt = "";
|
|
137
|
+
objKeys.forEach((key) => {
|
|
138
|
+
var _a;
|
|
139
|
+
typeCnt += `${parseSchemaToType(apiDoc, (_a = schema.properties) === null || _a === void 0 ? void 0 : _a[key], key, requiredKeys.includes(key), options)}`;
|
|
140
|
+
});
|
|
141
|
+
if (typeCnt.length > 0) {
|
|
142
|
+
type += `{\n${typeCnt}}`;
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
type += "{[k: string]: any}";
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
else if (schema.enum && schema.enum.length > 0) {
|
|
149
|
+
if (schema.enum.length > 1)
|
|
150
|
+
type += "(";
|
|
151
|
+
schema.enum.forEach((v) => {
|
|
152
|
+
let val = JSON.stringify(v);
|
|
153
|
+
if (val)
|
|
154
|
+
type += `|${val}`;
|
|
155
|
+
});
|
|
156
|
+
if (schema.enum.length > 1)
|
|
157
|
+
type += ")";
|
|
158
|
+
}
|
|
159
|
+
else if (schema.type) {
|
|
160
|
+
if (["string", "integer", "number", "array", "boolean"].includes(schema.type)) {
|
|
161
|
+
if (["integer", "number"].includes(schema.type)) {
|
|
162
|
+
type += `number`;
|
|
163
|
+
}
|
|
164
|
+
else if (schema.type === "array") {
|
|
165
|
+
//Since we would have already parsed the arrays keys above "schema.items" if it exists
|
|
166
|
+
type += "any[]";
|
|
167
|
+
/* if (schema.items) {
|
|
168
|
+
type += `${parseSchemaToType(
|
|
169
|
+
apiDoc,
|
|
170
|
+
schema.items,
|
|
171
|
+
"",
|
|
172
|
+
false,
|
|
173
|
+
options
|
|
174
|
+
)}[]`;
|
|
175
|
+
} else {
|
|
176
|
+
type += "any[]";
|
|
177
|
+
} */
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
type += schema.type;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
else if (schema.type === "object") {
|
|
184
|
+
//Since we would have already parsed the object keys above "schema.properties" if it exists
|
|
185
|
+
if (schema.additionalProperties) {
|
|
186
|
+
type += `{[k: string]: ${parseSchemaToType(apiDoc, schema.additionalProperties, "", true, options) || "any"}}`;
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
type += "{[k: string]: any}";
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
else {
|
|
195
|
+
//Default type to string if no schema provided
|
|
196
|
+
type = "string";
|
|
197
|
+
}
|
|
198
|
+
let _name = overrideName || name;
|
|
199
|
+
if ((options === null || options === void 0 ? void 0 : options.useComponentName) && !_name) {
|
|
200
|
+
_name = componentName;
|
|
201
|
+
}
|
|
202
|
+
let typeName = _name ? `\t"${_name}"${isRequired ? "" : "?"}: ` : "";
|
|
203
|
+
const nullable = (schema === null || schema === void 0 ? void 0 : schema.nullable) ? " | null" : "";
|
|
204
|
+
return type.length > 0
|
|
205
|
+
? `${typeName}${type}${nullable}${_name ? ";\n" : ""}`
|
|
206
|
+
: "";
|
|
207
|
+
};
|
|
56
208
|
// auto update only on dev
|
|
57
209
|
if (refetchInterval && !isNaN(refetchInterval) && refetchInterval > 0) {
|
|
58
210
|
if (!(process.env.NODE_ENV &&
|
|
@@ -61,12 +213,12 @@ const OpenapiSync = (apiUrl, apiName, refetchInterval) => __awaiter(void 0, void
|
|
|
61
213
|
if (fetchTimeout[apiName])
|
|
62
214
|
clearTimeout(fetchTimeout[apiName]);
|
|
63
215
|
// set next request timeout
|
|
64
|
-
fetchTimeout[apiName] = setTimeout(() => OpenapiSync(apiUrl, apiName, refetchInterval), refetchInterval);
|
|
216
|
+
fetchTimeout[apiName] = setTimeout(() => OpenapiSync(apiUrl, apiName, config, refetchInterval), refetchInterval);
|
|
65
217
|
}
|
|
66
218
|
}
|
|
67
219
|
// compare new spec with old spec, continuing only if spec it different
|
|
68
220
|
const prevSpec = (0, state_1.getState)(apiName);
|
|
69
|
-
if ((0,
|
|
221
|
+
if ((0, lodash_2.isEqual)(prevSpec, spec))
|
|
70
222
|
return;
|
|
71
223
|
(0, state_1.setState)(apiName, spec);
|
|
72
224
|
let endpointsFileContent = "";
|
|
@@ -86,10 +238,11 @@ const OpenapiSync = (apiUrl, apiName, refetchInterval) => __awaiter(void 0, void
|
|
|
86
238
|
].includes(key)) {
|
|
87
239
|
// Create components (shared) types
|
|
88
240
|
const components = spec.components[key];
|
|
241
|
+
const componentInterfaces = {};
|
|
89
242
|
const contentKeys = Object.keys(components);
|
|
90
243
|
// only need 1 schema so will us the first schema provided
|
|
91
244
|
contentKeys.forEach((contentKey) => {
|
|
92
|
-
var _a
|
|
245
|
+
var _a;
|
|
93
246
|
/* const schema = (() => {
|
|
94
247
|
switch (key) {
|
|
95
248
|
case "parameters":
|
|
@@ -101,16 +254,43 @@ const OpenapiSync = (apiUrl, apiName, refetchInterval) => __awaiter(void 0, void
|
|
|
101
254
|
const schema = (((_a = components[contentKey]) === null || _a === void 0 ? void 0 : _a.schema)
|
|
102
255
|
? components[contentKey].schema
|
|
103
256
|
: components[contentKey]);
|
|
104
|
-
const typeCnt = `${
|
|
257
|
+
const typeCnt = `${parseSchemaToType(spec, schema, "", true, {
|
|
105
258
|
noSharedImport: true,
|
|
106
259
|
useComponentName: ["parameters"].includes(key),
|
|
107
260
|
})}`;
|
|
108
261
|
if (typeCnt) {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
262
|
+
const parts = contentKey.split(".");
|
|
263
|
+
let currentLevel = componentInterfaces;
|
|
264
|
+
// Navigate or create the nested structure
|
|
265
|
+
for (let i = 0; i < parts.length; i++) {
|
|
266
|
+
const part = parts[i];
|
|
267
|
+
if (i < parts.length - 1) {
|
|
268
|
+
// If it's not the last part, create a nested object if it doesn't exist
|
|
269
|
+
if (!(part in currentLevel)) {
|
|
270
|
+
currentLevel[part] = {}; //<== This rely on js ability to assign value to origianl object by reference, so this assignment will be reflected in componentInterfaces
|
|
271
|
+
}
|
|
272
|
+
currentLevel = currentLevel[part]; //<== This rely on js ability to assign value to origianl object by reference, so this assignment will be reflected in componentInterfaces
|
|
273
|
+
}
|
|
274
|
+
else {
|
|
275
|
+
// This is the last part, assign the original schema value
|
|
276
|
+
currentLevel[part] = typeCnt; //<== This rely on js ability to assign value to origianl object by reference, so this assignment will be reflected in componentInterfaces
|
|
277
|
+
}
|
|
278
|
+
}
|
|
112
279
|
}
|
|
113
280
|
});
|
|
281
|
+
// Generate TypeScript interfaces for each component
|
|
282
|
+
Object.keys(componentInterfaces).forEach((key) => {
|
|
283
|
+
var _a;
|
|
284
|
+
const name = getSharedComponentName(key);
|
|
285
|
+
const cnt = componentInterfaces[key];
|
|
286
|
+
sharedTypesFileContent[key] =
|
|
287
|
+
((_a = sharedTypesFileContent[key]) !== null && _a !== void 0 ? _a : "") +
|
|
288
|
+
"export type " +
|
|
289
|
+
name +
|
|
290
|
+
" = " +
|
|
291
|
+
(typeof cnt === "string" ? cnt : (0, helpers_1.JSONStringify)(cnt)) +
|
|
292
|
+
";\n";
|
|
293
|
+
});
|
|
114
294
|
}
|
|
115
295
|
});
|
|
116
296
|
}
|
|
@@ -120,17 +300,17 @@ const OpenapiSync = (apiUrl, apiName, refetchInterval) => __awaiter(void 0, void
|
|
|
120
300
|
const contentKeys = Object.keys(requestBody.content);
|
|
121
301
|
// only need 1 schema so will us the first schema provided
|
|
122
302
|
if (contentKeys[0] && requestBody.content[contentKeys[0]].schema) {
|
|
123
|
-
typeCnt += `${
|
|
303
|
+
typeCnt += `${parseSchemaToType(spec, requestBody.content[contentKeys[0]].schema, "")}`;
|
|
124
304
|
}
|
|
125
305
|
}
|
|
126
306
|
return typeCnt;
|
|
127
307
|
};
|
|
128
308
|
const treatEndpointUrl = (endpointUrl) => {
|
|
129
|
-
var _a, _b;
|
|
309
|
+
var _a, _b, _c, _d, _e;
|
|
130
310
|
if (((_b = (_a = config === null || config === void 0 ? void 0 : config.endpoints) === null || _a === void 0 ? void 0 : _a.value) === null || _b === void 0 ? void 0 : _b.replaceWords) &&
|
|
131
311
|
Array.isArray(config.endpoints.value.replaceWords)) {
|
|
132
312
|
let newEndpointUrl = endpointUrl;
|
|
133
|
-
config.endpoints.value.replaceWords.forEach((replaceWord, indx) => {
|
|
313
|
+
(_e = (_d = (_c = config === null || config === void 0 ? void 0 : config.endpoints) === null || _c === void 0 ? void 0 : _c.value) === null || _d === void 0 ? void 0 : _d.replaceWords) === null || _e === void 0 ? void 0 : _e.forEach((replaceWord, indx) => {
|
|
134
314
|
const regexp = new RegExp(replaceWord.replace, "g");
|
|
135
315
|
newEndpointUrl = newEndpointUrl.replace(regexp, replaceWord.with || "");
|
|
136
316
|
});
|
|
@@ -142,9 +322,11 @@ const OpenapiSync = (apiUrl, apiName, refetchInterval) => __awaiter(void 0, void
|
|
|
142
322
|
};
|
|
143
323
|
Object.keys(spec.paths || {}).forEach((endpointPath) => {
|
|
144
324
|
const endpointSpec = spec.paths[endpointPath];
|
|
325
|
+
// console.log("Endpoint Path:", { endpointPath, endpointSpec });
|
|
145
326
|
const endpointMethods = Object.keys(endpointSpec);
|
|
146
|
-
endpointMethods.forEach((
|
|
147
|
-
var _a, _b, _c, _d, _e, _f;
|
|
327
|
+
endpointMethods.forEach((_method) => {
|
|
328
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
|
|
329
|
+
const method = _method;
|
|
148
330
|
const endpoint = (0, helpers_1.getEndpointDetails)(endpointPath, method);
|
|
149
331
|
const endpointUrlTxt = endpoint.pathParts
|
|
150
332
|
.map((part) => {
|
|
@@ -173,38 +355,85 @@ const OpenapiSync = (apiUrl, apiName, refetchInterval) => __awaiter(void 0, void
|
|
|
173
355
|
}
|
|
174
356
|
//treat endpoint url
|
|
175
357
|
endpointUrl = treatEndpointUrl(endpointUrl);
|
|
358
|
+
let name = `${endpoint.name}`;
|
|
359
|
+
if ((_b = (_a = config === null || config === void 0 ? void 0 : config.endpoints) === null || _a === void 0 ? void 0 : _a.name) === null || _b === void 0 ? void 0 : _b.format) {
|
|
360
|
+
const formattedName = config.endpoints.name.format({
|
|
361
|
+
method,
|
|
362
|
+
path: endpointPath,
|
|
363
|
+
summary: (_c = endpointSpec[method]) === null || _c === void 0 ? void 0 : _c.summary,
|
|
364
|
+
});
|
|
365
|
+
if (formattedName)
|
|
366
|
+
name = formattedName;
|
|
367
|
+
}
|
|
176
368
|
// Add the endpoint url
|
|
177
|
-
endpointsFileContent += `export const ${
|
|
369
|
+
endpointsFileContent += `export const ${endpointPrefix}${name} = ${endpointUrl};
|
|
178
370
|
`;
|
|
179
|
-
if ((
|
|
371
|
+
if ((_d = endpointSpec[method]) === null || _d === void 0 ? void 0 : _d.parameters) {
|
|
180
372
|
// create query parameters types
|
|
181
|
-
const parameters = (
|
|
373
|
+
const parameters = (_e = endpointSpec[method]) === null || _e === void 0 ? void 0 : _e.parameters;
|
|
182
374
|
let typeCnt = "";
|
|
183
375
|
parameters.forEach((param, i) => {
|
|
184
376
|
if (param.$ref || (param.in === "query" && param.name)) {
|
|
185
|
-
typeCnt += `${
|
|
377
|
+
typeCnt += `${parseSchemaToType(spec, param.$ref ? param : param.schema, param.name || "", param.required)}`;
|
|
186
378
|
}
|
|
187
379
|
});
|
|
188
380
|
if (typeCnt) {
|
|
189
|
-
|
|
381
|
+
let name = `${endpoint.name}Query`;
|
|
382
|
+
if ((_g = (_f = config === null || config === void 0 ? void 0 : config.types) === null || _f === void 0 ? void 0 : _f.name) === null || _g === void 0 ? void 0 : _g.format) {
|
|
383
|
+
const formattedName = config.types.name.format("endpoint", {
|
|
384
|
+
code: "",
|
|
385
|
+
type: "query",
|
|
386
|
+
method,
|
|
387
|
+
path: endpointPath,
|
|
388
|
+
summary: (_h = endpointSpec[method]) === null || _h === void 0 ? void 0 : _h.summary,
|
|
389
|
+
});
|
|
390
|
+
if (formattedName)
|
|
391
|
+
name = formattedName;
|
|
392
|
+
}
|
|
393
|
+
typesFileContent += `export type ${typePrefix}${name} = {\n${typeCnt}};\n`;
|
|
190
394
|
}
|
|
191
395
|
}
|
|
192
|
-
if ((
|
|
396
|
+
if ((_j = endpointSpec[method]) === null || _j === void 0 ? void 0 : _j.requestBody) {
|
|
193
397
|
//create requestBody types
|
|
194
|
-
const requestBody = (
|
|
398
|
+
const requestBody = (_k = endpointSpec[method]) === null || _k === void 0 ? void 0 : _k.requestBody;
|
|
195
399
|
let typeCnt = getBodySchemaType(requestBody);
|
|
196
400
|
if (typeCnt) {
|
|
197
|
-
|
|
401
|
+
let name = `${endpoint.name}DTO`;
|
|
402
|
+
if ((_m = (_l = config === null || config === void 0 ? void 0 : config.types) === null || _l === void 0 ? void 0 : _l.name) === null || _m === void 0 ? void 0 : _m.format) {
|
|
403
|
+
const formattedName = config.types.name.format("endpoint", {
|
|
404
|
+
code: "",
|
|
405
|
+
type: "dto",
|
|
406
|
+
method,
|
|
407
|
+
path: endpointPath,
|
|
408
|
+
summary: (_o = endpointSpec[method]) === null || _o === void 0 ? void 0 : _o.summary,
|
|
409
|
+
});
|
|
410
|
+
if (formattedName)
|
|
411
|
+
name = formattedName;
|
|
412
|
+
}
|
|
413
|
+
typesFileContent += `export type ${typePrefix}${name} = ${typeCnt};\n`;
|
|
198
414
|
}
|
|
199
415
|
}
|
|
200
|
-
if ((
|
|
416
|
+
if ((_p = endpointSpec[method]) === null || _p === void 0 ? void 0 : _p.responses) {
|
|
201
417
|
// create request response types
|
|
202
|
-
const responses = (
|
|
418
|
+
const responses = (_q = endpointSpec[method]) === null || _q === void 0 ? void 0 : _q.responses;
|
|
203
419
|
const resCodes = Object.keys(responses);
|
|
204
420
|
resCodes.forEach((code) => {
|
|
421
|
+
var _a, _b, _c;
|
|
205
422
|
let typeCnt = getBodySchemaType(responses[code]);
|
|
206
423
|
if (typeCnt) {
|
|
207
|
-
|
|
424
|
+
let name = `${endpoint.name}${code}Response`;
|
|
425
|
+
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) {
|
|
426
|
+
const formattedName = config.types.name.format("endpoint", {
|
|
427
|
+
code,
|
|
428
|
+
type: "response",
|
|
429
|
+
method,
|
|
430
|
+
path: endpointPath,
|
|
431
|
+
summary: (_c = endpointSpec[method]) === null || _c === void 0 ? void 0 : _c.summary,
|
|
432
|
+
});
|
|
433
|
+
if (formattedName)
|
|
434
|
+
name = formattedName;
|
|
435
|
+
}
|
|
436
|
+
typesFileContent += `export type ${typePrefix}${name} = ${typeCnt};\n`;
|
|
208
437
|
}
|
|
209
438
|
});
|
|
210
439
|
}
|
package/dist/index.js
CHANGED
|
@@ -21,7 +21,20 @@ dotenv_1.default.config();
|
|
|
21
21
|
const rootUsingCwd = process.cwd();
|
|
22
22
|
const Init = (options) => __awaiter(void 0, void 0, void 0, function* () {
|
|
23
23
|
// Load config file
|
|
24
|
-
|
|
24
|
+
let configJS, configJson;
|
|
25
|
+
try {
|
|
26
|
+
configJS = require(path_1.default.join(rootUsingCwd, "openapi.sync.js"));
|
|
27
|
+
}
|
|
28
|
+
catch (e) {
|
|
29
|
+
// console.log(e);
|
|
30
|
+
}
|
|
31
|
+
try {
|
|
32
|
+
configJson = require(path_1.default.join(rootUsingCwd, "openapi.sync.json"));
|
|
33
|
+
}
|
|
34
|
+
catch (e) {
|
|
35
|
+
// console.log(e);
|
|
36
|
+
}
|
|
37
|
+
const config = configJS || configJson;
|
|
25
38
|
const apiNames = Object.keys(config.api);
|
|
26
39
|
const refetchInterval = options &&
|
|
27
40
|
"refetchInterval" in options &&
|
|
@@ -32,7 +45,7 @@ const Init = (options) => __awaiter(void 0, void 0, void 0, function* () {
|
|
|
32
45
|
for (let i = 0; i < apiNames.length; i += 1) {
|
|
33
46
|
const apiName = apiNames[i];
|
|
34
47
|
const apiUrl = config.api[apiName];
|
|
35
|
-
(0, Openapi_sync_1.default)(apiUrl, apiName, refetchInterval);
|
|
48
|
+
(0, Openapi_sync_1.default)(apiUrl, apiName, config, refetchInterval);
|
|
36
49
|
}
|
|
37
50
|
});
|
|
38
51
|
exports.Init = Init;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openapi-sync",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
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",
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
"bin",
|
|
25
25
|
"dist",
|
|
26
26
|
"db.json",
|
|
27
|
+
"types.ts",
|
|
27
28
|
"LICENSE",
|
|
28
29
|
"README.md",
|
|
29
30
|
"package.json"
|
|
@@ -31,7 +32,7 @@
|
|
|
31
32
|
"scripts": {
|
|
32
33
|
"test": "echo \"Error: no test specified\"",
|
|
33
34
|
"build": "tsc",
|
|
34
|
-
"publish-package": "npm run build && npm version
|
|
35
|
+
"publish-package": "npm run build && npm version major && npm publish",
|
|
35
36
|
"start": "npm run build && openapi-sync"
|
|
36
37
|
},
|
|
37
38
|
"author": "P-Technologies",
|
package/types.ts
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { Method } from "axios";
|
|
2
|
+
|
|
3
|
+
export type IOpenApiSpec = Record<"openapi", string> & Record<string, any>;
|
|
4
|
+
|
|
5
|
+
export type IOpenApSchemaSpec = {
|
|
6
|
+
nullable?: boolean;
|
|
7
|
+
type: "string" | "integer" | "number" | "array" | "object" | "boolean";
|
|
8
|
+
example?: any;
|
|
9
|
+
enum?: string[];
|
|
10
|
+
format?: string;
|
|
11
|
+
items?: IOpenApSchemaSpec;
|
|
12
|
+
required?: string[];
|
|
13
|
+
$ref?: string;
|
|
14
|
+
properties?: Record<string, IOpenApSchemaSpec>;
|
|
15
|
+
additionalProperties?: IOpenApSchemaSpec;
|
|
16
|
+
anyOf?: IOpenApSchemaSpec[];
|
|
17
|
+
oneOf?: IOpenApSchemaSpec[];
|
|
18
|
+
allOf?: IOpenApSchemaSpec[];
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export type IOpenApiParameterSpec = {
|
|
22
|
+
$ref?: string;
|
|
23
|
+
name: string;
|
|
24
|
+
in: string;
|
|
25
|
+
enum?: string[];
|
|
26
|
+
description?: string;
|
|
27
|
+
required?: boolean;
|
|
28
|
+
deprecated?: boolean;
|
|
29
|
+
allowEmptyValue?: boolean;
|
|
30
|
+
style?: string;
|
|
31
|
+
explode?: boolean;
|
|
32
|
+
allowReserved?: boolean;
|
|
33
|
+
schema?: IOpenApSchemaSpec;
|
|
34
|
+
example?: any;
|
|
35
|
+
examples?: any[];
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export type IOpenApiMediaTypeSpec = {
|
|
39
|
+
schema?: IOpenApSchemaSpec;
|
|
40
|
+
example?: any;
|
|
41
|
+
examples?: any[];
|
|
42
|
+
encoding?: any;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export type IOpenApiRequestBodySpec = {
|
|
46
|
+
description?: string;
|
|
47
|
+
required?: boolean;
|
|
48
|
+
content: Record<string, IOpenApiMediaTypeSpec>;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export type IOpenApiResponseSpec = Record<string, IOpenApiRequestBodySpec>;
|
|
52
|
+
|
|
53
|
+
export type IConfigReplaceWord = {
|
|
54
|
+
/** string and regular expression as a string*/
|
|
55
|
+
replace: string;
|
|
56
|
+
with: string;
|
|
57
|
+
type?: "endpoint" | "type";
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export type IConfig = {
|
|
61
|
+
refetchInterval?: number;
|
|
62
|
+
folder?: string;
|
|
63
|
+
api: Record<string, string>;
|
|
64
|
+
types?: {
|
|
65
|
+
name?: {
|
|
66
|
+
prefix?: string;
|
|
67
|
+
format?: (
|
|
68
|
+
source: "shared" | "endpoint",
|
|
69
|
+
data: {
|
|
70
|
+
name?: string;
|
|
71
|
+
type?: "response" | "dto" | "query";
|
|
72
|
+
code?: string;
|
|
73
|
+
method?: Method;
|
|
74
|
+
path?: string;
|
|
75
|
+
summary?: string;
|
|
76
|
+
}
|
|
77
|
+
) => string | null | undefined;
|
|
78
|
+
};
|
|
79
|
+
};
|
|
80
|
+
endpoints?: {
|
|
81
|
+
value?: {
|
|
82
|
+
replaceWords?: IConfigReplaceWord[];
|
|
83
|
+
};
|
|
84
|
+
name?: {
|
|
85
|
+
format?: (data: {
|
|
86
|
+
method: Method;
|
|
87
|
+
path: string;
|
|
88
|
+
summary: string;
|
|
89
|
+
}) => string | null;
|
|
90
|
+
prefix?: string;
|
|
91
|
+
};
|
|
92
|
+
};
|
|
93
|
+
};
|
|
File without changes
|