openapi-sync 1.0.24 → 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/README.md +113 -12
- package/dist/Openapi-sync/components/helpers.js +17 -113
- package/dist/Openapi-sync/index.js +296 -39
- 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
package/README.md
CHANGED
|
@@ -1,37 +1,138 @@
|
|
|
1
1
|
# Openapi-sync
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/openapi-sync)
|
|
4
|
+
[](https://github.com/akintomiwa-fisayo/openapi-sync/blob/main/LICENSE)
|
|
5
|
+
|
|
6
|
+
**Openapi-sync** is a powerful developer tool that automates the synchronization of your API documentation with your codebase using OpenAPI (formerly Swagger) specifications. It generates TypeScript types and endpoint definitions from your OpenAPI schema, ensuring your API documentation stays up-to-date with your code.
|
|
7
|
+
|
|
8
|
+
## Features
|
|
9
|
+
|
|
10
|
+
- 🔄 Real-time API Synchronization
|
|
11
|
+
- 📝 Automatic Type Generation
|
|
12
|
+
- 🔄 Periodic API Refetching
|
|
13
|
+
- 📁 Configurable Output Directory
|
|
14
|
+
- 🔄 Customizable Naming Conventions
|
|
15
|
+
- 🔄 Endpoint URL Transformation
|
|
16
|
+
- 🔄 Schema Validation
|
|
17
|
+
- 🔄 CLI Integration
|
|
18
|
+
- 🔄 TypeScript Support
|
|
19
|
+
- 🔄 YAML and JSON Support
|
|
4
20
|
|
|
5
21
|
## Installation
|
|
6
22
|
|
|
7
|
-
|
|
23
|
+
Install the package using npm:
|
|
8
24
|
|
|
9
25
|
```bash
|
|
10
26
|
npm install openapi-sync
|
|
11
27
|
```
|
|
12
28
|
|
|
29
|
+
Or use it directly via npx:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
npx openapi-sync
|
|
33
|
+
```
|
|
34
|
+
|
|
13
35
|
## Configuration
|
|
14
36
|
|
|
15
|
-
Create
|
|
37
|
+
Create a `openapi.sync.json` file in your project root with the following structure:
|
|
38
|
+
|
|
39
|
+
```json
|
|
40
|
+
{
|
|
41
|
+
"refetchInterval": 5000, // milliseconds between API refetches
|
|
42
|
+
"folder": "/path/to/output", // output directory for generated files
|
|
43
|
+
"api": {
|
|
44
|
+
"example1": "https://api.example.com/openapi.json",
|
|
45
|
+
"example2": "https://api.example.com/openapi.yaml"
|
|
46
|
+
},
|
|
47
|
+
"naming": {
|
|
48
|
+
"replaceWords": [
|
|
49
|
+
{
|
|
50
|
+
"replace": "Api",
|
|
51
|
+
"with": "",
|
|
52
|
+
"type": "endpoint"
|
|
53
|
+
}
|
|
54
|
+
]
|
|
55
|
+
},
|
|
56
|
+
"endpoints": {
|
|
57
|
+
"value": {
|
|
58
|
+
"replaceWords": [
|
|
59
|
+
{
|
|
60
|
+
"replace": "/api/v\\d/",
|
|
61
|
+
"with": ""
|
|
62
|
+
}
|
|
63
|
+
]
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
```
|
|
16
68
|
|
|
17
69
|
## Usage
|
|
18
70
|
|
|
19
|
-
|
|
71
|
+
### CLI Commands
|
|
20
72
|
|
|
21
73
|
```bash
|
|
74
|
+
# Basic usage
|
|
22
75
|
npx openapi-sync
|
|
76
|
+
|
|
77
|
+
# With custom refetch interval
|
|
78
|
+
npx openapi-sync --refreshinterval 30000
|
|
23
79
|
```
|
|
24
80
|
|
|
25
|
-
|
|
81
|
+
### Programmatic Usage
|
|
26
82
|
|
|
27
|
-
```
|
|
28
|
-
"
|
|
29
|
-
|
|
30
|
-
|
|
83
|
+
```typescript
|
|
84
|
+
import { Init } from "openapi-sync";
|
|
85
|
+
|
|
86
|
+
// Initialize with custom options
|
|
87
|
+
await Init({
|
|
88
|
+
refetchInterval: 30000, // optional, defaults to config value
|
|
89
|
+
});
|
|
31
90
|
```
|
|
32
91
|
|
|
33
|
-
##
|
|
92
|
+
## Output Generation
|
|
93
|
+
|
|
94
|
+
The tool generates:
|
|
95
|
+
|
|
96
|
+
1. TypeScript interfaces for API endpoints
|
|
97
|
+
2. Type definitions for request/response bodies
|
|
98
|
+
3. Shared component types
|
|
99
|
+
4. Endpoint URL constants
|
|
100
|
+
|
|
101
|
+
## Type Generation
|
|
102
|
+
|
|
103
|
+
The tool supports:
|
|
104
|
+
|
|
105
|
+
- Primitive types (string, number, boolean, etc.)
|
|
106
|
+
- Complex types (objects, arrays)
|
|
107
|
+
- Enums
|
|
108
|
+
- Nullable types
|
|
109
|
+
- Any types
|
|
110
|
+
- Shared components
|
|
111
|
+
- Request/response bodies
|
|
112
|
+
|
|
113
|
+
## Error Handling
|
|
114
|
+
|
|
115
|
+
The tool includes:
|
|
116
|
+
|
|
117
|
+
- Network error retries
|
|
118
|
+
- Schema validation
|
|
119
|
+
- Type generation error handling
|
|
120
|
+
- State persistence
|
|
121
|
+
|
|
122
|
+
## API Documentation
|
|
123
|
+
|
|
124
|
+
For detailed API documentation, please refer to the [OpenAPI specification](https://spec.openapis.org/oas/v3.0.3).
|
|
125
|
+
|
|
126
|
+
## License
|
|
127
|
+
|
|
128
|
+
This project is licensed under the ISC License - see the [LICENSE](LICENSE) file for details.
|
|
129
|
+
|
|
130
|
+
## Support
|
|
131
|
+
|
|
132
|
+
For support, please open an issue in the GitHub repository.
|
|
133
|
+
|
|
134
|
+
## Acknowledgments
|
|
34
135
|
|
|
35
|
-
-
|
|
36
|
-
-
|
|
136
|
+
- Thanks to the OpenAPI Initiative for the OpenAPI specification
|
|
137
|
+
- Thanks to all contributors and users of this package
|
|
37
138
|
- Flexible CLI Commands: Sync your API at any point in the development process on app start, pre-commit, or via manual triggers.
|
|
@@ -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) => `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,114 +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
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
const component = lodash_1.default.get(apiDoc, pathToComponent, null);
|
|
118
|
-
if (component) {
|
|
119
|
-
const componentName = pathToComponentParts[pathToComponentParts.length - 1];
|
|
120
|
-
// Reference component via import instead of parsing
|
|
121
|
-
type += `${(options === null || options === void 0 ? void 0 : options.noSharedImport) ? "" : "Shared."}${(0, exports.getSharedComponentName)(componentName)}`;
|
|
122
|
-
// type += `${parseSchemaToType(apiDoc, component, "", isRequired)}`;
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
else {
|
|
126
|
-
type += "";
|
|
127
|
-
//TODO $ref is a uri - use axios to fetch doc
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
else if (schema.anyOf) {
|
|
131
|
-
type += `(${schema.anyOf
|
|
132
|
-
.map((v) => (0, exports.parseSchemaToType)(apiDoc, v, "", isRequired, options))
|
|
133
|
-
.join("|")})`;
|
|
134
|
-
}
|
|
135
|
-
else if (schema.oneOf) {
|
|
136
|
-
type += `(${schema.oneOf
|
|
137
|
-
.map((v) => (0, exports.parseSchemaToType)(apiDoc, v, "", isRequired, options))
|
|
138
|
-
.join("|")})`;
|
|
139
|
-
}
|
|
140
|
-
else if (schema.allOf) {
|
|
141
|
-
type += `(${schema.allOf
|
|
142
|
-
.map((v) => (0, exports.parseSchemaToType)(apiDoc, v, "", isRequired, options))
|
|
143
|
-
.join("&")})`;
|
|
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);
|
|
144
111
|
}
|
|
145
|
-
else
|
|
146
|
-
|
|
147
|
-
}
|
|
148
|
-
else if (schema.properties) {
|
|
149
|
-
//parse object key one at a time
|
|
150
|
-
const objKeys = Object.keys(schema.properties);
|
|
151
|
-
const requiredKeys = schema.required || [];
|
|
152
|
-
let typeCnt = "";
|
|
153
|
-
objKeys.forEach((key) => {
|
|
154
|
-
var _a;
|
|
155
|
-
typeCnt += `${(0, exports.parseSchemaToType)(apiDoc, (_a = schema.properties) === null || _a === void 0 ? void 0 : _a[key], key, requiredKeys.includes(key), options)}`;
|
|
156
|
-
});
|
|
157
|
-
if (typeCnt.length > 0) {
|
|
158
|
-
type += `{\n${typeCnt}}`;
|
|
159
|
-
}
|
|
160
|
-
else {
|
|
161
|
-
type += "{[k: string]: any}";
|
|
162
|
-
}
|
|
112
|
+
else {
|
|
113
|
+
result += value;
|
|
163
114
|
}
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
if (schema.enum.length > 1)
|
|
167
|
-
type += "(";
|
|
168
|
-
type += schema.enum
|
|
169
|
-
.map((v) => `"${v}"`)
|
|
170
|
-
.join("|")
|
|
171
|
-
.toString();
|
|
172
|
-
if (schema.enum.length > 1)
|
|
173
|
-
type += ")";
|
|
174
|
-
}
|
|
175
|
-
else if (["string", "integer", "number", "array", "boolean"].includes(schema.type)) {
|
|
176
|
-
if (["integer", "number"].includes(schema.type)) {
|
|
177
|
-
type += `number`;
|
|
178
|
-
}
|
|
179
|
-
else if (schema.type === "array") {
|
|
180
|
-
//Since we would have already parsed the arrays keys above "schema.items" if it exists
|
|
181
|
-
type += "any[]";
|
|
182
|
-
/* if (schema.items) {
|
|
183
|
-
type += `${parseSchemaToType(
|
|
184
|
-
apiDoc,
|
|
185
|
-
schema.items,
|
|
186
|
-
"",
|
|
187
|
-
false,
|
|
188
|
-
options
|
|
189
|
-
)}[]`;
|
|
190
|
-
} else {
|
|
191
|
-
type += "any[]";
|
|
192
|
-
} */
|
|
193
|
-
}
|
|
194
|
-
else {
|
|
195
|
-
type += schema.type;
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
else if (schema.type === "object") {
|
|
199
|
-
//Since we would have already parsed the object keys above "schema.properties" if it exists
|
|
200
|
-
if (schema.additionalProperties) {
|
|
201
|
-
type += `{[k: string]: ${(0, exports.parseSchemaToType)(apiDoc, schema.additionalProperties, "", true, options) || "any"}}`;
|
|
202
|
-
}
|
|
203
|
-
else {
|
|
204
|
-
type += "{[k: string]: any}";
|
|
205
|
-
}
|
|
206
|
-
}
|
|
115
|
+
if (i < keys.length - 1) {
|
|
116
|
+
result += ", ";
|
|
207
117
|
}
|
|
208
118
|
}
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
type = "string";
|
|
212
|
-
}
|
|
213
|
-
const nullable = (schema === null || schema === void 0 ? void 0 : schema.nullable) ? " | null" : "";
|
|
214
|
-
return type.length > 0
|
|
215
|
-
? `${typeName}${type}${nullable}${name ? ";\n" : ""}`
|
|
216
|
-
: "";
|
|
119
|
+
result += "}";
|
|
120
|
+
return result;
|
|
217
121
|
};
|
|
218
|
-
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,28 +213,84 @@ 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 = "";
|
|
73
225
|
let typesFileContent = "";
|
|
74
|
-
let sharedTypesFileContent =
|
|
75
|
-
if (spec.components
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
226
|
+
let sharedTypesFileContent = {};
|
|
227
|
+
if (spec.components) {
|
|
228
|
+
Object.keys(spec.components).forEach((key) => {
|
|
229
|
+
if ([
|
|
230
|
+
"schemas",
|
|
231
|
+
"responses",
|
|
232
|
+
"parameters",
|
|
233
|
+
"examples",
|
|
234
|
+
"requestBodies",
|
|
235
|
+
"headers",
|
|
236
|
+
"links",
|
|
237
|
+
"callbacks",
|
|
238
|
+
].includes(key)) {
|
|
239
|
+
// Create components (shared) types
|
|
240
|
+
const components = spec.components[key];
|
|
241
|
+
const componentInterfaces = {};
|
|
242
|
+
const contentKeys = Object.keys(components);
|
|
243
|
+
// only need 1 schema so will us the first schema provided
|
|
244
|
+
contentKeys.forEach((contentKey) => {
|
|
245
|
+
var _a;
|
|
246
|
+
/* const schema = (() => {
|
|
247
|
+
switch (key) {
|
|
248
|
+
case "parameters":
|
|
249
|
+
return components[contentKey].schema;
|
|
250
|
+
default:
|
|
251
|
+
return components[contentKey];
|
|
252
|
+
}
|
|
253
|
+
})() as IOpenApSchemaSpec; */
|
|
254
|
+
const schema = (((_a = components[contentKey]) === null || _a === void 0 ? void 0 : _a.schema)
|
|
255
|
+
? components[contentKey].schema
|
|
256
|
+
: components[contentKey]);
|
|
257
|
+
const typeCnt = `${parseSchemaToType(spec, schema, "", true, {
|
|
258
|
+
noSharedImport: true,
|
|
259
|
+
useComponentName: ["parameters"].includes(key),
|
|
260
|
+
})}`;
|
|
261
|
+
if (typeCnt) {
|
|
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
|
+
}
|
|
279
|
+
}
|
|
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
|
+
});
|
|
86
294
|
}
|
|
87
295
|
});
|
|
88
296
|
}
|
|
@@ -92,17 +300,17 @@ const OpenapiSync = (apiUrl, apiName, refetchInterval) => __awaiter(void 0, void
|
|
|
92
300
|
const contentKeys = Object.keys(requestBody.content);
|
|
93
301
|
// only need 1 schema so will us the first schema provided
|
|
94
302
|
if (contentKeys[0] && requestBody.content[contentKeys[0]].schema) {
|
|
95
|
-
typeCnt += `${
|
|
303
|
+
typeCnt += `${parseSchemaToType(spec, requestBody.content[contentKeys[0]].schema, "")}`;
|
|
96
304
|
}
|
|
97
305
|
}
|
|
98
306
|
return typeCnt;
|
|
99
307
|
};
|
|
100
308
|
const treatEndpointUrl = (endpointUrl) => {
|
|
101
|
-
var _a, _b;
|
|
309
|
+
var _a, _b, _c, _d, _e;
|
|
102
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) &&
|
|
103
311
|
Array.isArray(config.endpoints.value.replaceWords)) {
|
|
104
312
|
let newEndpointUrl = endpointUrl;
|
|
105
|
-
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) => {
|
|
106
314
|
const regexp = new RegExp(replaceWord.replace, "g");
|
|
107
315
|
newEndpointUrl = newEndpointUrl.replace(regexp, replaceWord.with || "");
|
|
108
316
|
});
|
|
@@ -114,9 +322,11 @@ const OpenapiSync = (apiUrl, apiName, refetchInterval) => __awaiter(void 0, void
|
|
|
114
322
|
};
|
|
115
323
|
Object.keys(spec.paths || {}).forEach((endpointPath) => {
|
|
116
324
|
const endpointSpec = spec.paths[endpointPath];
|
|
325
|
+
// console.log("Endpoint Path:", { endpointPath, endpointSpec });
|
|
117
326
|
const endpointMethods = Object.keys(endpointSpec);
|
|
118
|
-
endpointMethods.forEach((
|
|
119
|
-
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;
|
|
120
330
|
const endpoint = (0, helpers_1.getEndpointDetails)(endpointPath, method);
|
|
121
331
|
const endpointUrlTxt = endpoint.pathParts
|
|
122
332
|
.map((part) => {
|
|
@@ -145,38 +355,85 @@ const OpenapiSync = (apiUrl, apiName, refetchInterval) => __awaiter(void 0, void
|
|
|
145
355
|
}
|
|
146
356
|
//treat endpoint url
|
|
147
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
|
+
}
|
|
148
368
|
// Add the endpoint url
|
|
149
|
-
endpointsFileContent += `export const ${
|
|
369
|
+
endpointsFileContent += `export const ${endpointPrefix}${name} = ${endpointUrl};
|
|
150
370
|
`;
|
|
151
|
-
if ((
|
|
371
|
+
if ((_d = endpointSpec[method]) === null || _d === void 0 ? void 0 : _d.parameters) {
|
|
152
372
|
// create query parameters types
|
|
153
|
-
const parameters = (
|
|
373
|
+
const parameters = (_e = endpointSpec[method]) === null || _e === void 0 ? void 0 : _e.parameters;
|
|
154
374
|
let typeCnt = "";
|
|
155
|
-
parameters.forEach((param) => {
|
|
156
|
-
if (param.in === "query" && param.name) {
|
|
157
|
-
typeCnt += `${
|
|
375
|
+
parameters.forEach((param, i) => {
|
|
376
|
+
if (param.$ref || (param.in === "query" && param.name)) {
|
|
377
|
+
typeCnt += `${parseSchemaToType(spec, param.$ref ? param : param.schema, param.name || "", param.required)}`;
|
|
158
378
|
}
|
|
159
379
|
});
|
|
160
380
|
if (typeCnt) {
|
|
161
|
-
|
|
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`;
|
|
162
394
|
}
|
|
163
395
|
}
|
|
164
|
-
if ((
|
|
396
|
+
if ((_j = endpointSpec[method]) === null || _j === void 0 ? void 0 : _j.requestBody) {
|
|
165
397
|
//create requestBody types
|
|
166
|
-
const requestBody = (
|
|
398
|
+
const requestBody = (_k = endpointSpec[method]) === null || _k === void 0 ? void 0 : _k.requestBody;
|
|
167
399
|
let typeCnt = getBodySchemaType(requestBody);
|
|
168
400
|
if (typeCnt) {
|
|
169
|
-
|
|
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`;
|
|
170
414
|
}
|
|
171
415
|
}
|
|
172
|
-
if ((
|
|
416
|
+
if ((_p = endpointSpec[method]) === null || _p === void 0 ? void 0 : _p.responses) {
|
|
173
417
|
// create request response types
|
|
174
|
-
const responses = (
|
|
418
|
+
const responses = (_q = endpointSpec[method]) === null || _q === void 0 ? void 0 : _q.responses;
|
|
175
419
|
const resCodes = Object.keys(responses);
|
|
176
420
|
resCodes.forEach((code) => {
|
|
421
|
+
var _a, _b, _c;
|
|
177
422
|
let typeCnt = getBodySchemaType(responses[code]);
|
|
178
423
|
if (typeCnt) {
|
|
179
|
-
|
|
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`;
|
|
180
437
|
}
|
|
181
438
|
});
|
|
182
439
|
}
|
|
@@ -187,21 +444,21 @@ const OpenapiSync = (apiUrl, apiName, refetchInterval) => __awaiter(void 0, void
|
|
|
187
444
|
yield fs_1.default.promises.mkdir(path_1.default.dirname(endpointsFilePath), { recursive: true });
|
|
188
445
|
// Create the file asynchronously
|
|
189
446
|
yield fs_1.default.promises.writeFile(endpointsFilePath, endpointsFileContent);
|
|
190
|
-
if (sharedTypesFileContent.length > 0) {
|
|
447
|
+
if (Object.values(sharedTypesFileContent).length > 0) {
|
|
191
448
|
// Create the necessary directories
|
|
192
449
|
const sharedTypesFilePath = path_1.default.join(rootUsingCwd, folderPath, "types", "shared.ts");
|
|
193
450
|
yield fs_1.default.promises.mkdir(path_1.default.dirname(sharedTypesFilePath), {
|
|
194
451
|
recursive: true,
|
|
195
452
|
});
|
|
196
453
|
// Create the file asynchronously
|
|
197
|
-
yield fs_1.default.promises.writeFile(sharedTypesFilePath, sharedTypesFileContent);
|
|
454
|
+
yield fs_1.default.promises.writeFile(sharedTypesFilePath, Object.values(sharedTypesFileContent).join("\n"));
|
|
198
455
|
}
|
|
199
456
|
if (typesFileContent.length > 0) {
|
|
200
457
|
// Create the necessary directories
|
|
201
458
|
const typesFilePath = path_1.default.join(rootUsingCwd, folderPath, "types", "index.ts");
|
|
202
459
|
yield fs_1.default.promises.mkdir(path_1.default.dirname(typesFilePath), { recursive: true });
|
|
203
460
|
// Create the file asynchronously
|
|
204
|
-
yield fs_1.default.promises.writeFile(typesFilePath, `${sharedTypesFileContent.length > 0
|
|
461
|
+
yield fs_1.default.promises.writeFile(typesFilePath, `${Object.values(sharedTypesFileContent).length > 0
|
|
205
462
|
? `import * as Shared from "./shared";\n\n`
|
|
206
463
|
: ""}${typesFileContent}`);
|
|
207
464
|
}
|
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
|