@tuyau/core 0.0.6 → 0.1.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/build/commands/generate.js +56 -28
- package/package.json +3 -3
|
@@ -8,9 +8,11 @@ import { BaseCommand, flags } from "@adonisjs/core/ace";
|
|
|
8
8
|
|
|
9
9
|
// src/codegen/api_types_generator.ts
|
|
10
10
|
import { Node } from "ts-morph";
|
|
11
|
+
import matchit from "@poppinss/matchit";
|
|
11
12
|
import { fileURLToPath } from "node:url";
|
|
12
13
|
import { dirname, relative } from "node:path";
|
|
13
14
|
import { existsSync, mkdirSync } from "node:fs";
|
|
15
|
+
import string from "@adonisjs/core/helpers/string";
|
|
14
16
|
import { parseBindingReference } from "@adonisjs/core/helpers";
|
|
15
17
|
var ApiTypesGenerator = class {
|
|
16
18
|
#appRoot;
|
|
@@ -34,7 +36,7 @@ var ApiTypesGenerator = class {
|
|
|
34
36
|
* Create the destination directory if it does not exists
|
|
35
37
|
*/
|
|
36
38
|
#prepareDestination() {
|
|
37
|
-
this.#destination = new URL("./.adonisjs/
|
|
39
|
+
this.#destination = new URL("./.adonisjs/api.ts", this.#appRoot);
|
|
38
40
|
const directory = this.#getDestinationDirectory();
|
|
39
41
|
if (!existsSync(directory)) {
|
|
40
42
|
mkdirSync(directory, { recursive: true });
|
|
@@ -90,13 +92,13 @@ var ApiTypesGenerator = class {
|
|
|
90
92
|
/**
|
|
91
93
|
* Generate the final interface containing all routes, request, and response
|
|
92
94
|
*/
|
|
93
|
-
#
|
|
95
|
+
#generateDefinitionInterface(types, indent = " ") {
|
|
94
96
|
let interfaceContent = "";
|
|
95
97
|
Object.entries(types).forEach(([key, value]) => {
|
|
96
98
|
if (typeof value === "object") {
|
|
97
99
|
interfaceContent += `${indent}'${key}': {
|
|
98
100
|
`;
|
|
99
|
-
interfaceContent += this.#
|
|
101
|
+
interfaceContent += this.#generateDefinitionInterface(value, indent + " ");
|
|
100
102
|
interfaceContent += `${indent}};
|
|
101
103
|
`;
|
|
102
104
|
} else {
|
|
@@ -106,22 +108,6 @@ var ApiTypesGenerator = class {
|
|
|
106
108
|
});
|
|
107
109
|
return interfaceContent;
|
|
108
110
|
}
|
|
109
|
-
/**
|
|
110
|
-
* Write the final interface containing all routes, request, and response
|
|
111
|
-
* in a routes.d.ts file
|
|
112
|
-
*/
|
|
113
|
-
async #writeFinalInterface(types) {
|
|
114
|
-
const file = this.#project.createSourceFile(fileURLToPath(this.#destination), "", {
|
|
115
|
-
overwrite: true
|
|
116
|
-
});
|
|
117
|
-
if (!file)
|
|
118
|
-
throw new Error("Unable to create the api.d.ts file");
|
|
119
|
-
file?.removeText();
|
|
120
|
-
file.insertText(0, (writer) => {
|
|
121
|
-
writer.writeLine(`import type { MakeTuyauRequest, MakeTuyauResponse } from '@tuyau/utils/types'`).writeLine(`import type { InferInput } from '@vinejs/vine/types'`).newLine().writeLine(`export interface AdonisApi {`).write(this.#generateFinalInterface(types, " ")).writeLine(`}`);
|
|
122
|
-
});
|
|
123
|
-
await file.save();
|
|
124
|
-
}
|
|
125
111
|
/**
|
|
126
112
|
* Filter routes to generate based on the ignoreRoutes config
|
|
127
113
|
*/
|
|
@@ -141,8 +127,45 @@ var ApiTypesGenerator = class {
|
|
|
141
127
|
return true;
|
|
142
128
|
});
|
|
143
129
|
}
|
|
130
|
+
#generateRoutesNameArray(routes) {
|
|
131
|
+
return routes.map(({ name, pattern, methods }) => {
|
|
132
|
+
const params = matchit.parse(pattern).filter((node) => node.type !== 0).map((node) => node.val);
|
|
133
|
+
const typeName = string.pascalCase(string.slug(pattern)) + string.pascalCase(methods.join(" "));
|
|
134
|
+
return { params, name, path: pattern, method: methods, types: typeName };
|
|
135
|
+
}).filter((route) => !!route.name);
|
|
136
|
+
}
|
|
137
|
+
async #writeApiFile(options) {
|
|
138
|
+
const path = fileURLToPath(this.#destination);
|
|
139
|
+
const file = this.#project.createSourceFile(path, "", { overwrite: true });
|
|
140
|
+
if (!file)
|
|
141
|
+
throw new Error("Unable to create the api.ts file");
|
|
142
|
+
file.removeText().insertText(0, (writer) => {
|
|
143
|
+
writer.writeLine(`import type { MakeTuyauRequest, MakeTuyauResponse } from '@tuyau/utils/types'`).writeLine(`import type { InferInput } from '@vinejs/vine/types'`).newLine();
|
|
144
|
+
Object.entries(options.typesByPattern).forEach(([key, value]) => {
|
|
145
|
+
writer.writeLine(`type ${key} = {`);
|
|
146
|
+
writer.writeLine(` request: ${value.request}`);
|
|
147
|
+
writer.writeLine(` response: ${value.response}`);
|
|
148
|
+
writer.writeLine(`}`);
|
|
149
|
+
});
|
|
150
|
+
writer.writeLine(`interface AdonisApi {`).write(this.#generateDefinitionInterface(options.definition, " ")).writeLine(`}`);
|
|
151
|
+
writer.writeLine(`const routes = [`);
|
|
152
|
+
for (const route of options.routesNameArray) {
|
|
153
|
+
writer.writeLine(` {`);
|
|
154
|
+
writer.writeLine(` params: ${JSON.stringify(route.params)},`);
|
|
155
|
+
writer.writeLine(` name: '${route.name}',`);
|
|
156
|
+
writer.writeLine(` path: '${route.path}',`);
|
|
157
|
+
writer.writeLine(` method: ${JSON.stringify(route.method)},`);
|
|
158
|
+
writer.writeLine(` types: {} as ${route.types},`);
|
|
159
|
+
writer.writeLine(` },`);
|
|
160
|
+
}
|
|
161
|
+
writer.writeLine(`] as const;`);
|
|
162
|
+
writer.writeLine(`export const api = {`).writeLine(` routes,`).writeLine(` definition: {} as AdonisApi`).writeLine(`}`);
|
|
163
|
+
});
|
|
164
|
+
await file.save();
|
|
165
|
+
}
|
|
144
166
|
async generate() {
|
|
145
|
-
const
|
|
167
|
+
const definition = {};
|
|
168
|
+
const typesByPattern = {};
|
|
146
169
|
const sourcesFiles = this.#project.getSourceFiles();
|
|
147
170
|
const routes = this.#filterRoutesToGenerate(this.#routes);
|
|
148
171
|
for (const route of routes) {
|
|
@@ -165,25 +188,30 @@ var ApiTypesGenerator = class {
|
|
|
165
188
|
const schemaImport = this.#extractRequest(handlerData);
|
|
166
189
|
const methods = route.methods.map((method) => "$" + method.toLowerCase()).filter((method) => method !== "head");
|
|
167
190
|
const segments = route.pattern.split("/").filter(Boolean);
|
|
168
|
-
let currentLevel =
|
|
191
|
+
let currentLevel = definition;
|
|
169
192
|
const relativePath = relative(this.#getDestinationDirectory(), file.getFilePath());
|
|
170
193
|
segments.forEach((segment, i) => {
|
|
171
|
-
if (!currentLevel[segment])
|
|
194
|
+
if (!currentLevel[segment])
|
|
172
195
|
currentLevel[segment] = {};
|
|
173
|
-
}
|
|
174
196
|
currentLevel = currentLevel[segment];
|
|
175
197
|
if (i !== segments.length - 1)
|
|
176
198
|
return;
|
|
199
|
+
const typeName = string.pascalCase(string.slug(route.pattern)) + string.pascalCase(methods.join(""));
|
|
200
|
+
typesByPattern[typeName] = {
|
|
201
|
+
request: schemaImport ? `MakeTuyauRequest<${schemaImport}>` : "unknown",
|
|
202
|
+
response: `MakeTuyauResponse<import('${relativePath}').default['${routeHandler.method}']>`
|
|
203
|
+
};
|
|
177
204
|
currentLevel.$url = {};
|
|
178
205
|
for (const method of methods) {
|
|
179
|
-
currentLevel[method] = {
|
|
180
|
-
request: schemaImport ? `MakeTuyauRequest<${schemaImport}>` : "unknown",
|
|
181
|
-
response: `MakeTuyauResponse<import('${relativePath}').default['${routeHandler.method}']>`
|
|
182
|
-
};
|
|
206
|
+
currentLevel[method] = `${string.pascalCase(typeName)}`;
|
|
183
207
|
}
|
|
184
208
|
});
|
|
185
209
|
}
|
|
186
|
-
await this.#
|
|
210
|
+
await this.#writeApiFile({
|
|
211
|
+
definition,
|
|
212
|
+
typesByPattern,
|
|
213
|
+
routesNameArray: this.#generateRoutesNameArray(routes)
|
|
214
|
+
});
|
|
187
215
|
}
|
|
188
216
|
};
|
|
189
217
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tuyau/core",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.0
|
|
4
|
+
"version": "0.1.0",
|
|
5
5
|
"description": "",
|
|
6
6
|
"author": "",
|
|
7
7
|
"license": "MIT",
|
|
@@ -31,8 +31,8 @@
|
|
|
31
31
|
"@poppinss/cliui": "^6.4.1",
|
|
32
32
|
"@poppinss/matchit": "^3.1.2",
|
|
33
33
|
"@types/node": "^20.12.7",
|
|
34
|
-
"@tuyau/
|
|
35
|
-
"@tuyau/
|
|
34
|
+
"@tuyau/utils": "0.0.4",
|
|
35
|
+
"@tuyau/client": "0.1.0"
|
|
36
36
|
},
|
|
37
37
|
"publishConfig": {
|
|
38
38
|
"access": "public",
|