@genapi/pipeline 3.7.1 → 4.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 +60 -0
- package/dist/index.d.mts +69 -26
- package/dist/index.mjs +206 -95
- package/package.json +20 -17
package/README.md
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# @genapi/pipeline
|
|
2
|
+
|
|
3
|
+
<!-- automd:badges -->
|
|
4
|
+
|
|
5
|
+
[](https://npmjs.com/package/@genapi/pipeline)
|
|
6
|
+
[](https://npm.chart.dev/@genapi/pipeline)
|
|
7
|
+
|
|
8
|
+
<!-- /automd -->
|
|
9
|
+
|
|
10
|
+
GenAPI pipeline core: config reading, data source fetching, parsing, compilation, generation, and output. Composable for custom generation flows.
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
pnpm add @genapi/pipeline
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## API
|
|
19
|
+
|
|
20
|
+
<!-- automd:jsdocs src=src/index.ts -->
|
|
21
|
+
|
|
22
|
+
## Pipeline
|
|
23
|
+
|
|
24
|
+
### `compiler(configRead)`
|
|
25
|
+
|
|
26
|
+
Compiles graphs to AST: request code and typings for each output.
|
|
27
|
+
|
|
28
|
+
### `config(userConfig)`
|
|
29
|
+
|
|
30
|
+
Normalizes pipeline config: output paths, responseType, baseURL (from meta), and builds ConfigRead with inputs/outputs.
|
|
31
|
+
|
|
32
|
+
### `default(config, original, parser, compiler, generate, dest)`
|
|
33
|
+
|
|
34
|
+
Builds a GenAPI pipeline from five steps: config → original → parser → compiler → generate → dest.
|
|
35
|
+
|
|
36
|
+
### `dest(configRead)`
|
|
37
|
+
|
|
38
|
+
Writes output files from configRead.outputs (code to path).
|
|
39
|
+
|
|
40
|
+
### `generate(configRead)`
|
|
41
|
+
|
|
42
|
+
Generates code string from AST for each output and formats with Prettier.
|
|
43
|
+
|
|
44
|
+
### `original(configRead)`
|
|
45
|
+
|
|
46
|
+
Fetches source: resolves uri/http/json from configRead.inputs and sets configRead.source.
|
|
47
|
+
|
|
48
|
+
<!-- /automd -->
|
|
49
|
+
|
|
50
|
+
## License
|
|
51
|
+
|
|
52
|
+
[MIT](https://github.com/hairyf/genapi/blob/main/LICENSE)
|
|
53
|
+
|
|
54
|
+
<!-- automd:with-automd -->
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
_🤖 auto updated with [automd](https://automd.unjs.io)_
|
|
59
|
+
|
|
60
|
+
<!-- /automd -->
|
package/dist/index.d.mts
CHANGED
|
@@ -2,55 +2,98 @@ import { ApiPipeline } from "@genapi/shared";
|
|
|
2
2
|
|
|
3
3
|
//#region src/pipeline/index.d.ts
|
|
4
4
|
/**
|
|
5
|
-
* Pipeline read
|
|
5
|
+
* Pipeline read (input) step: turns raw config into internal config + inputs.
|
|
6
6
|
*/
|
|
7
7
|
type PipelineRead<Config, ConfigRead> = (config: Config) => ConfigRead | Promise<ConfigRead>;
|
|
8
8
|
/**
|
|
9
|
-
*
|
|
9
|
+
* Middle step that receives and returns config read; used for original, parser, compiler, generate.
|
|
10
10
|
*/
|
|
11
11
|
type PipelineFlow<ConfigRead> = (configRead: ConfigRead) => ConfigRead | Promise<ConfigRead>;
|
|
12
12
|
/**
|
|
13
|
-
* Pipeline dest
|
|
13
|
+
* Pipeline dest (output) step: writes files from config read.
|
|
14
14
|
*/
|
|
15
|
-
type PipelineDest<ConfigRead> = (configRead: ApiPipeline.ConfigRead) => void
|
|
15
|
+
type PipelineDest<ConfigRead> = (configRead: ApiPipeline.ConfigRead) => void | Promise<void>;
|
|
16
16
|
/**
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* @param
|
|
20
|
-
* @param
|
|
21
|
-
* @param
|
|
22
|
-
* @param
|
|
23
|
-
* @param
|
|
17
|
+
* Builds a GenAPI pipeline from five steps: config → original → parser → compiler → generate → dest.
|
|
18
|
+
*
|
|
19
|
+
* @param config - Reads config and returns ConfigRead
|
|
20
|
+
* @param original - Fetches source (e.g. OpenAPI JSON)
|
|
21
|
+
* @param parser - Parses source into graphs
|
|
22
|
+
* @param compiler - Compiles graphs to AST
|
|
23
|
+
* @param generate - Generates code string
|
|
24
|
+
* @param dest - Writes output files
|
|
25
|
+
* @returns A function that runs the pipeline for a given config
|
|
26
|
+
* @group Pipeline
|
|
24
27
|
*/
|
|
25
28
|
declare function pipeline<Config = ApiPipeline.Config, ConfigRead = ApiPipeline.ConfigRead>(config: PipelineRead<Config, ConfigRead>, original: PipelineFlow<ConfigRead>, parser: PipelineFlow<ConfigRead>, compiler: PipelineFlow<ConfigRead>, generate: PipelineFlow<ConfigRead>, dest: PipelineDest<ConfigRead>): ApiPipeline.Pipeline;
|
|
26
29
|
declare namespace pipeline {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
var config: typeof config;
|
|
31
|
+
var original: typeof original;
|
|
32
|
+
var parser: typeof original;
|
|
33
|
+
var compiler: typeof compiler;
|
|
34
|
+
var generate: typeof generate;
|
|
35
|
+
var dest: typeof dest;
|
|
33
36
|
}
|
|
34
|
-
|
|
37
|
+
//#endregion
|
|
38
|
+
//#region src/compiler/request.d.ts
|
|
39
|
+
declare function compilerTsRequestDeclaration(configRead: ApiPipeline.ConfigRead): string;
|
|
40
|
+
//#endregion
|
|
41
|
+
//#region src/compiler/typings.d.ts
|
|
42
|
+
/**
|
|
43
|
+
* Compiles configRead graphs to typings code string using knitwork-x.
|
|
44
|
+
*/
|
|
45
|
+
declare function compilerTsTypingsDeclaration(configRead: ApiPipeline.ConfigRead, comment?: boolean): string;
|
|
35
46
|
//#endregion
|
|
36
47
|
//#region src/compiler/index.d.ts
|
|
48
|
+
/**
|
|
49
|
+
* Compiles graphs to code string: request and typings for each output.
|
|
50
|
+
*
|
|
51
|
+
* @param configRead - ConfigRead with graphs and outputs
|
|
52
|
+
* @returns Same configRead with output.code set
|
|
53
|
+
* @group Pipeline
|
|
54
|
+
*/
|
|
37
55
|
declare function compiler(configRead: ApiPipeline.ConfigRead): ApiPipeline.ConfigRead<ApiPipeline.Config>;
|
|
38
|
-
|
|
39
56
|
//#endregion
|
|
40
57
|
//#region src/config/index.d.ts
|
|
58
|
+
/**
|
|
59
|
+
* Normalizes pipeline config: output paths, responseType, baseURL, and builds ConfigRead with inputs/outputs.
|
|
60
|
+
*
|
|
61
|
+
* @param userConfig - Raw config from defineConfig
|
|
62
|
+
* @returns ConfigRead (config + inputs + outputs)
|
|
63
|
+
* @group Pipeline
|
|
64
|
+
*/
|
|
41
65
|
declare function config(userConfig: ApiPipeline.Config): ApiPipeline.ConfigRead<Required<ApiPipeline.Config>>;
|
|
42
|
-
|
|
43
66
|
//#endregion
|
|
44
67
|
//#region src/dest/index.d.ts
|
|
45
|
-
|
|
46
|
-
|
|
68
|
+
/**
|
|
69
|
+
* Writes output files from configRead.outputs (code to path).
|
|
70
|
+
*
|
|
71
|
+
* @param configRead - ConfigRead with outputs[].path and outputs[].code
|
|
72
|
+
* @group Pipeline
|
|
73
|
+
*/
|
|
74
|
+
declare function dest(configRead: ApiPipeline.ConfigRead): Promise<void>;
|
|
47
75
|
//#endregion
|
|
48
76
|
//#region src/generate/index.d.ts
|
|
49
|
-
|
|
50
|
-
|
|
77
|
+
/**
|
|
78
|
+
* Formats code for each output with Prettier.
|
|
79
|
+
*
|
|
80
|
+
* @param configRead - ConfigRead with outputs[].code
|
|
81
|
+
* @returns Same configRead with outputs[].code formatted
|
|
82
|
+
* @group Pipeline
|
|
83
|
+
*/
|
|
84
|
+
declare function generate(configRead: ApiPipeline.ConfigRead, options?: any): Promise<ApiPipeline.ConfigRead<ApiPipeline.Config>>;
|
|
85
|
+
declare function formatTypescript(code: string, options?: any): Promise<string>;
|
|
51
86
|
//#endregion
|
|
52
87
|
//#region src/original/index.d.ts
|
|
88
|
+
/**
|
|
89
|
+
* Fetches source: resolves uri/http/json from configRead.inputs and sets configRead.source.
|
|
90
|
+
* Transforms the source based on parser configuration (wpapi -> swagger2, swagger -> unchanged).
|
|
91
|
+
* Supports YAML source URLs (e.g. .yaml / .yml); uses confbox for parsing (same as undocs).
|
|
92
|
+
*
|
|
93
|
+
* @param configRead - ConfigRead with inputs (uri, http, or json)
|
|
94
|
+
* @returns Same configRead with source set and transformed if needed
|
|
95
|
+
* @group Pipeline
|
|
96
|
+
*/
|
|
53
97
|
declare function original(configRead: ApiPipeline.ConfigRead): Promise<ApiPipeline.ConfigRead<ApiPipeline.Config>>;
|
|
54
|
-
|
|
55
98
|
//#endregion
|
|
56
|
-
export { PipelineDest, PipelineFlow, PipelineRead, compiler, config, pipeline as default, dest, generate, original };
|
|
99
|
+
export { type PipelineDest, type PipelineFlow, type PipelineRead, compiler, compilerTsRequestDeclaration, compilerTsTypingsDeclaration, config, pipeline as default, dest, formatTypescript, generate, original };
|
package/dist/index.mjs
CHANGED
|
@@ -1,114 +1,177 @@
|
|
|
1
1
|
import pPipe from "p-pipe";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { inject, provide } from "@genapi/shared";
|
|
3
|
+
import { genComment, genFunction, genImport, genInterface, genTypeAlias, genVariable } from "knitwork-x";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import process from "node:process";
|
|
6
|
-
import { provide } from "@genapi/shared";
|
|
7
6
|
import fs from "fs-extra";
|
|
8
7
|
import { format } from "prettier";
|
|
9
|
-
import
|
|
8
|
+
import { wpapiToSwagger2 } from "@genapi/transform";
|
|
9
|
+
import { parseYAML } from "confbox";
|
|
10
|
+
import { ofetch } from "ofetch";
|
|
10
11
|
|
|
11
12
|
//#region src/compiler/typings.ts
|
|
13
|
+
/**
|
|
14
|
+
* Compiles configRead graphs to typings code string using knitwork-x.
|
|
15
|
+
*/
|
|
12
16
|
function compilerTsTypingsDeclaration(configRead, comment = true) {
|
|
13
17
|
configRead.graphs.comments = configRead.graphs.comments || [];
|
|
14
18
|
configRead.graphs.typings = configRead.graphs.typings || [];
|
|
15
19
|
configRead.graphs.interfaces = configRead.graphs.interfaces || [];
|
|
20
|
+
const sections = [];
|
|
21
|
+
if (comment && configRead.graphs.comments.length > 0) sections.push(genComment(configRead.graphs.comments.join("\n"), { block: true }));
|
|
16
22
|
const typings = configRead.graphs.typings.map((item) => {
|
|
17
|
-
return
|
|
23
|
+
return genTypeAlias(item.name, item.value, { export: !!item.export });
|
|
18
24
|
});
|
|
25
|
+
if (typings.length > 0) sections.push(typings.join("\n"));
|
|
19
26
|
const interfaces = configRead.graphs.interfaces.map((item) => {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
27
|
+
const properties = (item.properties || []).map((p) => ({
|
|
28
|
+
name: p.name,
|
|
29
|
+
type: p.type ?? "any",
|
|
30
|
+
optional: !p.required,
|
|
31
|
+
jsdoc: p.description
|
|
32
|
+
}));
|
|
33
|
+
return genInterface(item.name, properties, { export: !!item.export });
|
|
25
34
|
});
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
...typings,
|
|
29
|
-
factory.createIdentifier(""),
|
|
30
|
-
...interfaces
|
|
31
|
-
];
|
|
32
|
-
if (comment) nodes.unshift(createComment("multi", configRead.graphs.comments));
|
|
33
|
-
return nodes;
|
|
35
|
+
if (interfaces.length > 0) sections.push(interfaces.join("\n"));
|
|
36
|
+
return sections.filter(Boolean).join("\n\n");
|
|
34
37
|
}
|
|
35
38
|
|
|
36
39
|
//#endregion
|
|
37
40
|
//#region src/compiler/request.ts
|
|
38
|
-
const varFlags = {
|
|
39
|
-
let: NodeFlags.Let,
|
|
40
|
-
const: NodeFlags.Const,
|
|
41
|
-
var: NodeFlags.None
|
|
42
|
-
};
|
|
43
41
|
function compilerTsRequestDeclaration(configRead) {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
42
|
+
const { graphs, config, outputs } = configRead;
|
|
43
|
+
const sections = [];
|
|
44
|
+
const interfaceMap = new Map((graphs.interfaces || []).map((i) => [i.name, i]));
|
|
45
|
+
if (graphs.comments?.length) sections.push(genComment(graphs.comments.join("\n"), { block: true }));
|
|
46
|
+
const importLines = (graphs.imports || []).map((item) => {
|
|
47
|
+
const isType = !!item.type;
|
|
48
|
+
if (item.namespace) return genImport(item.value, {
|
|
49
|
+
name: "*",
|
|
50
|
+
as: item.name
|
|
51
|
+
}, { type: isType });
|
|
52
|
+
if (item.name && !item.names) return genImport(item.value, item.name, { type: isType });
|
|
53
|
+
const names = item.names || [];
|
|
54
|
+
const imports = item.name ? [{
|
|
55
|
+
name: "default",
|
|
56
|
+
as: item.name
|
|
57
|
+
}, ...names.map((n) => ({ name: n }))] : names;
|
|
58
|
+
return genImport(item.value, imports, { type: isType });
|
|
53
59
|
});
|
|
54
|
-
|
|
55
|
-
|
|
60
|
+
if (config.meta?.mockjs) importLines.push(genImport("better-mock", { name: "Mock" }));
|
|
61
|
+
if (importLines.length) sections.push(importLines.join("\n"));
|
|
62
|
+
const variables = (graphs.variables || []).map((item) => genVariable(item.name, item.value ?? "", {
|
|
63
|
+
export: !!item.export,
|
|
64
|
+
kind: item.flag
|
|
65
|
+
}));
|
|
66
|
+
if (variables.length) sections.push(variables.join("\n"));
|
|
67
|
+
const functions = genFunctionsWithMock(graphs.functions || [], interfaceMap, config);
|
|
68
|
+
if (functions.length) sections.push(functions.join("\n\n"));
|
|
69
|
+
const isGenerateType = outputs.some((v) => v.type === "typings");
|
|
70
|
+
const isTsRequest = outputs.some((v) => v.type === "request" && v.path.endsWith(".ts"));
|
|
71
|
+
if (!isGenerateType && isTsRequest) sections.push(compilerTsTypingsDeclaration(configRead, false));
|
|
72
|
+
return sections.filter(Boolean).join("\n\n");
|
|
73
|
+
}
|
|
74
|
+
const RE_NAMESPACE = /^(Types\.|import\(['"][^'"]+['"]\)\.)/g;
|
|
75
|
+
const RE_ARRAY_TYPE = /^(.+)\[\]$/;
|
|
76
|
+
/**
|
|
77
|
+
* 优化后的 Mock 模板生成函数
|
|
78
|
+
*/
|
|
79
|
+
function generateMockTemplate(typeName, interfaceMap, visited = /* @__PURE__ */ new Set()) {
|
|
80
|
+
const cleanTypeName = typeName.replace(RE_NAMESPACE, "").trim();
|
|
81
|
+
const arrayMatch = cleanTypeName.match(RE_ARRAY_TYPE);
|
|
82
|
+
if (arrayMatch) return `[${generateMockTemplate(arrayMatch[1], interfaceMap, visited)}]`;
|
|
83
|
+
const primitiveMap = {
|
|
84
|
+
string: "'@string'",
|
|
85
|
+
number: "'@integer'",
|
|
86
|
+
boolean: "'@boolean'",
|
|
87
|
+
Date: "'@datetime'",
|
|
88
|
+
void: "null",
|
|
89
|
+
any: "'@string'"
|
|
90
|
+
};
|
|
91
|
+
if (primitiveMap[cleanTypeName]) return primitiveMap[cleanTypeName];
|
|
92
|
+
if (cleanTypeName.includes("|")) return "{}";
|
|
93
|
+
const interfaceDef = interfaceMap.get(cleanTypeName);
|
|
94
|
+
if (!interfaceDef?.properties || visited.has(cleanTypeName)) return "{}";
|
|
95
|
+
visited.add(cleanTypeName);
|
|
96
|
+
const properties = interfaceDef.properties.filter((prop) => prop.type).map((prop) => {
|
|
97
|
+
const propType = prop.type.replace(RE_NAMESPACE, "").trim();
|
|
98
|
+
const nextVisited = new Set(visited);
|
|
99
|
+
if (propType.endsWith("[]")) {
|
|
100
|
+
const itemTemplate = generateMockTemplate(propType.slice(0, -2), interfaceMap, nextVisited);
|
|
101
|
+
return `'${prop.name}|1-5': ${itemTemplate}`;
|
|
102
|
+
}
|
|
103
|
+
const innerTemplate = generateMockTemplate(propType, interfaceMap, nextVisited);
|
|
104
|
+
return `'${prop.name}': ${innerTemplate}`;
|
|
56
105
|
});
|
|
57
|
-
|
|
58
|
-
|
|
106
|
+
visited.delete(cleanTypeName);
|
|
107
|
+
return properties.length > 0 ? `{\n ${properties.join(",\n ")}\n }` : "{}";
|
|
108
|
+
}
|
|
109
|
+
function genFunctionsWithMock(functions, interfaceMap, config) {
|
|
110
|
+
const functionBlocks = [];
|
|
111
|
+
(functions || []).forEach((item) => {
|
|
112
|
+
const functionCode = genFunction({
|
|
59
113
|
export: true,
|
|
60
|
-
comment: item.description,
|
|
61
114
|
name: item.name,
|
|
62
|
-
parameters: item.parameters
|
|
63
|
-
|
|
115
|
+
parameters: (item.parameters || []).map((p) => ({
|
|
116
|
+
name: p.name,
|
|
117
|
+
type: p.type,
|
|
118
|
+
optional: !p.required
|
|
119
|
+
})),
|
|
120
|
+
body: item.body || [],
|
|
64
121
|
async: item.async,
|
|
65
122
|
returnType: item.returnType,
|
|
66
123
|
generics: item.generics,
|
|
67
|
-
|
|
124
|
+
jsdoc: item.description
|
|
68
125
|
});
|
|
126
|
+
functionBlocks.push(functionCode);
|
|
127
|
+
const responseType = inject(item.name)?.responseType;
|
|
128
|
+
if (!config.meta?.mockjs || !responseType || responseType === "void" || responseType === "any") return;
|
|
129
|
+
const mockTemplate = generateMockTemplate(responseType, interfaceMap);
|
|
130
|
+
functionBlocks.push(`${item.name}.mock = () => Mock.mock(${mockTemplate});`);
|
|
69
131
|
});
|
|
70
|
-
|
|
71
|
-
...comments,
|
|
72
|
-
factory.createIdentifier(""),
|
|
73
|
-
...imports,
|
|
74
|
-
factory.createIdentifier(""),
|
|
75
|
-
...variables,
|
|
76
|
-
factory.createIdentifier(""),
|
|
77
|
-
...functions
|
|
78
|
-
];
|
|
79
|
-
if (!isGenerateType && isTypescript) {
|
|
80
|
-
nodes.push(factory.createIdentifier(""));
|
|
81
|
-
nodes.push(factory.createIdentifier(""));
|
|
82
|
-
nodes.push(...compilerTsTypingsDeclaration(configRead, false));
|
|
83
|
-
}
|
|
84
|
-
return nodes;
|
|
132
|
+
return functionBlocks;
|
|
85
133
|
}
|
|
86
134
|
|
|
87
135
|
//#endregion
|
|
88
136
|
//#region src/compiler/index.ts
|
|
137
|
+
/**
|
|
138
|
+
* Compiles graphs to code string: request and typings for each output.
|
|
139
|
+
*
|
|
140
|
+
* @param configRead - ConfigRead with graphs and outputs
|
|
141
|
+
* @returns Same configRead with output.code set
|
|
142
|
+
* @group Pipeline
|
|
143
|
+
*/
|
|
89
144
|
function compiler(configRead) {
|
|
90
145
|
for (const output of configRead.outputs) {
|
|
91
|
-
if (output.type === "request" && !configRead.config.onlyDeclaration) output.
|
|
92
|
-
if (output.type === "typings") output.
|
|
146
|
+
if (output.type === "request" && !configRead.config.meta?.onlyDeclaration) output.code = compilerTsRequestDeclaration(configRead);
|
|
147
|
+
if (output.type === "typings") output.code = compilerTsTypingsDeclaration(configRead);
|
|
93
148
|
}
|
|
94
149
|
return configRead;
|
|
95
150
|
}
|
|
96
151
|
|
|
97
152
|
//#endregion
|
|
98
153
|
//#region src/config/index.ts
|
|
154
|
+
/**
|
|
155
|
+
* Normalizes pipeline config: output paths, responseType, baseURL, and builds ConfigRead with inputs/outputs.
|
|
156
|
+
*
|
|
157
|
+
* @param userConfig - Raw config from defineConfig
|
|
158
|
+
* @returns ConfigRead (config + inputs + outputs)
|
|
159
|
+
* @group Pipeline
|
|
160
|
+
*/
|
|
99
161
|
function config(userConfig) {
|
|
100
|
-
userConfig.
|
|
101
|
-
userConfig.
|
|
162
|
+
userConfig.meta = userConfig.meta || {};
|
|
163
|
+
userConfig.meta.import = userConfig.meta.import || {};
|
|
164
|
+
userConfig.meta.responseType = userConfig.meta.responseType || {};
|
|
102
165
|
if (typeof userConfig.output === "string") userConfig.output = { main: userConfig.output };
|
|
103
166
|
userConfig.output = userConfig.output || {};
|
|
104
167
|
userConfig.output.main = userConfig.output.main || "src/api/index.ts";
|
|
105
|
-
if (typeof userConfig.baseURL === "string") userConfig.baseURL = userConfig.baseURL.endsWith("/\"") ? userConfig.baseURL = `${userConfig.baseURL.slice(0, userConfig.baseURL.length - 2)}"` : userConfig.baseURL;
|
|
168
|
+
if (typeof userConfig.meta.baseURL === "string") userConfig.meta.baseURL = userConfig.meta.baseURL.endsWith("/\"") ? userConfig.meta.baseURL = `${userConfig.meta.baseURL.slice(0, userConfig.meta.baseURL.length - 2)}"` : userConfig.meta.baseURL;
|
|
106
169
|
if (userConfig.output?.type !== false) userConfig.output.type = userConfig.output.type || userConfig.output.main.replace(/\.ts|\.js/g, ".type.ts");
|
|
107
|
-
if (typeof userConfig.responseType === "string") userConfig.responseType = { infer: userConfig.responseType };
|
|
170
|
+
if (typeof userConfig.meta.responseType === "string") userConfig.meta.responseType = { infer: userConfig.meta.responseType };
|
|
108
171
|
const userRoot = process.cwd();
|
|
109
172
|
const isTypescript = userConfig.output.main.endsWith(".ts");
|
|
110
173
|
const isGenerateType = userConfig.output?.type !== false;
|
|
111
|
-
const importTypePath = userConfig.import.type || getImportTypePath(userConfig.output.main, userConfig.output.type || "");
|
|
174
|
+
const importTypePath = userConfig.meta.import.type || getImportTypePath(userConfig.output.main, userConfig.output.type || "");
|
|
112
175
|
const imports = [isTypescript && isGenerateType && {
|
|
113
176
|
name: "Types",
|
|
114
177
|
value: importTypePath,
|
|
@@ -120,10 +183,10 @@ function config(userConfig) {
|
|
|
120
183
|
root: path.join(userRoot, path.dirname(userConfig.output.main)),
|
|
121
184
|
path: path.join(userRoot, userConfig.output.main)
|
|
122
185
|
}];
|
|
123
|
-
const typings = [!!userConfig.responseType
|
|
186
|
+
const typings = [!!userConfig.meta.responseType?.infer && {
|
|
124
187
|
export: true,
|
|
125
188
|
name: "Infer<T>",
|
|
126
|
-
value: userConfig.responseType.infer
|
|
189
|
+
value: userConfig.meta.responseType.infer
|
|
127
190
|
}];
|
|
128
191
|
if (userConfig.output.type !== false) outputs.push({
|
|
129
192
|
type: "typings",
|
|
@@ -145,7 +208,7 @@ function config(userConfig) {
|
|
|
145
208
|
functions: [],
|
|
146
209
|
interfaces: [],
|
|
147
210
|
typings: typings.filter(Boolean),
|
|
148
|
-
response: userConfig.responseType
|
|
211
|
+
response: userConfig.meta.responseType
|
|
149
212
|
}
|
|
150
213
|
};
|
|
151
214
|
provide({
|
|
@@ -154,8 +217,8 @@ function config(userConfig) {
|
|
|
154
217
|
});
|
|
155
218
|
return configRead;
|
|
156
219
|
}
|
|
157
|
-
function prefix(path
|
|
158
|
-
return path
|
|
220
|
+
function prefix(path) {
|
|
221
|
+
return path.startsWith(".") ? path : `./${path}`;
|
|
159
222
|
}
|
|
160
223
|
function getImportTypePath(main, type) {
|
|
161
224
|
let importTypePath = path.dirname(main);
|
|
@@ -166,61 +229,109 @@ function getImportTypePath(main, type) {
|
|
|
166
229
|
|
|
167
230
|
//#endregion
|
|
168
231
|
//#region src/dest/index.ts
|
|
169
|
-
|
|
170
|
-
|
|
232
|
+
/**
|
|
233
|
+
* Writes output files from configRead.outputs (code to path).
|
|
234
|
+
*
|
|
235
|
+
* @param configRead - ConfigRead with outputs[].path and outputs[].code
|
|
236
|
+
* @group Pipeline
|
|
237
|
+
*/
|
|
238
|
+
async function dest(configRead) {
|
|
239
|
+
await Promise.all(configRead.outputs.map(async (output) => {
|
|
171
240
|
await fs.ensureDir(output.root);
|
|
172
241
|
await fs.writeFile(output.path, output.code || "", { flag: "w" });
|
|
173
|
-
});
|
|
242
|
+
}));
|
|
174
243
|
}
|
|
175
244
|
|
|
176
245
|
//#endregion
|
|
177
246
|
//#region src/generate/index.ts
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
247
|
+
/**
|
|
248
|
+
* Formats code for each output with Prettier.
|
|
249
|
+
*
|
|
250
|
+
* @param configRead - ConfigRead with outputs[].code
|
|
251
|
+
* @returns Same configRead with outputs[].code formatted
|
|
252
|
+
* @group Pipeline
|
|
253
|
+
*/
|
|
254
|
+
async function generate(configRead, options) {
|
|
255
|
+
for (const output of configRead.outputs || []) if (output.code) output.code = await formatTypescript(output.code, options);
|
|
183
256
|
return configRead;
|
|
184
257
|
}
|
|
185
|
-
function formatTypescript(code) {
|
|
186
|
-
return format(code, {
|
|
258
|
+
async function formatTypescript(code, options) {
|
|
259
|
+
return await format(code, {
|
|
187
260
|
printWidth: 800,
|
|
261
|
+
...options,
|
|
188
262
|
parser: "typescript"
|
|
189
263
|
});
|
|
190
264
|
}
|
|
191
265
|
|
|
192
266
|
//#endregion
|
|
193
267
|
//#region src/original/index.ts
|
|
268
|
+
function isYamlUrl(url) {
|
|
269
|
+
try {
|
|
270
|
+
const pathname = new URL(url).pathname;
|
|
271
|
+
return pathname.endsWith(".yaml") || pathname.endsWith(".yml");
|
|
272
|
+
} catch {
|
|
273
|
+
return false;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
async function fetchSource(url, options) {
|
|
277
|
+
if (isYamlUrl(url)) return parseYAML(await ofetch(url, {
|
|
278
|
+
...options,
|
|
279
|
+
responseType: "text"
|
|
280
|
+
}));
|
|
281
|
+
if (options && Object.keys(options).length > 0) return await ofetch(url, options);
|
|
282
|
+
return await ofetch(url);
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Fetches source: resolves uri/http/json from configRead.inputs and sets configRead.source.
|
|
286
|
+
* Transforms the source based on parser configuration (wpapi -> swagger2, swagger -> unchanged).
|
|
287
|
+
* Supports YAML source URLs (e.g. .yaml / .yml); uses confbox for parsing (same as undocs).
|
|
288
|
+
*
|
|
289
|
+
* @param configRead - ConfigRead with inputs (uri, http, or json)
|
|
290
|
+
* @returns Same configRead with source set and transformed if needed
|
|
291
|
+
* @group Pipeline
|
|
292
|
+
*/
|
|
194
293
|
async function original(configRead) {
|
|
195
|
-
if (configRead.inputs.uri) configRead.source = await
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
...configRead.inputs.http,
|
|
201
|
-
responseType: "json"
|
|
202
|
-
}).json();
|
|
294
|
+
if (configRead.inputs.uri) configRead.source = await fetchSource(configRead.inputs.uri);
|
|
295
|
+
if (configRead.inputs.http) {
|
|
296
|
+
const { url, ...options } = configRead.inputs.http;
|
|
297
|
+
configRead.source = await fetchSource(url || configRead.inputs.uri || "", options);
|
|
298
|
+
}
|
|
203
299
|
if (configRead.inputs.json) configRead.source = await readJsonSource(configRead.inputs.json);
|
|
204
300
|
if (!configRead.source) throw new Error("No source found, please check your input config.");
|
|
301
|
+
if ((configRead.config.parser || "swagger") === "wpapi") configRead.source = wpapiToSwagger2(configRead.source);
|
|
205
302
|
if (!configRead.source.schemes?.length) {
|
|
303
|
+
const effectiveUrl = configRead.inputs.http?.url || configRead.inputs.uri || "";
|
|
206
304
|
const schemes = [];
|
|
207
|
-
if (
|
|
208
|
-
if (
|
|
209
|
-
configRead.source.schemes = schemes;
|
|
305
|
+
if (effectiveUrl.startsWith("https://")) schemes.push("https", "http");
|
|
306
|
+
if (effectiveUrl.startsWith("http://")) schemes.push("http");
|
|
307
|
+
if (schemes.length > 0) configRead.source.schemes = schemes;
|
|
210
308
|
}
|
|
211
309
|
return configRead;
|
|
212
310
|
}
|
|
213
311
|
function readJsonSource(json) {
|
|
214
|
-
if (!json) return;
|
|
215
|
-
if (typeof json === "object") return json;
|
|
216
|
-
|
|
312
|
+
if (!json) return Promise.resolve(void 0);
|
|
313
|
+
if (typeof json === "object") return Promise.resolve(json);
|
|
314
|
+
const trimmed = String(json).trim();
|
|
315
|
+
if (trimmed.startsWith("{") || trimmed.startsWith("[")) return Promise.resolve(JSON.parse(json));
|
|
316
|
+
return import(json).then((mod) => mod.default);
|
|
217
317
|
}
|
|
218
318
|
|
|
219
319
|
//#endregion
|
|
220
320
|
//#region src/pipeline/index.ts
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
321
|
+
/**
|
|
322
|
+
* Builds a GenAPI pipeline from five steps: config → original → parser → compiler → generate → dest.
|
|
323
|
+
*
|
|
324
|
+
* @param config - Reads config and returns ConfigRead
|
|
325
|
+
* @param original - Fetches source (e.g. OpenAPI JSON)
|
|
326
|
+
* @param parser - Parses source into graphs
|
|
327
|
+
* @param compiler - Compiles graphs to AST
|
|
328
|
+
* @param generate - Generates code string
|
|
329
|
+
* @param dest - Writes output files
|
|
330
|
+
* @returns A function that runs the pipeline for a given config
|
|
331
|
+
* @group Pipeline
|
|
332
|
+
*/
|
|
333
|
+
function pipeline(config, original, parser, compiler, generate, dest) {
|
|
334
|
+
return pPipe(config, original, parser, compiler, generate, dest);
|
|
224
335
|
}
|
|
225
336
|
pipeline.config = config;
|
|
226
337
|
pipeline.original = original;
|
|
@@ -234,4 +345,4 @@ pipeline.dest = dest;
|
|
|
234
345
|
var src_default = pipeline;
|
|
235
346
|
|
|
236
347
|
//#endregion
|
|
237
|
-
export { compiler, config, src_default as default, dest, generate, original };
|
|
348
|
+
export { compiler, compilerTsRequestDeclaration, compilerTsTypingsDeclaration, config, src_default as default, dest, formatTypescript, generate, original };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@genapi/pipeline",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "4.0.0",
|
|
5
5
|
"author": "Hairyf <wwu710632@gmail.com>",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"homepage": "https://github.com/hairyf/genapi#readme",
|
|
@@ -15,29 +15,32 @@
|
|
|
15
15
|
"shared"
|
|
16
16
|
],
|
|
17
17
|
"sideEffects": false,
|
|
18
|
-
"
|
|
18
|
+
"exports": {
|
|
19
|
+
".": "./dist/index.mjs",
|
|
20
|
+
"./package.json": "./package.json"
|
|
21
|
+
},
|
|
22
|
+
"types": "./dist/index.d.mts",
|
|
19
23
|
"files": [
|
|
20
24
|
"dist"
|
|
21
25
|
],
|
|
22
26
|
"dependencies": {
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
"@genapi/shared": "
|
|
27
|
+
"confbox": "^0.2.4",
|
|
28
|
+
"fs-extra": "^11.3.3",
|
|
29
|
+
"knitwork-x": "^0.2.0",
|
|
30
|
+
"ofetch": "^1.5.1",
|
|
31
|
+
"p-pipe": "^4.0.0",
|
|
32
|
+
"prettier": "^3.8.1",
|
|
33
|
+
"@genapi/shared": "4.0.0",
|
|
34
|
+
"@genapi/transform": "4.0.0"
|
|
30
35
|
},
|
|
31
36
|
"devDependencies": {
|
|
32
|
-
"@types/fs-extra": "^11.0.
|
|
37
|
+
"@types/fs-extra": "^11.0.4",
|
|
38
|
+
"@types/prettier": "^2.7.3"
|
|
33
39
|
},
|
|
34
40
|
"scripts": {
|
|
35
41
|
"build": "tsdown",
|
|
36
|
-
"
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
},
|
|
41
|
-
"module": "./dist/index.mjs",
|
|
42
|
-
"types": "./dist/index.d.mts"
|
|
42
|
+
"dev": "tsdown --watch",
|
|
43
|
+
"typecheck": "tsc --noEmit",
|
|
44
|
+
"automd": "automd"
|
|
45
|
+
}
|
|
43
46
|
}
|