api-farmer 0.0.19 → 0.0.20
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/chunk-5YXY7GCE.js +280 -0
- package/dist/{chunk-SKKHIIUE.js → chunk-NFK24PSA.js} +8 -5
- package/dist/cli.cjs +80 -101943
- package/dist/cli.js +2 -3
- package/dist/{generate-IJGTBA2I.js → generate-IQIB2PJD.js} +2 -3
- package/dist/index.cjs +186 -102087
- package/dist/index.js +2 -3
- package/package.json +3 -3
- package/dist/acorn-O63CA7L4.js +0 -3047
- package/dist/angular-U44OZXUW.js +0 -2794
- package/dist/babel-VWJW3TNP.js +0 -6946
- package/dist/chunk-6OIOYGN7.js +0 -17
- package/dist/chunk-K46PCBCF.js +0 -22981
- package/dist/estree-OIZOUIW7.js +0 -4374
- package/dist/flow-TDKVTHFE.js +0 -26897
- package/dist/glimmer-AWQE7API.js +0 -2847
- package/dist/graphql-IJWEVF4G.js +0 -1247
- package/dist/html-7SW5PDZO.js +0 -2716
- package/dist/markdown-2BNVGUT3.js +0 -3484
- package/dist/meriyah-L52O7E6A.js +0 -2474
- package/dist/postcss-AOWY4ITF.js +0 -5057
- package/dist/typescript-ANND5E4Y.js +0 -13104
- package/dist/yaml-MB3PL3NY.js +0 -4223
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CWD,
|
|
3
|
+
SUPPORTED_HTTP_METHODS,
|
|
4
|
+
getValidResponseMetadataItems,
|
|
5
|
+
hasQueryParameter,
|
|
6
|
+
isRequiredRequestBody,
|
|
7
|
+
readSchema,
|
|
8
|
+
readTemplateFile
|
|
9
|
+
} from "./chunk-NFK24PSA.js";
|
|
10
|
+
|
|
11
|
+
// src/generate.ts
|
|
12
|
+
import { resolve } from "path";
|
|
13
|
+
import ejs from "ejs";
|
|
14
|
+
import fse from "fs-extra";
|
|
15
|
+
import openapiTS, { astToString } from "openapi-typescript";
|
|
16
|
+
import prettier from "prettier";
|
|
17
|
+
import { groupBy, isArray, merge } from "rattail";
|
|
18
|
+
import { logger } from "rslog";
|
|
19
|
+
|
|
20
|
+
// src/config.ts
|
|
21
|
+
import { loadConfig } from "unconfig";
|
|
22
|
+
function defineConfig(config) {
|
|
23
|
+
return config;
|
|
24
|
+
}
|
|
25
|
+
async function getConfig() {
|
|
26
|
+
const { config } = await loadConfig({
|
|
27
|
+
sources: [
|
|
28
|
+
{
|
|
29
|
+
files: "api-farmer.config"
|
|
30
|
+
}
|
|
31
|
+
]
|
|
32
|
+
});
|
|
33
|
+
return config ?? {};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// src/transformer.ts
|
|
37
|
+
import pluralize from "pluralize";
|
|
38
|
+
import { camelize, pascalCase } from "rattail";
|
|
39
|
+
function transformModuleName({ name }) {
|
|
40
|
+
return camelize(name);
|
|
41
|
+
}
|
|
42
|
+
function transformUrl({ path, base }) {
|
|
43
|
+
return (base ? path.replace(base, "") : path).replace(/{/g, ":").replace(/}/g, "");
|
|
44
|
+
}
|
|
45
|
+
function transformVerb({ method }) {
|
|
46
|
+
switch (method) {
|
|
47
|
+
case "post":
|
|
48
|
+
return "Create";
|
|
49
|
+
case "put":
|
|
50
|
+
return "Update";
|
|
51
|
+
default:
|
|
52
|
+
return pascalCase(method);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
function transformEntity({ path, method, base }) {
|
|
56
|
+
path = base ? path.replace(base, "") : path;
|
|
57
|
+
const words = path.split("/").filter(Boolean);
|
|
58
|
+
return words.reduce((entity, word, index) => {
|
|
59
|
+
if (word.includes("{")) {
|
|
60
|
+
return entity;
|
|
61
|
+
}
|
|
62
|
+
word = word.replace(/\.([a-z])/g, (_, p) => p.toUpperCase());
|
|
63
|
+
word = pluralize.singular(pascalCase(word));
|
|
64
|
+
if (method === "get" && index === words.length - 1) {
|
|
65
|
+
word = pluralize.plural(word);
|
|
66
|
+
}
|
|
67
|
+
return `${entity}${word}`;
|
|
68
|
+
}, "");
|
|
69
|
+
}
|
|
70
|
+
function transformFn({ verb, entity }) {
|
|
71
|
+
return `api${verb}${entity}`;
|
|
72
|
+
}
|
|
73
|
+
function transformType({ verb, entity }) {
|
|
74
|
+
return `Api${verb}${entity}`;
|
|
75
|
+
}
|
|
76
|
+
function transformTypeValue({ path, method }) {
|
|
77
|
+
return `paths['${path}']['${method}']`;
|
|
78
|
+
}
|
|
79
|
+
function transformTypeQuery({ type }) {
|
|
80
|
+
return `${type}Query`;
|
|
81
|
+
}
|
|
82
|
+
function transformTypeQueryValue({
|
|
83
|
+
type
|
|
84
|
+
}) {
|
|
85
|
+
return `${type}['parameters']['query']`;
|
|
86
|
+
}
|
|
87
|
+
function transformTypeRequestBody({
|
|
88
|
+
type
|
|
89
|
+
}) {
|
|
90
|
+
return `${type}RequestBody`;
|
|
91
|
+
}
|
|
92
|
+
function transformTypeRequestBodyValue({
|
|
93
|
+
type,
|
|
94
|
+
required
|
|
95
|
+
}) {
|
|
96
|
+
return required ? `${type}['requestBody']['content']['application/json']` : `NonNullable<${type}['requestBody']>['content']['application/json'] | undefined`;
|
|
97
|
+
}
|
|
98
|
+
function transformTypeResponseBody({
|
|
99
|
+
type
|
|
100
|
+
}) {
|
|
101
|
+
return `${type}ResponseBody`;
|
|
102
|
+
}
|
|
103
|
+
function transformTypeResponseBodyValue({
|
|
104
|
+
type,
|
|
105
|
+
responseMetadataItems
|
|
106
|
+
}) {
|
|
107
|
+
return responseMetadataItems.map(({ status, mime }) => `${type}['responses']['${status}']['content']['${mime}']`).join(" | ");
|
|
108
|
+
}
|
|
109
|
+
function createTransformer() {
|
|
110
|
+
return {
|
|
111
|
+
moduleName: transformModuleName,
|
|
112
|
+
verb: transformVerb,
|
|
113
|
+
url: transformUrl,
|
|
114
|
+
entity: transformEntity,
|
|
115
|
+
fn: transformFn,
|
|
116
|
+
type: transformType,
|
|
117
|
+
typeValue: transformTypeValue,
|
|
118
|
+
typeQuery: transformTypeQuery,
|
|
119
|
+
typeQueryValue: transformTypeQueryValue,
|
|
120
|
+
typeRequestBody: transformTypeRequestBody,
|
|
121
|
+
typeRequestBodyValue: transformTypeRequestBodyValue,
|
|
122
|
+
typeResponseBody: transformTypeResponseBody,
|
|
123
|
+
typeResponseBodyValue: transformTypeResponseBodyValue
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// src/generate.ts
|
|
128
|
+
function transformPayloads(pathItems, options) {
|
|
129
|
+
const { transformer, path, base, validateStatus } = options;
|
|
130
|
+
return Object.entries(pathItems).filter(([key]) => SUPPORTED_HTTP_METHODS.includes(key)).reduce((payloads, [method, operation]) => {
|
|
131
|
+
const url = transformer.url({ path, base });
|
|
132
|
+
const args = { path, base, url, method, operation };
|
|
133
|
+
const entity = transformer.entity(args);
|
|
134
|
+
const verb = transformer.verb(args);
|
|
135
|
+
const fn = transformer.fn({ ...args, verb, entity });
|
|
136
|
+
const type = transformer.type({ ...args, verb, entity });
|
|
137
|
+
const typeValue = transformer.typeValue({ ...args, verb, entity });
|
|
138
|
+
const typeQuery = transformer.typeQuery({ ...args, type, verb, entity });
|
|
139
|
+
const typeQueryValue = hasQueryParameter(operation) ? transformer.typeQueryValue({ ...args, type, verb, entity }) : "undefined";
|
|
140
|
+
const typeRequestBody = transformer.typeRequestBody({ ...args, type, verb, entity });
|
|
141
|
+
const typeRequestBodyValue = operation.requestBody ? transformer.typeRequestBodyValue({
|
|
142
|
+
...args,
|
|
143
|
+
type,
|
|
144
|
+
verb,
|
|
145
|
+
entity,
|
|
146
|
+
required: isRequiredRequestBody(operation.requestBody)
|
|
147
|
+
}) : "undefined";
|
|
148
|
+
const typeResponseBody = transformer.typeResponseBody({ ...args, type, verb, entity });
|
|
149
|
+
const responseMetadataItems = getValidResponseMetadataItems(operation, validateStatus);
|
|
150
|
+
const typeResponseBodyValue = responseMetadataItems.length > 0 ? transformer.typeResponseBodyValue({ ...args, type, verb, entity, responseMetadataItems }) : "undefined";
|
|
151
|
+
payloads.push({
|
|
152
|
+
fn,
|
|
153
|
+
url,
|
|
154
|
+
method,
|
|
155
|
+
verb,
|
|
156
|
+
entity,
|
|
157
|
+
type,
|
|
158
|
+
typeValue,
|
|
159
|
+
typeQuery,
|
|
160
|
+
typeQueryValue,
|
|
161
|
+
typeRequestBody,
|
|
162
|
+
typeRequestBodyValue,
|
|
163
|
+
typeResponseBody,
|
|
164
|
+
typeResponseBodyValue
|
|
165
|
+
});
|
|
166
|
+
return payloads;
|
|
167
|
+
}, []);
|
|
168
|
+
}
|
|
169
|
+
function partitionApiModules(schema, options) {
|
|
170
|
+
const { base, transformer, validateStatus } = options;
|
|
171
|
+
const schemaPaths = schema.paths ?? {};
|
|
172
|
+
const schemaPathKeys = base ? Object.keys(schemaPaths).map((key) => key.replace(base, "")) : Object.keys(schemaPaths);
|
|
173
|
+
const keyToPaths = groupBy(schemaPathKeys, (key) => key.split("/")[1]);
|
|
174
|
+
const apiModules = Object.entries(keyToPaths).reduce((apiModules2, [name, paths]) => {
|
|
175
|
+
const payloads = paths.reduce((payloads2, path) => {
|
|
176
|
+
const pathItems = schemaPaths[path];
|
|
177
|
+
payloads2.push(
|
|
178
|
+
...transformPayloads(pathItems, { ...options, path: base ? base + path : path, transformer, validateStatus })
|
|
179
|
+
);
|
|
180
|
+
return payloads2;
|
|
181
|
+
}, []);
|
|
182
|
+
apiModules2.push({ name: transformer.moduleName({ name }), payloads });
|
|
183
|
+
return apiModules2;
|
|
184
|
+
}, []);
|
|
185
|
+
return apiModules;
|
|
186
|
+
}
|
|
187
|
+
function renderApiModules(apiModules, options) {
|
|
188
|
+
const { output, ts, typesOnly, overrides, preset } = options;
|
|
189
|
+
const templateFile = readTemplateFile(preset);
|
|
190
|
+
const typesFilename = options.typesFilename.replace(".ts", "");
|
|
191
|
+
return Promise.all(
|
|
192
|
+
apiModules.map(
|
|
193
|
+
(apiModule) => new Promise((promiseResolve) => {
|
|
194
|
+
const data = {
|
|
195
|
+
apiModule,
|
|
196
|
+
typesFilename,
|
|
197
|
+
ts,
|
|
198
|
+
typesOnly
|
|
199
|
+
};
|
|
200
|
+
prettier.format(ejs.render(templateFile, data), {
|
|
201
|
+
parser: "typescript",
|
|
202
|
+
semi: false,
|
|
203
|
+
singleQuote: true,
|
|
204
|
+
printWidth: 120
|
|
205
|
+
}).then((content) => {
|
|
206
|
+
const path = resolve(output, `${apiModule.name}.${ts ? "ts" : "js"}`);
|
|
207
|
+
const shouldSkip = (!overrides || isArray(overrides) && !overrides.includes(apiModule.name)) && fse.existsSync(path);
|
|
208
|
+
if (shouldSkip) {
|
|
209
|
+
logger.warn(`File already exists, skip: ${path}`);
|
|
210
|
+
promiseResolve(content);
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
fse.outputFileSync(path, content);
|
|
214
|
+
logger.success(`Generated ${path}`);
|
|
215
|
+
promiseResolve(content);
|
|
216
|
+
});
|
|
217
|
+
})
|
|
218
|
+
)
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
async function generateTypes(schema, output, typesFilename) {
|
|
222
|
+
const ast = await openapiTS(schema);
|
|
223
|
+
const contents = astToString(ast);
|
|
224
|
+
const typesFilepath = resolve(CWD, output, typesFilename);
|
|
225
|
+
fse.outputFileSync(typesFilepath, contents);
|
|
226
|
+
logger.success(`Generated ${typesFilepath}`);
|
|
227
|
+
}
|
|
228
|
+
async function generate(userOptions = {}) {
|
|
229
|
+
const config = await getConfig();
|
|
230
|
+
const options = merge(config, userOptions);
|
|
231
|
+
const {
|
|
232
|
+
base,
|
|
233
|
+
ts = true,
|
|
234
|
+
typesOnly = false,
|
|
235
|
+
overrides = true,
|
|
236
|
+
preset = "axle",
|
|
237
|
+
input = "./schema.json",
|
|
238
|
+
output = "./src/apis/generated",
|
|
239
|
+
typesFilename = "_types.ts",
|
|
240
|
+
validateStatus = (status) => status >= 200 && status < 300,
|
|
241
|
+
transformer = {}
|
|
242
|
+
} = options;
|
|
243
|
+
const mergedTransformer = { ...createTransformer(), ...transformer };
|
|
244
|
+
const schema = await readSchema(input);
|
|
245
|
+
logger.info("Generating API modules...");
|
|
246
|
+
if (ts) {
|
|
247
|
+
await generateTypes(schema, output, typesFilename);
|
|
248
|
+
}
|
|
249
|
+
const apiModules = partitionApiModules(schema, {
|
|
250
|
+
base,
|
|
251
|
+
transformer: mergedTransformer,
|
|
252
|
+
validateStatus
|
|
253
|
+
});
|
|
254
|
+
await renderApiModules(apiModules, { output, typesFilename, ts, typesOnly, overrides, preset });
|
|
255
|
+
logger.success("Done");
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
export {
|
|
259
|
+
defineConfig,
|
|
260
|
+
getConfig,
|
|
261
|
+
transformModuleName,
|
|
262
|
+
transformUrl,
|
|
263
|
+
transformVerb,
|
|
264
|
+
transformEntity,
|
|
265
|
+
transformFn,
|
|
266
|
+
transformType,
|
|
267
|
+
transformTypeValue,
|
|
268
|
+
transformTypeQuery,
|
|
269
|
+
transformTypeQueryValue,
|
|
270
|
+
transformTypeRequestBody,
|
|
271
|
+
transformTypeRequestBodyValue,
|
|
272
|
+
transformTypeResponseBody,
|
|
273
|
+
transformTypeResponseBodyValue,
|
|
274
|
+
createTransformer,
|
|
275
|
+
transformPayloads,
|
|
276
|
+
partitionApiModules,
|
|
277
|
+
renderApiModules,
|
|
278
|
+
generateTypes,
|
|
279
|
+
generate
|
|
280
|
+
};
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
// node_modules/.pnpm/tsup@8.3.5_jiti@2.4.2_postcss@8.5.1_tsx@4.19.2_typescript@5.3.3_yaml@2.7.0/node_modules/tsup/assets/esm_shims.js
|
|
2
|
+
import { fileURLToPath } from "url";
|
|
3
|
+
import path from "path";
|
|
4
|
+
var getFilename = () => fileURLToPath(import.meta.url);
|
|
5
|
+
var getDirname = () => path.dirname(getFilename());
|
|
6
|
+
var __dirname = /* @__PURE__ */ getDirname();
|
|
4
7
|
|
|
5
8
|
// src/constants.ts
|
|
6
9
|
import { resolve } from "path";
|
|
@@ -47,8 +50,8 @@ function createStatusCodesByStrategy(strategy) {
|
|
|
47
50
|
}
|
|
48
51
|
async function readSchema(input) {
|
|
49
52
|
const isYaml = input.endsWith(".yaml");
|
|
50
|
-
const
|
|
51
|
-
const content = fse.readFileSync(
|
|
53
|
+
const path2 = resolve2(CWD, input);
|
|
54
|
+
const content = fse.readFileSync(path2, "utf-8");
|
|
52
55
|
const swaggerOrOpenapiSchema = isYaml ? yaml.parse(content) : JSON.parse(content);
|
|
53
56
|
const schema = swaggerOrOpenapiSchema.swagger ? (await swagger.convert(swaggerOrOpenapiSchema, {})).openapi : swaggerOrOpenapiSchema;
|
|
54
57
|
return schema;
|