@nudojs/service 0.2.1 → 0.3.1
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 +517 -4
- package/dist/index.js +3043 -213
- package/package.json +16 -5
- package/CHANGELOG.md +0 -38
- package/src/__tests__/analyzer.test.ts +0 -812
- package/src/__tests__/as-replace.test.ts +0 -165
- package/src/__tests__/case-emitter.test.ts +0 -636
- package/src/__tests__/diagnostics.test.ts +0 -90
- package/src/__tests__/dts-generator.test.ts +0 -382
- package/src/__tests__/fn-sig-impl.test.ts +0 -247
- package/src/__tests__/guard-generator.test.ts +0 -29
- package/src/__tests__/integration.test.ts +0 -332
- package/src/__tests__/schema-generator.test.ts +0 -38
- package/src/analyzer.ts +0 -1841
- package/src/case-emitter.ts +0 -475
- package/src/dts-generator.ts +0 -291
- package/src/guard-generator.ts +0 -50
- package/src/index.ts +0 -47
- package/src/schema-generator.ts +0 -43
- package/tsconfig.json +0 -13
package/src/dts-generator.ts
DELETED
|
@@ -1,291 +0,0 @@
|
|
|
1
|
-
import type { TypeValue } from "@nudojs/core";
|
|
2
|
-
import { T, isTemplate, getTemplateParts, simplifyUnion, typeValueEquals } from "@nudojs/core";
|
|
3
|
-
import type { AnalysisResult, FunctionAnalysis } from "./analyzer.ts";
|
|
4
|
-
|
|
5
|
-
export function typeValueToTSType(tv: TypeValue): string {
|
|
6
|
-
switch (tv.kind) {
|
|
7
|
-
case "literal": {
|
|
8
|
-
const v = tv.value;
|
|
9
|
-
if (v === null) return "null";
|
|
10
|
-
if (v === undefined) return "undefined";
|
|
11
|
-
if (typeof v === "string") return JSON.stringify(v);
|
|
12
|
-
if (typeof v === "boolean") return String(v);
|
|
13
|
-
return String(v);
|
|
14
|
-
}
|
|
15
|
-
case "primitive":
|
|
16
|
-
return tv.type;
|
|
17
|
-
case "refined": {
|
|
18
|
-
if (isTemplate(tv)) {
|
|
19
|
-
const parts = getTemplateParts(tv)!;
|
|
20
|
-
const inner = parts
|
|
21
|
-
.map((p) => (p.kind === "literal" && typeof p.value === "string" ? p.value : `\${${typeValueToTSType(p)}}`))
|
|
22
|
-
.join("");
|
|
23
|
-
return `\`${inner}\``;
|
|
24
|
-
}
|
|
25
|
-
return typeValueToTSType(tv.base);
|
|
26
|
-
}
|
|
27
|
-
case "object": {
|
|
28
|
-
const entries = Object.entries(tv.properties);
|
|
29
|
-
if (entries.length === 0) return "{}";
|
|
30
|
-
const inner = entries
|
|
31
|
-
.map(([k, v]) => `${k}: ${typeValueToTSType(v)}`)
|
|
32
|
-
.join("; ");
|
|
33
|
-
return `{ ${inner} }`;
|
|
34
|
-
}
|
|
35
|
-
case "array":
|
|
36
|
-
return `${wrapComplexType(tv.element)}[]`;
|
|
37
|
-
case "tuple": {
|
|
38
|
-
const inner = tv.elements.map(typeValueToTSType).join(", ");
|
|
39
|
-
return `[${inner}]`;
|
|
40
|
-
}
|
|
41
|
-
case "function": {
|
|
42
|
-
const params = tv.params
|
|
43
|
-
.map((p) => `${p}: unknown`)
|
|
44
|
-
.join(", ");
|
|
45
|
-
const returnType = (tv as any)._returnType;
|
|
46
|
-
const retStr = returnType ? typeValueToTSType(returnType) : "unknown";
|
|
47
|
-
return `(${params}) => ${retStr}`;
|
|
48
|
-
}
|
|
49
|
-
case "promise":
|
|
50
|
-
return `Promise<${typeValueToTSType(tv.value)}>`;
|
|
51
|
-
case "instance":
|
|
52
|
-
return tv.className;
|
|
53
|
-
case "union":
|
|
54
|
-
return tv.members.map(typeValueToTSType).join(" | ");
|
|
55
|
-
case "never":
|
|
56
|
-
return "never";
|
|
57
|
-
case "unknown":
|
|
58
|
-
return "unknown";
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
function wrapComplexType(tv: TypeValue): string {
|
|
63
|
-
const ts = typeValueToTSType(tv);
|
|
64
|
-
if (tv.kind === "union") return `(${ts})`;
|
|
65
|
-
return ts;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
function getParamName(fn: FunctionAnalysis, index: number): string {
|
|
69
|
-
if (fn.paramNames && fn.paramNames[index]) {
|
|
70
|
-
return fn.paramNames[index];
|
|
71
|
-
}
|
|
72
|
-
return `arg${index}`;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// ---------------------------------------------------------------------------
|
|
76
|
-
// Widening —— 主签名语义
|
|
77
|
-
//
|
|
78
|
-
// case 形状携带字面量精度(10、"Alice"、true、[1,2,3]、{ id: 1 }),但
|
|
79
|
-
// .d.ts 是调用面而非 case 台账:按 case 生成重载时 `safeSqrt(arg0: 10): 10`
|
|
80
|
-
// 会让合法调用 `safeSqrt(5)` 匹配不到任何重载,直接编译错误(tsc 5.9.3
|
|
81
|
-
// 实测 TS2769,见 __tests__/dts-generator.test.ts 的 safeSqrt 场景)。
|
|
82
|
-
// 主签名因此取 Combined 语义:每个参数位置取各 case 对应参数类型的联合
|
|
83
|
-
// 并 widen,返回类型对 combined 同样 widen(顶层标量字面量 → 基类型
|
|
84
|
-
// number/string/boolean/bigint;null/undefined 字面量本身是基类型,不变)。
|
|
85
|
-
//
|
|
86
|
-
// 参数位是逆变位,拦截面最广,widen 递归进结构(tsc --strict 实测):
|
|
87
|
-
// - 同构元组 [1,2,3,4,5] → number[]:定长 widened 元组
|
|
88
|
-
// [number,number,number,number,number] 仍会拒收变长合法实参(TS2345
|
|
89
|
-
// "Source has 2 element(s) but target requires 3"),而字面量长度只是
|
|
90
|
-
// 单次调用观察,不该构成约束;
|
|
91
|
-
// - 异构元组 [1,"two"] → [number, string]:位置语义真实,且不拦截
|
|
92
|
-
// 合法的按位调用(实测 f([1,"x"]) 通过);
|
|
93
|
-
// - 对象属性值 { id: 1 } → { id: number }、数组元素、Promise 载荷、
|
|
94
|
-
// 实例属性同样递归 widen(全部处于逆变位,字面量精度同样拦截赋值);
|
|
95
|
-
// - refined(模板串/数值收窄)剥到 base:参数位收窄拦截一切不匹配
|
|
96
|
-
// 实参,精确形状由 JSDoc Case: 行保留。
|
|
97
|
-
//
|
|
98
|
-
// 返回值位是协变位,收窄只会让调用方拿到更精确的类型、不会拦截调用,
|
|
99
|
-
// 维持现状:仅顶层(含 union 成员)标量字面量 widen,嵌套精度保留
|
|
100
|
-
// (Promise<42>、返回元组字面量等)。
|
|
101
|
-
//
|
|
102
|
-
// 就地实现而不复用 core 的 widenLiteral:①本路径不依赖 core 侧并行改动的
|
|
103
|
-
// 落地时序;②core 版本把 bigint 字面量映射到 unknown,不符合此处语义。
|
|
104
|
-
// ---------------------------------------------------------------------------
|
|
105
|
-
function widenLiteralToBase(tv: TypeValue): TypeValue {
|
|
106
|
-
if (tv.kind !== "literal") return tv;
|
|
107
|
-
const v = tv.value;
|
|
108
|
-
if (typeof v === "number") return T.number;
|
|
109
|
-
if (typeof v === "string") return T.string;
|
|
110
|
-
if (typeof v === "boolean") return T.boolean;
|
|
111
|
-
if (typeof v === "bigint") return T.bigint;
|
|
112
|
-
return tv;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
/** 返回值位(协变):仅顶层标量字面量 widen,嵌套精度保留 */
|
|
116
|
-
function widenTopLevel(tv: TypeValue): TypeValue {
|
|
117
|
-
if (tv.kind !== "union") return widenLiteralToBase(tv);
|
|
118
|
-
return simplifyUnion(tv.members.map(widenLiteralToBase));
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
function widenProperties(properties: Record<string, TypeValue>): Record<string, TypeValue> {
|
|
122
|
-
const out: Record<string, TypeValue> = {};
|
|
123
|
-
for (const [k, v] of Object.entries(properties)) out[k] = widenParamType(v);
|
|
124
|
-
return out;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
/** 参数位(逆变)递归 widen:结构内的字面量精度一律放宽到基类型 */
|
|
128
|
-
function widenParamType(tv: TypeValue): TypeValue {
|
|
129
|
-
switch (tv.kind) {
|
|
130
|
-
case "literal":
|
|
131
|
-
return widenLiteralToBase(tv);
|
|
132
|
-
case "union":
|
|
133
|
-
return simplifyUnion(tv.members.map(widenParamType));
|
|
134
|
-
case "tuple": {
|
|
135
|
-
const widened = tv.elements.map(widenParamType);
|
|
136
|
-
const first = widened[0];
|
|
137
|
-
if (first && widened.every((el) => typeValueEquals(el, first))) {
|
|
138
|
-
return T.array(first);
|
|
139
|
-
}
|
|
140
|
-
return T.tuple(widened);
|
|
141
|
-
}
|
|
142
|
-
case "array":
|
|
143
|
-
return T.array(widenParamType(tv.element));
|
|
144
|
-
case "object":
|
|
145
|
-
return T.object(widenProperties(tv.properties));
|
|
146
|
-
case "promise":
|
|
147
|
-
return T.promise(widenParamType(tv.value));
|
|
148
|
-
case "instance":
|
|
149
|
-
return T.instanceOf(tv.className, widenProperties(tv.properties));
|
|
150
|
-
case "refined":
|
|
151
|
-
return widenParamType(tv.base);
|
|
152
|
-
default:
|
|
153
|
-
return tv;
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* 各 case 在同一参数位的类型 → 拍平、递归 widen、去重后的单一 TypeValue。
|
|
159
|
-
* 去重以 TS 渲染串为键:TypeValue 的对象/元组相等性是引用比较,两个同形
|
|
160
|
-
* 的 widened 对象(如各 case 的 { id: number })不去重会渲染成重复成员。
|
|
161
|
-
*/
|
|
162
|
-
function widenedUnion(members: TypeValue[]): TypeValue {
|
|
163
|
-
const flat: TypeValue[] = [];
|
|
164
|
-
const collect = (tv: TypeValue): void => {
|
|
165
|
-
if (tv.kind === "union") {
|
|
166
|
-
tv.members.forEach(collect);
|
|
167
|
-
return;
|
|
168
|
-
}
|
|
169
|
-
flat.push(tv);
|
|
170
|
-
};
|
|
171
|
-
members.forEach(collect);
|
|
172
|
-
const widened = flat.map(widenParamType);
|
|
173
|
-
const seen = new Set<string>();
|
|
174
|
-
const deduped = widened.filter((tv) => {
|
|
175
|
-
const key = typeValueToTSType(tv);
|
|
176
|
-
if (seen.has(key)) return false;
|
|
177
|
-
seen.add(key);
|
|
178
|
-
return true;
|
|
179
|
-
});
|
|
180
|
-
return simplifyUnion(deduped);
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
type MainSignature = {
|
|
184
|
-
/** 渲染后的参数声明(含 `?` / `...rest`),如 `["x: number", "y?: string"]` */
|
|
185
|
-
params: string[];
|
|
186
|
-
/** 去重后的参数名(JSDoc @param 与渲染共用,保证一致) */
|
|
187
|
-
paramNames: string[];
|
|
188
|
-
/** 各参数位 widen 后的 TS 类型串(JSDoc 与精确度比对用) */
|
|
189
|
-
paramTypes: string[];
|
|
190
|
-
/** widen 后的返回类型串 */
|
|
191
|
-
returnType: string;
|
|
192
|
-
};
|
|
193
|
-
|
|
194
|
-
function computeMainSignature(fn: FunctionAnalysis): MainSignature {
|
|
195
|
-
const arity = Math.max(...fn.cases.map((c) => c.args.length));
|
|
196
|
-
const minArity = Math.min(...fn.cases.map((c) => c.args.length));
|
|
197
|
-
const params: string[] = [];
|
|
198
|
-
const paramNames: string[] = [];
|
|
199
|
-
const paramTypes: string[] = [];
|
|
200
|
-
const usedNames = new Set<string>();
|
|
201
|
-
for (let i = 0; i < arity; i++) {
|
|
202
|
-
const members = fn.cases
|
|
203
|
-
.filter((c) => i < c.args.length)
|
|
204
|
-
.map((c) => c.args[i]);
|
|
205
|
-
const typeStr = typeValueToTSType(widenedUnion(members));
|
|
206
|
-
let name = getParamName(fn, i);
|
|
207
|
-
if (usedNames.has(name)) {
|
|
208
|
-
// 解构/模式参数在 AST 提取时都叫 "_";单一签名里重名会让 .d.ts
|
|
209
|
-
// 非法(tsc TS2300 Duplicate identifier),序号去重
|
|
210
|
-
let n = 2;
|
|
211
|
-
while (usedNames.has(`${name}${n}`)) n++;
|
|
212
|
-
name = `${name}${n}`;
|
|
213
|
-
}
|
|
214
|
-
usedNames.add(name);
|
|
215
|
-
// 各 case 元数不一致时,短 case 不传的尾部参数标可选,长调用短调用都放行
|
|
216
|
-
const optional = i >= minArity && !name.startsWith("...");
|
|
217
|
-
params.push(optional ? `${name}?: ${typeStr}` : `${name}: ${typeStr}`);
|
|
218
|
-
paramNames.push(name);
|
|
219
|
-
paramTypes.push(typeStr);
|
|
220
|
-
}
|
|
221
|
-
const combined = fn.combined ?? simplifyUnion(fn.cases.map((c) => c.result));
|
|
222
|
-
const returnType = typeValueToTSType(widenTopLevel(combined));
|
|
223
|
-
return { params, paramNames, paramTypes, returnType };
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
function generateJSDoc(fn: FunctionAnalysis, sig: MainSignature): string {
|
|
227
|
-
if (fn.cases.length === 0) return "";
|
|
228
|
-
const lines: string[] = ["/**"];
|
|
229
|
-
// 精确 case 形状记录在主签名 JSDoc 而非生成精确重载。决策依据按实测修正
|
|
230
|
-
// (tsc 5.9.3,最小 .d.ts + 调用文件 + tsc --noEmit):字面量参数重载其实
|
|
231
|
-
// 可达——「宽主签名在前则后置精确重载永不命中」不成立,新鲜与非新鲜
|
|
232
|
-
// (as const 传入)字面量实参都会优先命中字面量参数重载,与声明顺序无关。
|
|
233
|
-
// 即便如此仍只生成单一主签名:① --callsites 场景单个函数可合成几十个
|
|
234
|
-
// case,逐 case 重载会让声明面爆炸;② throwing case 的 `: never` 重载对
|
|
235
|
-
// 调用方是陷阱(对 never 取属性/运算直接报错);③ 字面量精度由下面的
|
|
236
|
-
// Case: 行完整保留。与主签名同形的 case(无信息损失)不罗列。
|
|
237
|
-
for (const c of fn.cases) {
|
|
238
|
-
const preciseDiffers =
|
|
239
|
-
c.args.length !== sig.paramTypes.length ||
|
|
240
|
-
c.args.some((a, i) => typeValueToTSType(a) !== sig.paramTypes[i]) ||
|
|
241
|
-
typeValueToTSType(c.result) !== sig.returnType;
|
|
242
|
-
if (!preciseDiffers) continue;
|
|
243
|
-
const argsStr = c.args.map(typeValueToTSType).join(", ");
|
|
244
|
-
lines.push(` * Case: ${c.name} (${argsStr}) => ${typeValueToTSType(c.result)}`);
|
|
245
|
-
}
|
|
246
|
-
for (let i = 0; i < sig.paramTypes.length; i++) {
|
|
247
|
-
lines.push(` * @param ${sig.paramNames[i]} - ${sig.paramTypes[i]}`);
|
|
248
|
-
}
|
|
249
|
-
lines.push(` * @returns ${sig.returnType}`);
|
|
250
|
-
lines.push(" */");
|
|
251
|
-
return lines.join("\n");
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
/**
|
|
255
|
-
* 为单个函数生成 .d.ts 声明行(JSDoc + 单一 widen 主签名)。
|
|
256
|
-
* service 的 generateDts 与 CLI `--dts`(infer/watch)共用本函数,
|
|
257
|
-
* 两条路径输出保持一致。
|
|
258
|
-
*/
|
|
259
|
-
export function generateFunctionDtsLines(fn: FunctionAnalysis): string[] {
|
|
260
|
-
// CJS-style binding/assignment functions have no declaration-stable
|
|
261
|
-
// export name; they stay in infer/JSON output only.
|
|
262
|
-
if (fn.noDeclaration) return [];
|
|
263
|
-
|
|
264
|
-
if (fn.cases.length === 0) {
|
|
265
|
-
// skipped / entryOnly / 无 case 函数:只有声明或 combined 返回类型已知,
|
|
266
|
-
// 保持历史行为——rest-args 形式,combined(含 Promise<T>)原样输出。
|
|
267
|
-
if (fn.combined) {
|
|
268
|
-
return [
|
|
269
|
-
`export declare function ${fn.name}(...args: unknown[]): ${typeValueToTSType(fn.combined)};`,
|
|
270
|
-
];
|
|
271
|
-
}
|
|
272
|
-
return [];
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
const sig = computeMainSignature(fn);
|
|
276
|
-
const jsdoc = generateJSDoc(fn, sig);
|
|
277
|
-
const lines: string[] = [];
|
|
278
|
-
if (jsdoc) lines.push(jsdoc);
|
|
279
|
-
lines.push(`export declare function ${fn.name}(${sig.params.join(", ")}): ${sig.returnType};`);
|
|
280
|
-
return lines;
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
export function generateDts(result: AnalysisResult): string {
|
|
284
|
-
const lines: string[] = [];
|
|
285
|
-
|
|
286
|
-
for (const fn of result.functions) {
|
|
287
|
-
lines.push(...generateFunctionDtsLines(fn));
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
return lines.join("\n") + "\n";
|
|
291
|
-
}
|
package/src/guard-generator.ts
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import type { TypeValue } from "@nudojs/core";
|
|
2
|
-
|
|
3
|
-
export function generateGuardFunction(name: string, tv: TypeValue): string {
|
|
4
|
-
const body = generateGuardBody(tv, "data");
|
|
5
|
-
return `export function ${name}(data) {\n return ${body};\n}`;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
function generateGuardBody(tv: TypeValue, varName: string): string {
|
|
9
|
-
switch (tv.kind) {
|
|
10
|
-
case "literal": {
|
|
11
|
-
if (tv.value === null) return `${varName} === null`;
|
|
12
|
-
if (tv.value === undefined) return `${varName} === undefined`;
|
|
13
|
-
return `${varName} === ${JSON.stringify(tv.value)}`;
|
|
14
|
-
}
|
|
15
|
-
case "primitive":
|
|
16
|
-
return `typeof ${varName} === '${tv.type}'`;
|
|
17
|
-
case "refined":
|
|
18
|
-
return generateGuardBody(tv.base, varName);
|
|
19
|
-
case "object": {
|
|
20
|
-
const checks = [`typeof ${varName} === 'object'`, `${varName} !== null`];
|
|
21
|
-
for (const [key, val] of Object.entries(tv.properties)) {
|
|
22
|
-
checks.push(generateGuardBody(val, `${varName}.${key}`));
|
|
23
|
-
}
|
|
24
|
-
return checks.join(" && ");
|
|
25
|
-
}
|
|
26
|
-
case "array":
|
|
27
|
-
return `Array.isArray(${varName}) && ${varName}.every(item => ${generateGuardBody(tv.element, "item")})`;
|
|
28
|
-
case "tuple": {
|
|
29
|
-
const checks = [`Array.isArray(${varName})`, `${varName}.length === ${tv.elements.length}`];
|
|
30
|
-
tv.elements.forEach((el, i) => {
|
|
31
|
-
checks.push(generateGuardBody(el, `${varName}[${i}]`));
|
|
32
|
-
});
|
|
33
|
-
return checks.join(" && ");
|
|
34
|
-
}
|
|
35
|
-
case "union": {
|
|
36
|
-
const members = tv.members.map((m) => generateGuardBody(m, varName));
|
|
37
|
-
return `(${members.join(" || ")})`;
|
|
38
|
-
}
|
|
39
|
-
case "never":
|
|
40
|
-
return "false";
|
|
41
|
-
case "unknown":
|
|
42
|
-
return "true";
|
|
43
|
-
case "function":
|
|
44
|
-
return `typeof ${varName} === 'function'`;
|
|
45
|
-
case "promise":
|
|
46
|
-
return `${varName} instanceof Promise`;
|
|
47
|
-
case "instance":
|
|
48
|
-
return `${varName} instanceof ${tv.className}`;
|
|
49
|
-
}
|
|
50
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
export {
|
|
2
|
-
type AnalysisResult,
|
|
3
|
-
type FunctionAnalysis,
|
|
4
|
-
type CaseResult,
|
|
5
|
-
type CaseInfo,
|
|
6
|
-
type CaseHint,
|
|
7
|
-
type Diagnostic,
|
|
8
|
-
type DiagnosticSeverity,
|
|
9
|
-
type DiagnosticTag,
|
|
10
|
-
type SourceLocation,
|
|
11
|
-
type BindingInfo,
|
|
12
|
-
type CompletionItem,
|
|
13
|
-
type SymbolInfo,
|
|
14
|
-
type ReferenceInfo,
|
|
15
|
-
type SymbolTable,
|
|
16
|
-
analyzeFile,
|
|
17
|
-
analyzeFileAsync,
|
|
18
|
-
collectCallRecords,
|
|
19
|
-
type CallRecord,
|
|
20
|
-
getTypeAtPosition,
|
|
21
|
-
getTypeAtPositionAsync,
|
|
22
|
-
getCompletionsAtPosition,
|
|
23
|
-
getCasesForFile,
|
|
24
|
-
buildModuleGraph,
|
|
25
|
-
type ModuleGraphCache,
|
|
26
|
-
computeDirtySet,
|
|
27
|
-
topoSortDirty,
|
|
28
|
-
} from "./analyzer.ts";
|
|
29
|
-
|
|
30
|
-
export {
|
|
31
|
-
typeValueToTSType,
|
|
32
|
-
generateDts,
|
|
33
|
-
generateFunctionDtsLines,
|
|
34
|
-
} from "./dts-generator.ts";
|
|
35
|
-
|
|
36
|
-
export { typeValueToZodSchema } from "./schema-generator.ts";
|
|
37
|
-
export { generateGuardFunction } from "./guard-generator.ts";
|
|
38
|
-
|
|
39
|
-
export {
|
|
40
|
-
serializeCaseArg,
|
|
41
|
-
buildCaseDirective,
|
|
42
|
-
stripGeneratedCaseDirectives,
|
|
43
|
-
insertGeneratedCaseDirectives,
|
|
44
|
-
unifiedDiff,
|
|
45
|
-
type EmitSkipReason,
|
|
46
|
-
type EmitResult,
|
|
47
|
-
} from "./case-emitter.ts";
|
package/src/schema-generator.ts
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import type { TypeValue } from "@nudojs/core";
|
|
2
|
-
|
|
3
|
-
export function typeValueToZodSchema(tv: TypeValue): string {
|
|
4
|
-
switch (tv.kind) {
|
|
5
|
-
case "literal": {
|
|
6
|
-
if (tv.value === null) return "z.null()";
|
|
7
|
-
if (tv.value === undefined) return "z.undefined()";
|
|
8
|
-
if (typeof tv.value === "string") return `z.literal(${JSON.stringify(tv.value)})`;
|
|
9
|
-
if (typeof tv.value === "boolean") return `z.literal(${tv.value})`;
|
|
10
|
-
return `z.literal(${tv.value})`;
|
|
11
|
-
}
|
|
12
|
-
case "primitive":
|
|
13
|
-
return `z.${tv.type}()`;
|
|
14
|
-
case "refined":
|
|
15
|
-
return typeValueToZodSchema(tv.base);
|
|
16
|
-
case "object": {
|
|
17
|
-
const entries = Object.entries(tv.properties)
|
|
18
|
-
.map(([k, v]) => `${k}: ${typeValueToZodSchema(v)}`)
|
|
19
|
-
.join(", ");
|
|
20
|
-
return `z.object({ ${entries} })`;
|
|
21
|
-
}
|
|
22
|
-
case "array":
|
|
23
|
-
return `z.array(${typeValueToZodSchema(tv.element)})`;
|
|
24
|
-
case "tuple": {
|
|
25
|
-
const inner = tv.elements.map(typeValueToZodSchema).join(", ");
|
|
26
|
-
return `z.tuple([${inner}])`;
|
|
27
|
-
}
|
|
28
|
-
case "function":
|
|
29
|
-
return "z.function()";
|
|
30
|
-
case "promise":
|
|
31
|
-
return `z.promise(${typeValueToZodSchema(tv.value)})`;
|
|
32
|
-
case "instance":
|
|
33
|
-
return `z.instanceof(${tv.className})`;
|
|
34
|
-
case "union": {
|
|
35
|
-
const members = tv.members.map(typeValueToZodSchema).join(", ");
|
|
36
|
-
return `z.union([${members}])`;
|
|
37
|
-
}
|
|
38
|
-
case "never":
|
|
39
|
-
return "z.never()";
|
|
40
|
-
case "unknown":
|
|
41
|
-
return "z.unknown()";
|
|
42
|
-
}
|
|
43
|
-
}
|
package/tsconfig.json
DELETED