@tuyau/core 0.0.5 → 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/LICENSE.md +9 -0
- package/build/chunk-3KNDPG6Y.js +15 -0
- package/build/commands/commands.json +1 -1
- package/build/commands/generate.d.ts +1 -0
- package/build/commands/generate.js +74 -36
- package/build/index.js +2 -0
- package/build/providers/tuyau_provider.js +2 -0
- package/package.json +19 -33
package/LICENSE.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# The MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __decorateClass = (decorators, target, key, kind) => {
|
|
4
|
+
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
|
|
5
|
+
for (var i = decorators.length - 1, decorator; i >= 0; i--)
|
|
6
|
+
if (decorator = decorators[i])
|
|
7
|
+
result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
8
|
+
if (kind && result)
|
|
9
|
+
__defProp(target, key, result);
|
|
10
|
+
return result;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export {
|
|
14
|
+
__decorateClass
|
|
15
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"commands":[{"commandName":"tuyau:generate","description":"Tuyau generator command","help":"","namespace":"tuyau","aliases":[],"flags":[],"args":[],"options":{"startApp":true},"filePath":"generate.js","absoluteFilePath":"/home/julien/code/adonis/tuyau/packages/core/build/commands/generate.js"}],"version":1}
|
|
1
|
+
{"commands":[{"commandName":"tuyau:generate","description":"Tuyau generator command","help":"","namespace":"tuyau","aliases":[],"flags":[{"name":"verbose","flagName":"verbose","required":false,"type":"boolean","description":"Verbose logs","default":false,"alias":"v"}],"args":[],"options":{"startApp":true},"filePath":"generate.js","absoluteFilePath":"/home/julien/code/adonis/tuyau/packages/core/build/commands/generate.js"}],"version":1}
|
|
@@ -1,12 +1,18 @@
|
|
|
1
|
+
import {
|
|
2
|
+
__decorateClass
|
|
3
|
+
} from "../chunk-3KNDPG6Y.js";
|
|
4
|
+
|
|
1
5
|
// commands/generate.ts
|
|
2
6
|
import { Project, QuoteKind } from "ts-morph";
|
|
3
|
-
import { BaseCommand } from "@adonisjs/core/ace";
|
|
7
|
+
import { BaseCommand, flags } from "@adonisjs/core/ace";
|
|
4
8
|
|
|
5
9
|
// src/codegen/api_types_generator.ts
|
|
6
10
|
import { Node } from "ts-morph";
|
|
11
|
+
import matchit from "@poppinss/matchit";
|
|
7
12
|
import { fileURLToPath } from "node:url";
|
|
8
13
|
import { dirname, relative } from "node:path";
|
|
9
14
|
import { existsSync, mkdirSync } from "node:fs";
|
|
15
|
+
import string from "@adonisjs/core/helpers/string";
|
|
10
16
|
import { parseBindingReference } from "@adonisjs/core/helpers";
|
|
11
17
|
var ApiTypesGenerator = class {
|
|
12
18
|
#appRoot;
|
|
@@ -30,7 +36,7 @@ var ApiTypesGenerator = class {
|
|
|
30
36
|
* Create the destination directory if it does not exists
|
|
31
37
|
*/
|
|
32
38
|
#prepareDestination() {
|
|
33
|
-
this.#destination = new URL("./.adonisjs/
|
|
39
|
+
this.#destination = new URL("./.adonisjs/api.ts", this.#appRoot);
|
|
34
40
|
const directory = this.#getDestinationDirectory();
|
|
35
41
|
if (!existsSync(directory)) {
|
|
36
42
|
mkdirSync(directory, { recursive: true });
|
|
@@ -72,7 +78,12 @@ var ApiTypesGenerator = class {
|
|
|
72
78
|
const schema = validateUsingCallNode.getArguments()[0];
|
|
73
79
|
if (!Node.isIdentifier(schema))
|
|
74
80
|
return;
|
|
75
|
-
const
|
|
81
|
+
const implementation = schema.getImplementations().at(0);
|
|
82
|
+
if (!implementation) {
|
|
83
|
+
this.#logger.warning(`Unable to find the schema file for ${schema.getText()}`);
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
const importPath = implementation.getSourceFile().getFilePath();
|
|
76
87
|
const relativeImportPath = relative(this.#getDestinationDirectory(), importPath);
|
|
77
88
|
return `InferInput<typeof import('${relativeImportPath}')['${schema.getText()}']>`;
|
|
78
89
|
}
|
|
@@ -81,13 +92,13 @@ var ApiTypesGenerator = class {
|
|
|
81
92
|
/**
|
|
82
93
|
* Generate the final interface containing all routes, request, and response
|
|
83
94
|
*/
|
|
84
|
-
#
|
|
95
|
+
#generateDefinitionInterface(types, indent = " ") {
|
|
85
96
|
let interfaceContent = "";
|
|
86
97
|
Object.entries(types).forEach(([key, value]) => {
|
|
87
98
|
if (typeof value === "object") {
|
|
88
99
|
interfaceContent += `${indent}'${key}': {
|
|
89
100
|
`;
|
|
90
|
-
interfaceContent += this.#
|
|
101
|
+
interfaceContent += this.#generateDefinitionInterface(value, indent + " ");
|
|
91
102
|
interfaceContent += `${indent}};
|
|
92
103
|
`;
|
|
93
104
|
} else {
|
|
@@ -97,24 +108,6 @@ var ApiTypesGenerator = class {
|
|
|
97
108
|
});
|
|
98
109
|
return interfaceContent;
|
|
99
110
|
}
|
|
100
|
-
/**
|
|
101
|
-
* Write the final interface containing all routes, request, and response
|
|
102
|
-
* in a routes.d.ts file
|
|
103
|
-
*/
|
|
104
|
-
async #writeFinalInterface(types) {
|
|
105
|
-
const file = this.#project.createSourceFile(fileURLToPath(this.#destination), "", {
|
|
106
|
-
overwrite: true
|
|
107
|
-
});
|
|
108
|
-
if (!file)
|
|
109
|
-
throw new Error("Unable to create the api.d.ts file");
|
|
110
|
-
file?.removeText();
|
|
111
|
-
file.insertText(0, (writer) => {
|
|
112
|
-
writer.writeLine(
|
|
113
|
-
`import type { MakeOptional, Serialize, Simplify, ConvertReturnTypeToRecordStatusResponse } from '@tuyau/utils/types'`
|
|
114
|
-
).writeLine(`import type { InferInput } from '@vinejs/vine/types'`).newLine().writeLine(`export interface AdonisApi {`).write(this.#generateFinalInterface(types, " ")).writeLine(`}`);
|
|
115
|
-
});
|
|
116
|
-
await file.save();
|
|
117
|
-
}
|
|
118
111
|
/**
|
|
119
112
|
* Filter routes to generate based on the ignoreRoutes config
|
|
120
113
|
*/
|
|
@@ -134,8 +127,45 @@ var ApiTypesGenerator = class {
|
|
|
134
127
|
return true;
|
|
135
128
|
});
|
|
136
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
|
+
}
|
|
137
166
|
async generate() {
|
|
138
|
-
const
|
|
167
|
+
const definition = {};
|
|
168
|
+
const typesByPattern = {};
|
|
139
169
|
const sourcesFiles = this.#project.getSourceFiles();
|
|
140
170
|
const routes = this.#filterRoutesToGenerate(this.#routes);
|
|
141
171
|
for (const route of routes) {
|
|
@@ -158,25 +188,30 @@ var ApiTypesGenerator = class {
|
|
|
158
188
|
const schemaImport = this.#extractRequest(handlerData);
|
|
159
189
|
const methods = route.methods.map((method) => "$" + method.toLowerCase()).filter((method) => method !== "head");
|
|
160
190
|
const segments = route.pattern.split("/").filter(Boolean);
|
|
161
|
-
let currentLevel =
|
|
191
|
+
let currentLevel = definition;
|
|
162
192
|
const relativePath = relative(this.#getDestinationDirectory(), file.getFilePath());
|
|
163
193
|
segments.forEach((segment, i) => {
|
|
164
|
-
if (!currentLevel[segment])
|
|
194
|
+
if (!currentLevel[segment])
|
|
165
195
|
currentLevel[segment] = {};
|
|
166
|
-
}
|
|
167
196
|
currentLevel = currentLevel[segment];
|
|
168
|
-
if (i
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
197
|
+
if (i !== segments.length - 1)
|
|
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
|
+
};
|
|
204
|
+
currentLevel.$url = {};
|
|
205
|
+
for (const method of methods) {
|
|
206
|
+
currentLevel[method] = `${string.pascalCase(typeName)}`;
|
|
176
207
|
}
|
|
177
208
|
});
|
|
178
209
|
}
|
|
179
|
-
await this.#
|
|
210
|
+
await this.#writeApiFile({
|
|
211
|
+
definition,
|
|
212
|
+
typesByPattern,
|
|
213
|
+
routesNameArray: this.#generateRoutesNameArray(routes)
|
|
214
|
+
});
|
|
180
215
|
}
|
|
181
216
|
};
|
|
182
217
|
|
|
@@ -212,6 +247,9 @@ var CodegenTypes = class extends BaseCommand {
|
|
|
212
247
|
this.logger.success("Types generated successfully");
|
|
213
248
|
}
|
|
214
249
|
};
|
|
250
|
+
__decorateClass([
|
|
251
|
+
flags.boolean({ description: "Verbose logs", default: false, alias: "v" })
|
|
252
|
+
], CodegenTypes.prototype, "verbose", 2);
|
|
215
253
|
export {
|
|
216
254
|
CodegenTypes as default
|
|
217
255
|
};
|
package/build/index.js
CHANGED
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",
|
|
@@ -18,20 +18,6 @@
|
|
|
18
18
|
"engines": {
|
|
19
19
|
"node": ">=20.6.0"
|
|
20
20
|
},
|
|
21
|
-
"scripts": {
|
|
22
|
-
"clean": "del-cli build",
|
|
23
|
-
"copy:templates": "copyfiles \"stubs/**/*.stub\" build",
|
|
24
|
-
"typecheck": "tsc --noEmit",
|
|
25
|
-
"format": "prettier --write .",
|
|
26
|
-
"quick:test": "node --import=./tsnode.esm.js --enable-source-maps bin/test.ts",
|
|
27
|
-
"test": "c8 npm run quick:test",
|
|
28
|
-
"index:commands": "adonis-kit index build/commands",
|
|
29
|
-
"prebuild": "npm run clean",
|
|
30
|
-
"build": "pnpm clean && tsup-node && pnpm copy:templates && pnpm index:commands",
|
|
31
|
-
"release": "pnpm build && pnpm release-it",
|
|
32
|
-
"version": "npm run build",
|
|
33
|
-
"prepublishOnly": "npm run build"
|
|
34
|
-
},
|
|
35
21
|
"peerDependencies": {
|
|
36
22
|
"@adonisjs/core": "^6.2.0"
|
|
37
23
|
},
|
|
@@ -39,14 +25,14 @@
|
|
|
39
25
|
"ts-morph": "^22.0.0"
|
|
40
26
|
},
|
|
41
27
|
"devDependencies": {
|
|
42
|
-
"@adonisjs/assembler": "^7.
|
|
43
|
-
"@adonisjs/core": "^6.
|
|
28
|
+
"@adonisjs/assembler": "^7.5.1",
|
|
29
|
+
"@adonisjs/core": "^6.8.0",
|
|
44
30
|
"@julr/tooling-configs": "^2.2.0",
|
|
45
31
|
"@poppinss/cliui": "^6.4.1",
|
|
46
32
|
"@poppinss/matchit": "^3.1.2",
|
|
47
|
-
"@
|
|
48
|
-
"@tuyau/utils": "
|
|
49
|
-
"@
|
|
33
|
+
"@types/node": "^20.12.7",
|
|
34
|
+
"@tuyau/utils": "0.0.4",
|
|
35
|
+
"@tuyau/client": "0.1.0"
|
|
50
36
|
},
|
|
51
37
|
"publishConfig": {
|
|
52
38
|
"access": "public",
|
|
@@ -61,18 +47,6 @@
|
|
|
61
47
|
"tests/**"
|
|
62
48
|
]
|
|
63
49
|
},
|
|
64
|
-
"release-it": {
|
|
65
|
-
"git": {
|
|
66
|
-
"commitMessage": "chore(release): @tuyau/core@${version}",
|
|
67
|
-
"tagAnnotation": "release ${version}",
|
|
68
|
-
"tagName": "@tuyau/core@${version}"
|
|
69
|
-
},
|
|
70
|
-
"github": {
|
|
71
|
-
"release": true,
|
|
72
|
-
"releaseName": "@tuyau/core@${version}",
|
|
73
|
-
"web": true
|
|
74
|
-
}
|
|
75
|
-
},
|
|
76
50
|
"tsup": {
|
|
77
51
|
"entry": [
|
|
78
52
|
"./index.ts",
|
|
@@ -85,5 +59,17 @@
|
|
|
85
59
|
"format": "esm",
|
|
86
60
|
"dts": true,
|
|
87
61
|
"target": "esnext"
|
|
62
|
+
},
|
|
63
|
+
"scripts": {
|
|
64
|
+
"clean": "del-cli build",
|
|
65
|
+
"copy:templates": "copyfiles \"stubs/**/*.stub\" build",
|
|
66
|
+
"typecheck": "tsc --noEmit",
|
|
67
|
+
"format": "prettier --write .",
|
|
68
|
+
"quick:test": "node --import=./tsnode.esm.js --enable-source-maps bin/test.ts",
|
|
69
|
+
"test": "c8 npm run quick:test",
|
|
70
|
+
"index:commands": "adonis-kit index build/commands",
|
|
71
|
+
"prebuild": "npm run clean",
|
|
72
|
+
"build": "pnpm clean && tsup-node && pnpm copy:templates && pnpm index:commands",
|
|
73
|
+
"version": "npm run build"
|
|
88
74
|
}
|
|
89
|
-
}
|
|
75
|
+
}
|