@ubean/codegen 0.1.2 → 0.1.3
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/index.d.ts +54 -0
- package/dist/index.js +176 -0
- package/package.json +3 -3
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { AutoImportOptions } from "@ubean/auto-imports";
|
|
2
|
+
import { ScanResult } from "@ubean/routing";
|
|
3
|
+
//#region src/route-types.d.ts
|
|
4
|
+
interface RouteTypesOptions {
|
|
5
|
+
outDir: string;
|
|
6
|
+
fileName?: string;
|
|
7
|
+
}
|
|
8
|
+
declare function generateRouteTypes(result: ScanResult, options: RouteTypesOptions): Promise<string>;
|
|
9
|
+
interface PageTypesOptions {
|
|
10
|
+
outDir: string;
|
|
11
|
+
fileName?: string;
|
|
12
|
+
}
|
|
13
|
+
declare function generatePageTypes(result: ScanResult, options: PageTypesOptions): Promise<string>;
|
|
14
|
+
//#endregion
|
|
15
|
+
//#region src/openapi-types.d.ts
|
|
16
|
+
/**
|
|
17
|
+
* OpenAPI 类型生成
|
|
18
|
+
*
|
|
19
|
+
* 从 OpenAPI schema 生成 `paths` 类型声明文件(.ubean/openapi.d.ts),
|
|
20
|
+
* 供 `createTypedClient<paths>` / `createTypedFlatClient<paths>` / `callTypedInternal<paths>` 消费。
|
|
21
|
+
*
|
|
22
|
+
* 底层使用 `openapi-typescript` 编译 schema 为 TypeScript 类型声明。
|
|
23
|
+
*/
|
|
24
|
+
interface GenerateOpenApiTypesOptions {
|
|
25
|
+
/** 输出目录(如 .ubean) */
|
|
26
|
+
outDir: string;
|
|
27
|
+
/** 输出文件名,默认 `openapi.d.ts` */
|
|
28
|
+
fileName?: string;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* 从 OpenAPI schema 对象生成 paths 类型声明文件。
|
|
32
|
+
*/
|
|
33
|
+
declare function generateOpenApiTypes(schema: unknown, options: GenerateOpenApiTypesOptions): Promise<string>;
|
|
34
|
+
/**
|
|
35
|
+
* 从 dev server 的 `/_openapi.json` 路由获取 schema 并生成类型声明文件。
|
|
36
|
+
*/
|
|
37
|
+
declare function generateOpenApiTypesFromServer(baseUrl: string, options: GenerateOpenApiTypesOptions): Promise<string>;
|
|
38
|
+
//#endregion
|
|
39
|
+
//#region src/index.d.ts
|
|
40
|
+
interface CodegenOptions extends Omit<AutoImportOptions, 'cwd' | 'srcDir' | 'buildDir'> {
|
|
41
|
+
cwd: string;
|
|
42
|
+
srcDir: string;
|
|
43
|
+
buildDir: string;
|
|
44
|
+
}
|
|
45
|
+
interface CodegenResult {
|
|
46
|
+
routeTypesPath: string;
|
|
47
|
+
pageTypesPath: string;
|
|
48
|
+
autoImportsDtsPath?: string;
|
|
49
|
+
componentsDtsPath?: string;
|
|
50
|
+
generated: string[];
|
|
51
|
+
}
|
|
52
|
+
declare function generateTypes(result: ScanResult, options: CodegenOptions): Promise<CodegenResult>;
|
|
53
|
+
//#endregion
|
|
54
|
+
export { CodegenOptions, CodegenResult, type GenerateOpenApiTypesOptions, type PageTypesOptions, type RouteTypesOptions, generateOpenApiTypes, generateOpenApiTypesFromServer, generatePageTypes, generateRouteTypes, generateTypes };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
2
|
+
import { generateAutoImports } from "@ubean/auto-imports";
|
|
3
|
+
import { join } from "pathe";
|
|
4
|
+
import openapiTS, { astToString } from "openapi-typescript";
|
|
5
|
+
//#region src/route-types.ts
|
|
6
|
+
async function generateRouteTypes(result, options) {
|
|
7
|
+
const { outDir, fileName = "routes.d.ts" } = options;
|
|
8
|
+
await mkdir(outDir, { recursive: true });
|
|
9
|
+
const apiRoutes = result.apiRoutes;
|
|
10
|
+
const lines = [
|
|
11
|
+
"// Auto-generated by ubean - do not edit manually",
|
|
12
|
+
"/* eslint-disable */",
|
|
13
|
+
"// @ts-nocheck",
|
|
14
|
+
"",
|
|
15
|
+
"declare module \"ubean:routes\" {",
|
|
16
|
+
" export interface ApiRoute {",
|
|
17
|
+
" method: string;",
|
|
18
|
+
" path: string;",
|
|
19
|
+
" filePath: string;",
|
|
20
|
+
" meta?: Record<string, unknown>;",
|
|
21
|
+
" }",
|
|
22
|
+
""
|
|
23
|
+
];
|
|
24
|
+
const routeEntries = apiRoutes.map((r) => ` "${r.method?.toUpperCase() || "ALL"} ${r.route}": { filePath: ${JSON.stringify(r.fullPath)} }`);
|
|
25
|
+
if (routeEntries.length > 0) {
|
|
26
|
+
lines.push(" export type ApiRouteMap = {");
|
|
27
|
+
lines.push(routeEntries.join(";\n"));
|
|
28
|
+
lines.push(" };");
|
|
29
|
+
} else lines.push(" export type ApiRouteMap = {};");
|
|
30
|
+
lines.push("");
|
|
31
|
+
const routePaths = [...new Set(apiRoutes.map((r) => r.route))].sort();
|
|
32
|
+
if (routePaths.length > 0) {
|
|
33
|
+
lines.push(" export type ApiRoutePath =");
|
|
34
|
+
lines.push(routePaths.map((p) => ` | ${JSON.stringify(p)}`).join("\n"));
|
|
35
|
+
lines.push(" ;");
|
|
36
|
+
} else lines.push(" export type ApiRoutePath = string;");
|
|
37
|
+
lines.push("");
|
|
38
|
+
const routeMethods = [...new Set(apiRoutes.map((r) => r.method?.toUpperCase()).filter(Boolean))].sort();
|
|
39
|
+
if (routeMethods.length > 0) {
|
|
40
|
+
lines.push(" export type ApiMethod =");
|
|
41
|
+
lines.push(routeMethods.map((m) => ` | ${JSON.stringify(m)}`).join("\n"));
|
|
42
|
+
lines.push(" ;");
|
|
43
|
+
} else lines.push(" export type ApiMethod = \"GET\" | \"POST\" | \"PUT\" | \"PATCH\" | \"DELETE\" | \"OPTIONS\" | \"HEAD\";");
|
|
44
|
+
lines.push("");
|
|
45
|
+
lines.push(" export const routes: ApiRoute[];");
|
|
46
|
+
lines.push(" export const middlewares: { filePath: string; order: number; global: boolean }[];");
|
|
47
|
+
lines.push("}");
|
|
48
|
+
const content = `${lines.join("\n")}\n`;
|
|
49
|
+
const filePath = join(outDir, fileName);
|
|
50
|
+
await writeFile(filePath, content, "utf-8");
|
|
51
|
+
return filePath;
|
|
52
|
+
}
|
|
53
|
+
async function generatePageTypes(result, options) {
|
|
54
|
+
const { outDir, fileName = "pages.d.ts" } = options;
|
|
55
|
+
await mkdir(outDir, { recursive: true });
|
|
56
|
+
const pages = result.pages;
|
|
57
|
+
const layouts = result.layouts;
|
|
58
|
+
const lines = [
|
|
59
|
+
"// Auto-generated by ubean - do not edit manually",
|
|
60
|
+
"/* eslint-disable */",
|
|
61
|
+
"// @ts-nocheck",
|
|
62
|
+
"",
|
|
63
|
+
"declare module \"ubean:pages\" {",
|
|
64
|
+
" export interface PageInfo {",
|
|
65
|
+
" name: string;",
|
|
66
|
+
" path: string;",
|
|
67
|
+
" filePath: string;",
|
|
68
|
+
" layout?: string;",
|
|
69
|
+
" reuseTarget?: string;",
|
|
70
|
+
" }",
|
|
71
|
+
"",
|
|
72
|
+
" export interface LayoutInfo {",
|
|
73
|
+
" name: string;",
|
|
74
|
+
" filePath: string;",
|
|
75
|
+
" isDefault: boolean;",
|
|
76
|
+
" }",
|
|
77
|
+
""
|
|
78
|
+
];
|
|
79
|
+
const pageNames = pages.map((p) => JSON.stringify(p.name));
|
|
80
|
+
if (pageNames.length > 0) {
|
|
81
|
+
lines.push(" export type RouteName =");
|
|
82
|
+
lines.push(pageNames.map((n) => ` | ${n}`).join("\n"));
|
|
83
|
+
lines.push(" ;");
|
|
84
|
+
} else lines.push(" export type RouteName = string;");
|
|
85
|
+
lines.push("");
|
|
86
|
+
const layoutNames = layouts.map((l) => JSON.stringify(l.name));
|
|
87
|
+
if (layoutNames.length > 0) {
|
|
88
|
+
lines.push(" export type LayoutName =");
|
|
89
|
+
lines.push(layoutNames.map((n) => ` | ${n}`).join("\n"));
|
|
90
|
+
lines.push(" ;");
|
|
91
|
+
} else lines.push(" export type LayoutName = string;");
|
|
92
|
+
lines.push("");
|
|
93
|
+
const pageEntries = pages.map((p) => ` ${JSON.stringify(p.name)}: { name: ${JSON.stringify(p.name)}, path: ${JSON.stringify(p.path)}, filePath: ${JSON.stringify(p.fullPath)}, layout: ${JSON.stringify(p.layout)}, reuseTarget: ${JSON.stringify(p.reuseTarget)} }`);
|
|
94
|
+
if (pageEntries.length > 0) {
|
|
95
|
+
lines.push(" export const pages: {");
|
|
96
|
+
lines.push(pageEntries.join(",\n"));
|
|
97
|
+
lines.push(" };");
|
|
98
|
+
} else lines.push(" export const pages: Record<string, PageInfo>;");
|
|
99
|
+
lines.push("");
|
|
100
|
+
const layoutEntries = layouts.map((l) => ` ${JSON.stringify(l.name)}: { name: ${JSON.stringify(l.name)}, filePath: ${JSON.stringify(l.fullPath)}, isDefault: ${l.isDefault} }`);
|
|
101
|
+
if (layoutEntries.length > 0) {
|
|
102
|
+
lines.push(" export const layouts: {");
|
|
103
|
+
lines.push(layoutEntries.join(",\n"));
|
|
104
|
+
lines.push(" };");
|
|
105
|
+
} else lines.push(" export const layouts: Record<string, LayoutInfo>;");
|
|
106
|
+
lines.push("}");
|
|
107
|
+
const content = `${lines.join("\n")}\n`;
|
|
108
|
+
const filePath = join(outDir, fileName);
|
|
109
|
+
await writeFile(filePath, content, "utf-8");
|
|
110
|
+
return filePath;
|
|
111
|
+
}
|
|
112
|
+
//#endregion
|
|
113
|
+
//#region src/openapi-types.ts
|
|
114
|
+
/**
|
|
115
|
+
* OpenAPI 类型生成
|
|
116
|
+
*
|
|
117
|
+
* 从 OpenAPI schema 生成 `paths` 类型声明文件(.ubean/openapi.d.ts),
|
|
118
|
+
* 供 `createTypedClient<paths>` / `createTypedFlatClient<paths>` / `callTypedInternal<paths>` 消费。
|
|
119
|
+
*
|
|
120
|
+
* 底层使用 `openapi-typescript` 编译 schema 为 TypeScript 类型声明。
|
|
121
|
+
*/
|
|
122
|
+
/**
|
|
123
|
+
* 从 OpenAPI schema 对象生成 paths 类型声明文件。
|
|
124
|
+
*/
|
|
125
|
+
async function generateOpenApiTypes(schema, options) {
|
|
126
|
+
const { outDir, fileName = "openapi.d.ts" } = options;
|
|
127
|
+
await mkdir(outDir, { recursive: true });
|
|
128
|
+
const typesContent = astToString(await openapiTS(schema));
|
|
129
|
+
const content = `${[
|
|
130
|
+
"// Auto-generated by ubean - do not edit manually",
|
|
131
|
+
"/* eslint-disable */",
|
|
132
|
+
"/* @ts-nocheck */",
|
|
133
|
+
"",
|
|
134
|
+
""
|
|
135
|
+
].join("\n") + typesContent}\n`;
|
|
136
|
+
const filePath = join(outDir, fileName);
|
|
137
|
+
await writeFile(filePath, content, "utf-8");
|
|
138
|
+
return filePath;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* 从 dev server 的 `/_openapi.json` 路由获取 schema 并生成类型声明文件。
|
|
142
|
+
*/
|
|
143
|
+
async function generateOpenApiTypesFromServer(baseUrl, options) {
|
|
144
|
+
const url = `${baseUrl.replace(/\/$/, "")}/_openapi.json`;
|
|
145
|
+
const response = await fetch(url);
|
|
146
|
+
if (!response.ok) throw new Error(`[openapi-types] Failed to fetch OpenAPI schema from ${url}: ${response.status} ${response.statusText}`);
|
|
147
|
+
return generateOpenApiTypes(await response.json(), options);
|
|
148
|
+
}
|
|
149
|
+
//#endregion
|
|
150
|
+
//#region src/index.ts
|
|
151
|
+
async function generateTypes(result, options) {
|
|
152
|
+
const { cwd, srcDir, buildDir, ...autoImportOptions } = options;
|
|
153
|
+
const outDir = join(cwd, buildDir);
|
|
154
|
+
await mkdir(outDir, { recursive: true });
|
|
155
|
+
const generated = [];
|
|
156
|
+
const routeTypesPath = await generateRouteTypes(result, { outDir });
|
|
157
|
+
generated.push(routeTypesPath);
|
|
158
|
+
const pageTypesPath = await generatePageTypes(result, { outDir });
|
|
159
|
+
generated.push(pageTypesPath);
|
|
160
|
+
const { autoImportsDtsPath, componentsDtsPath } = await generateAutoImports(result, {
|
|
161
|
+
cwd,
|
|
162
|
+
srcDir,
|
|
163
|
+
buildDir,
|
|
164
|
+
...autoImportOptions
|
|
165
|
+
});
|
|
166
|
+
generated.push(autoImportsDtsPath, componentsDtsPath);
|
|
167
|
+
return {
|
|
168
|
+
routeTypesPath,
|
|
169
|
+
pageTypesPath,
|
|
170
|
+
autoImportsDtsPath,
|
|
171
|
+
componentsDtsPath,
|
|
172
|
+
generated
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
//#endregion
|
|
176
|
+
export { generateOpenApiTypes, generateOpenApiTypesFromServer, generatePageTypes, generateRouteTypes, generateTypes };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ubean/codegen",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "Type generation for ubean (generateTypes, routes.d.ts, pages.d.ts, openapi.d.ts)",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist"
|
|
@@ -18,8 +18,8 @@
|
|
|
18
18
|
"dependencies": {
|
|
19
19
|
"openapi-typescript": "^7.13.0",
|
|
20
20
|
"pathe": "^2.0.3",
|
|
21
|
-
"@ubean/
|
|
22
|
-
"@ubean/
|
|
21
|
+
"@ubean/auto-imports": "0.1.3",
|
|
22
|
+
"@ubean/routing": "0.1.3"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"@types/node": "^26.1.1",
|