@nudojs/service 0.3.0 → 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 +18 -3
- package/dist/index.js +80 -55
- package/package.json +16 -6
- package/CHANGELOG.md +0 -68
- package/src/__tests__/abs-bindings.test.ts +0 -53
- package/src/__tests__/abs-call-records.test.ts +0 -33
- package/src/__tests__/abs-calls.test.ts +0 -59
- package/src/__tests__/abs-module-cache.test.ts +0 -121
- package/src/__tests__/abs-modules-graph.test.ts +0 -100
- package/src/__tests__/abs-typevalue-diff.test.ts +0 -111
- package/src/__tests__/analyzer.test.ts +0 -880
- package/src/__tests__/as-replace.test.ts +0 -165
- package/src/__tests__/bpath-arg-provenance.test.ts +0 -104
- package/src/__tests__/bpath-as.test.ts +0 -54
- package/src/__tests__/bpath-cache-key.test.ts +0 -33
- package/src/__tests__/bpath-calls.test.ts +0 -55
- package/src/__tests__/bpath-diagnostics.test.ts +0 -78
- package/src/__tests__/bpath-env-modules.test.ts +0 -30
- package/src/__tests__/bpath-env.test.ts +0 -80
- package/src/__tests__/bpath-hosted-skip.test.ts +0 -71
- package/src/__tests__/bpath-import-default-ns.test.ts +0 -106
- package/src/__tests__/bpath-method-dedupe.test.ts +0 -65
- package/src/__tests__/bpath-method-diag.test.ts +0 -45
- package/src/__tests__/bpath-module-diags.test.ts +0 -101
- package/src/__tests__/bpath-path-env.test.ts +0 -46
- package/src/__tests__/bpath-reexport.test.ts +0 -131
- package/src/__tests__/bpath-replace.test.ts +0 -52
- package/src/__tests__/bpath-require.test.ts +0 -66
- package/src/__tests__/bpath-run.test.ts +0 -109
- package/src/__tests__/case-emitter.test.ts +0 -636
- package/src/__tests__/cjs-require.test.ts +0 -54
- package/src/__tests__/diagnostics.test.ts +0 -60
- package/src/__tests__/dts-generator.test.ts +0 -382
- package/src/__tests__/fn-cache-evict.test.ts +0 -56
- package/src/__tests__/fn-sig-impl.test.ts +0 -247
- package/src/__tests__/guard-generator.test.ts +0 -29
- package/src/__tests__/harvest-auto.test.ts +0 -43
- package/src/__tests__/harvest-node.test.ts +0 -24
- package/src/__tests__/harvest-package.test.ts +0 -38
- package/src/__tests__/harvest-to-abs.test.ts +0 -46
- package/src/__tests__/hover-intension.test.ts +0 -39
- package/src/__tests__/infer-json.test.ts +0 -35
- package/src/__tests__/integration.test.ts +0 -421
- package/src/__tests__/m3-intension.test.ts +0 -28
- package/src/__tests__/mock-seed-fingerprint.test.ts +0 -64
- package/src/__tests__/schema-generator.test.ts +0 -38
- package/src/__tests__/session-cache-evict.test.ts +0 -90
- package/src/__tests__/static-imports.test.ts +0 -44
- package/src/abs-modules-graph.ts +0 -387
- package/src/analysis-file-cache.ts +0 -51
- package/src/analyzer.ts +0 -3133
- package/src/bpath-diagnostics.ts +0 -283
- package/src/bpath-run.ts +0 -409
- package/src/case-emitter.ts +0 -477
- package/src/dts-generator.ts +0 -291
- package/src/env-to-abs.ts +0 -57
- package/src/fn-analysis-cache.ts +0 -119
- package/src/guard-generator.ts +0 -57
- package/src/harvest-auto.ts +0 -86
- package/src/harvest-node.ts +0 -48
- package/src/harvest-package.ts +0 -204
- package/src/harvest-to-abs.ts +0 -129
- package/src/index.ts +0 -150
- package/src/infer-json.ts +0 -137
- package/src/load-module.ts +0 -34
- package/src/mock-abs.ts +0 -275
- package/src/schema-generator.ts +0 -43
- package/src/semantic-tokens.ts +0 -216
- package/src/session-cache.ts +0 -50
- package/src/static-imports.ts +0 -241
- package/src/target-path.ts +0 -17
- package/tsconfig.json +0 -13
package/src/harvest-package.ts
DELETED
|
@@ -1,204 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Host:从 npm 包 / @types 收集 .d.ts → harvestDts。
|
|
3
|
-
* 代数不碰 fs;这里只做「找到 dts 路径」这一层宿主职责。
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { existsSync, readdirSync, statSync, readFileSync } from "node:fs";
|
|
7
|
-
import { join, resolve, dirname, basename } from "node:path";
|
|
8
|
-
import { harvestDts, type HarvestedEnv } from "@nudojs/harvester";
|
|
9
|
-
import { typeValueToString, type TypeValue } from "@nudojs/core";
|
|
10
|
-
|
|
11
|
-
/** 在 node_modules 中解析包根(含 @types/*) */
|
|
12
|
-
export function resolvePackageRoot(
|
|
13
|
-
pkg: string,
|
|
14
|
-
fromDir: string = process.cwd(),
|
|
15
|
-
): string | undefined {
|
|
16
|
-
let dir = resolve(fromDir);
|
|
17
|
-
const bare = pkg.replace(/^@/, "").replace(/\//g, "__");
|
|
18
|
-
// 向上找 node_modules;每层重算候选(@types 优先:lodash 等包本体无 index.d.ts)
|
|
19
|
-
for (let i = 0; i < 8; i++) {
|
|
20
|
-
const typesPath = join(dir, "node_modules", "@types", bare);
|
|
21
|
-
if (existsSync(typesPath)) return typesPath;
|
|
22
|
-
const pkgPath = join(dir, "node_modules", pkg);
|
|
23
|
-
if (existsSync(pkgPath)) return pkgPath;
|
|
24
|
-
const parent = resolve(dir, "..");
|
|
25
|
-
if (parent === dir) break;
|
|
26
|
-
dir = parent;
|
|
27
|
-
}
|
|
28
|
-
return undefined;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const SKIP_DIRS = new Set(["node_modules", "test", "tests", "docs", "doc", "examples", "__tests__"]);
|
|
32
|
-
/** 单文件上限:巨型 lib.d.ts 级别拖垮 harvest */
|
|
33
|
-
const MAX_DTS_BYTES = 1_500_000;
|
|
34
|
-
|
|
35
|
-
/** 优先入口:index.d.ts / pkg 名 / lib 入口 */
|
|
36
|
-
function dtsPriority(p: string, root: string): number {
|
|
37
|
-
const base = basename(p);
|
|
38
|
-
const rel = p.slice(root.length);
|
|
39
|
-
if (base === "index.d.ts") return 0;
|
|
40
|
-
if (base === "index.d.mts") return 1;
|
|
41
|
-
if (rel.includes("/types/") && base === "index.d.ts") return 2;
|
|
42
|
-
if (base.endsWith(".d.ts") && !base.includes(".")) return 3; // foo.d.ts
|
|
43
|
-
return 10;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* 递归收集包内 .d.ts(限制数量 + 跳过超大文件 + 入口优先)。
|
|
48
|
-
*/
|
|
49
|
-
export function collectDtsFiles(root: string, maxFiles = 8): string[] {
|
|
50
|
-
const out: string[] = [];
|
|
51
|
-
const walk = (dir: string): void => {
|
|
52
|
-
if (out.length >= maxFiles * 3) return; // 多收一点再排序截断
|
|
53
|
-
let entries: string[];
|
|
54
|
-
try {
|
|
55
|
-
entries = readdirSync(dir);
|
|
56
|
-
} catch {
|
|
57
|
-
return;
|
|
58
|
-
}
|
|
59
|
-
for (const name of entries) {
|
|
60
|
-
if (out.length >= maxFiles * 3) return;
|
|
61
|
-
if (SKIP_DIRS.has(name)) continue;
|
|
62
|
-
const p = join(dir, name);
|
|
63
|
-
let st;
|
|
64
|
-
try {
|
|
65
|
-
st = statSync(p);
|
|
66
|
-
} catch {
|
|
67
|
-
continue;
|
|
68
|
-
}
|
|
69
|
-
if (st.isDirectory()) walk(p);
|
|
70
|
-
else if (name.endsWith(".d.ts") && !name.endsWith(".d.ts.map")) {
|
|
71
|
-
if (st.size > MAX_DTS_BYTES) continue;
|
|
72
|
-
out.push(p);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
};
|
|
76
|
-
walk(root);
|
|
77
|
-
out.sort((a, b) => dtsPriority(a, root) - dtsPriority(b, root) || a.length - b.length);
|
|
78
|
-
return out.slice(0, maxFiles);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/** package.json types/typings 入口(若存在且合理大小) */
|
|
82
|
-
function entryDtsFromPackageJson(root: string): string | undefined {
|
|
83
|
-
const pj = join(root, "package.json");
|
|
84
|
-
if (!existsSync(pj)) return undefined;
|
|
85
|
-
try {
|
|
86
|
-
const raw = JSON.parse(readFileSync(pj, "utf8")) as {
|
|
87
|
-
types?: string;
|
|
88
|
-
typings?: string;
|
|
89
|
-
exports?: Record<string, unknown>;
|
|
90
|
-
};
|
|
91
|
-
const entry = raw.types ?? raw.typings;
|
|
92
|
-
if (typeof entry === "string" && entry.endsWith(".d.ts")) {
|
|
93
|
-
const p = resolve(root, entry);
|
|
94
|
-
if (existsSync(p)) {
|
|
95
|
-
const st = statSync(p);
|
|
96
|
-
if (st.size <= MAX_DTS_BYTES) return p;
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
} catch {
|
|
100
|
-
// ignore
|
|
101
|
-
}
|
|
102
|
-
return undefined;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
export type PackageHarvest = {
|
|
106
|
-
pkg: string;
|
|
107
|
-
root: string;
|
|
108
|
-
dtsFiles: string[];
|
|
109
|
-
env: HarvestedEnv;
|
|
110
|
-
};
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* 从入口 .d.ts 沿 reference path / 相对 import 做 BFS 收集。
|
|
114
|
-
* 适合 @types 包(三斜线引用图);比整树 walk 更贴声明入口。
|
|
115
|
-
*/
|
|
116
|
-
export function collectDtsFromEntry(entry: string, maxFiles = 200): string[] {
|
|
117
|
-
const files: string[] = [];
|
|
118
|
-
const seen = new Set<string>();
|
|
119
|
-
const queue = [entry];
|
|
120
|
-
const REFERENCE_PATH_REGEX = /<reference\s+path=["']([^"']+)["']\s*\/>/g;
|
|
121
|
-
const RELATIVE_FROM_REGEX = /\bfrom\s+["'](\.[^"']+)["']/g;
|
|
122
|
-
|
|
123
|
-
while (queue.length > 0 && files.length < maxFiles) {
|
|
124
|
-
const current = queue.shift()!;
|
|
125
|
-
if (seen.has(current) || !existsSync(current)) continue;
|
|
126
|
-
seen.add(current);
|
|
127
|
-
if (!current.endsWith(".d.ts")) continue;
|
|
128
|
-
files.push(current);
|
|
129
|
-
|
|
130
|
-
let text: string;
|
|
131
|
-
try {
|
|
132
|
-
text = readFileSync(current, "utf-8");
|
|
133
|
-
} catch {
|
|
134
|
-
continue;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
const dir = dirname(current);
|
|
138
|
-
for (const match of text.matchAll(REFERENCE_PATH_REGEX)) {
|
|
139
|
-
queue.push(resolve(dir, match[1]!));
|
|
140
|
-
}
|
|
141
|
-
for (const match of text.matchAll(RELATIVE_FROM_REGEX)) {
|
|
142
|
-
const base = resolve(dir, match[1]!);
|
|
143
|
-
for (const candidate of [`${base}.d.ts`, join(base, "index.d.ts")]) {
|
|
144
|
-
if (existsSync(candidate)) {
|
|
145
|
-
queue.push(candidate);
|
|
146
|
-
break;
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
return files;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
/** harvest 一个 npm 包(或 @types 包) */
|
|
156
|
-
export function harvestPackage(
|
|
157
|
-
pkg: string,
|
|
158
|
-
fromDir?: string,
|
|
159
|
-
maxFiles = 8,
|
|
160
|
-
): PackageHarvest | { error: string } {
|
|
161
|
-
const root = resolvePackageRoot(pkg, fromDir);
|
|
162
|
-
if (!root) return { error: `package not found: ${pkg}` };
|
|
163
|
-
const entry = entryDtsFromPackageJson(root) ?? join(root, "index.d.ts");
|
|
164
|
-
// 入口 BFS 优先(@types 引用图);退化为整树 walk
|
|
165
|
-
let dtsFiles = existsSync(entry) ? collectDtsFromEntry(entry, maxFiles) : [];
|
|
166
|
-
if (dtsFiles.length === 0) {
|
|
167
|
-
const collected = collectDtsFiles(root, maxFiles);
|
|
168
|
-
dtsFiles =
|
|
169
|
-
entry && existsSync(entry) && !collected.includes(entry)
|
|
170
|
-
? [entry, ...collected.filter((f) => f !== entry)].slice(0, maxFiles)
|
|
171
|
-
: collected;
|
|
172
|
-
}
|
|
173
|
-
if (dtsFiles.length === 0) {
|
|
174
|
-
return { error: `no .d.ts under ${root}` };
|
|
175
|
-
}
|
|
176
|
-
const env = harvestDts(dtsFiles);
|
|
177
|
-
return { pkg, root, dtsFiles, env };
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
/** harvest 结果 → 人类可读导出表 */
|
|
181
|
-
export function formatHarvestSummary(h: PackageHarvest): string {
|
|
182
|
-
const lines: string[] = [];
|
|
183
|
-
lines.push(`${h.pkg}: ${h.dtsFiles.length} d.ts, ${h.env.stats.symbols} symbols`);
|
|
184
|
-
const mods = Object.keys(h.env.modules);
|
|
185
|
-
for (const m of mods.slice(0, 5)) {
|
|
186
|
-
const exports = h.env.modules[m]!;
|
|
187
|
-
const names = Object.keys(exports).slice(0, 12);
|
|
188
|
-
lines.push(` module "${m}": ${names.join(", ")}${Object.keys(exports).length > 12 ? "…" : ""}`);
|
|
189
|
-
}
|
|
190
|
-
if (mods.length > 5) lines.push(` … ${mods.length - 5} more modules`);
|
|
191
|
-
return lines.join("\n");
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
/** 取某个导出的 TypeValue 字符串 */
|
|
195
|
-
export function lookupHarvested(
|
|
196
|
-
h: PackageHarvest,
|
|
197
|
-
moduleName: string,
|
|
198
|
-
exportName: string,
|
|
199
|
-
): string | undefined {
|
|
200
|
-
const mod = h.env.modules[moduleName];
|
|
201
|
-
const tv = mod?.[exportName] ?? h.env.globals[exportName];
|
|
202
|
-
if (!tv) return undefined;
|
|
203
|
-
return typeValueToString(tv as TypeValue);
|
|
204
|
-
}
|
package/src/harvest-to-abs.ts
DELETED
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Harvest TypeValue 导出 → AbsModuleExports(供 Abs 模块图注入)。
|
|
3
|
-
* fnSig → absFunction + apply 直接返回声明返回类型(conf=mock)。
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import type { TypeValue } from "@nudojs/core";
|
|
7
|
-
import {
|
|
8
|
-
T,
|
|
9
|
-
type Abs,
|
|
10
|
-
typeValueToAbs,
|
|
11
|
-
confJoin,
|
|
12
|
-
getFnSig,
|
|
13
|
-
absFunction,
|
|
14
|
-
} from "@nudojs/core";
|
|
15
|
-
import type { AbsModuleExports } from "@nudojs/core";
|
|
16
|
-
import { dirname } from "node:path";
|
|
17
|
-
import type { PackageHarvest } from "./harvest-package.ts";
|
|
18
|
-
import { harvestPackageCached } from "./harvest-auto.ts";
|
|
19
|
-
|
|
20
|
-
function markMockConf(a: Abs): Abs {
|
|
21
|
-
a.conf = confJoin(a.conf, "mock");
|
|
22
|
-
return a;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/** 单个 TypeValue 导出 → Abs(可调用) */
|
|
26
|
-
export function harvestedValueToAbs(tv: TypeValue): Abs {
|
|
27
|
-
if (!tv) return markMockConf(typeValueToAbs(T.unknown));
|
|
28
|
-
const sig = getFnSig(tv);
|
|
29
|
-
if (sig) {
|
|
30
|
-
const ret = markMockConf(typeValueToAbs(sig.returnType));
|
|
31
|
-
const params =
|
|
32
|
-
tv.kind === "function" && tv.params?.length
|
|
33
|
-
? tv.params
|
|
34
|
-
: sig.paramTypes.map((_, i) => `_arg${i}`);
|
|
35
|
-
const dummyBody = {
|
|
36
|
-
type: "BlockStatement",
|
|
37
|
-
body: [],
|
|
38
|
-
directives: [],
|
|
39
|
-
} as never;
|
|
40
|
-
return markMockConf(
|
|
41
|
-
absFunction(params, {
|
|
42
|
-
body: dummyBody,
|
|
43
|
-
apply: () => ret,
|
|
44
|
-
}),
|
|
45
|
-
);
|
|
46
|
-
}
|
|
47
|
-
return markMockConf(typeValueToAbs(tv));
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* 把 harvest 的 modules/globals 合成 AbsModuleExports。
|
|
52
|
-
* 键同时登记:原始模块路径、包名、basename(path / @types/path)。
|
|
53
|
-
*/
|
|
54
|
-
export function harvestToAbsModules(
|
|
55
|
-
pkg: string,
|
|
56
|
-
fromDir: string,
|
|
57
|
-
): Record<string, AbsModuleExports> {
|
|
58
|
-
const h = harvestPackageCached(pkg, fromDir);
|
|
59
|
-
if (!h) return {};
|
|
60
|
-
return packageHarvestToAbsModules(pkg, h);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
export function packageHarvestToAbsModules(
|
|
64
|
-
pkg: string,
|
|
65
|
-
h: PackageHarvest,
|
|
66
|
-
): Record<string, AbsModuleExports> {
|
|
67
|
-
const out: Record<string, AbsModuleExports> = {};
|
|
68
|
-
|
|
69
|
-
const convertRecord = (
|
|
70
|
-
rec: Record<string, TypeValue>,
|
|
71
|
-
): Record<string, Abs> => {
|
|
72
|
-
const named: Record<string, Abs> = {};
|
|
73
|
-
for (const [k, v] of Object.entries(rec)) {
|
|
74
|
-
named[k] = harvestedValueToAbs(v);
|
|
75
|
-
}
|
|
76
|
-
return named;
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
const register = (key: string, exports: AbsModuleExports) => {
|
|
80
|
-
if (!out[key]) out[key] = exports;
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
for (const [mod, rec] of Object.entries(h.env.modules)) {
|
|
84
|
-
const named = convertRecord(rec);
|
|
85
|
-
const exports: AbsModuleExports = { named };
|
|
86
|
-
const def = rec["default"];
|
|
87
|
-
if (def) exports.default = harvestedValueToAbs(def);
|
|
88
|
-
register(mod, exports);
|
|
89
|
-
// 包名 / 去掉 @types/ 前缀 / basename
|
|
90
|
-
register(pkg, exports);
|
|
91
|
-
const stripped = mod.replace(/^@types\//, "").replace(/\\/g, "/");
|
|
92
|
-
if (stripped) register(stripped, exports);
|
|
93
|
-
const base = stripped.split("/").filter(Boolean).pop();
|
|
94
|
-
if (base && base !== pkg) register(base, exports);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// globals 也挂到包名(default / namespace 消费)
|
|
98
|
-
const globalNamed = convertRecord(h.env.globals);
|
|
99
|
-
if (Object.keys(globalNamed).length > 0) {
|
|
100
|
-
const existing = out[pkg];
|
|
101
|
-
if (existing) {
|
|
102
|
-
out[pkg] = { named: { ...globalNamed, ...existing.named }, default: existing.default };
|
|
103
|
-
} else {
|
|
104
|
-
out[pkg] = { named: globalNamed };
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
return out;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/** 裸说明符 → Abs 导出表(走 harvest 缓存) */
|
|
112
|
-
export function bareSpecToAbsModules(
|
|
113
|
-
spec: string,
|
|
114
|
-
fromFile: string,
|
|
115
|
-
): AbsModuleExports | undefined {
|
|
116
|
-
// node: 内建交给 env,不 harvest
|
|
117
|
-
if (!spec || spec.startsWith(".") || spec.startsWith("/") || spec.startsWith("node:")) {
|
|
118
|
-
return undefined;
|
|
119
|
-
}
|
|
120
|
-
const parts = spec.split("/");
|
|
121
|
-
const pkg = spec.startsWith("@")
|
|
122
|
-
? parts.length >= 2
|
|
123
|
-
? `${parts[0]}/${parts[1]}`
|
|
124
|
-
: undefined
|
|
125
|
-
: parts[0];
|
|
126
|
-
if (!pkg) return undefined;
|
|
127
|
-
const table = harvestToAbsModules(pkg, dirname(fromFile));
|
|
128
|
-
return table[spec] ?? table[pkg];
|
|
129
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1,150 +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
|
-
getHoverAtPosition,
|
|
23
|
-
type HoverInfo,
|
|
24
|
-
getCompletionsAtPosition,
|
|
25
|
-
getCasesForFile,
|
|
26
|
-
buildModuleGraph,
|
|
27
|
-
type ModuleGraphCache,
|
|
28
|
-
computeDirtySet,
|
|
29
|
-
topoSortDirty,
|
|
30
|
-
} from "./analyzer.ts";
|
|
31
|
-
|
|
32
|
-
export { collectAbsInlays, type AbsInlay } from "@nudojs/core";
|
|
33
|
-
|
|
34
|
-
export {
|
|
35
|
-
serializeInferJson,
|
|
36
|
-
type InferJson,
|
|
37
|
-
type InferJsonCase,
|
|
38
|
-
type InferJsonFunction,
|
|
39
|
-
} from "./infer-json.ts";
|
|
40
|
-
|
|
41
|
-
export { isNudoTargetPath } from "./target-path.ts";
|
|
42
|
-
export { defaultLoadModule, type LoadModule } from "./load-module.ts";
|
|
43
|
-
export {
|
|
44
|
-
collectStaticImports,
|
|
45
|
-
analyzeExportsFromSource,
|
|
46
|
-
collectDependencySpecs,
|
|
47
|
-
type ModuleExports,
|
|
48
|
-
} from "./static-imports.ts";
|
|
49
|
-
export {
|
|
50
|
-
harvestPackage,
|
|
51
|
-
collectDtsFromEntry,
|
|
52
|
-
formatHarvestSummary,
|
|
53
|
-
lookupHarvested,
|
|
54
|
-
resolvePackageRoot,
|
|
55
|
-
type PackageHarvest,
|
|
56
|
-
} from "./harvest-package.ts";
|
|
57
|
-
export {
|
|
58
|
-
barePackageName,
|
|
59
|
-
collectBarePackages,
|
|
60
|
-
autoHarvestModules,
|
|
61
|
-
harvestPackageCached,
|
|
62
|
-
clearHarvestCache,
|
|
63
|
-
} from "./harvest-auto.ts";
|
|
64
|
-
export {
|
|
65
|
-
evalAbsModuleGraph,
|
|
66
|
-
evalProgramAbsWithModules,
|
|
67
|
-
collectAbsBindingsFromGraph,
|
|
68
|
-
defaultAbsLoadModule,
|
|
69
|
-
clearAbsModuleCache,
|
|
70
|
-
evictAbsModuleCacheFiles,
|
|
71
|
-
type AbsModuleGraphResult,
|
|
72
|
-
type AbsGraphOptions,
|
|
73
|
-
type AbsModuleLoadIssue,
|
|
74
|
-
type AbsModuleCacheEntry,
|
|
75
|
-
} from "./abs-modules-graph.ts";
|
|
76
|
-
export {
|
|
77
|
-
harvestToAbsModules,
|
|
78
|
-
packageHarvestToAbsModules,
|
|
79
|
-
bareSpecToAbsModules,
|
|
80
|
-
harvestedValueToAbs,
|
|
81
|
-
} from "./harvest-to-abs.ts";
|
|
82
|
-
export {
|
|
83
|
-
isBPathCapable,
|
|
84
|
-
tryRunBPath,
|
|
85
|
-
tryBPathCall,
|
|
86
|
-
tryBPathCallFull,
|
|
87
|
-
clearBPathCache,
|
|
88
|
-
evictBPathCacheForFiles,
|
|
89
|
-
collectBPathReplacements,
|
|
90
|
-
collectEnvGlobals,
|
|
91
|
-
collectEnvModules,
|
|
92
|
-
type BPathRunResult,
|
|
93
|
-
} from "./bpath-run.ts";
|
|
94
|
-
export {
|
|
95
|
-
clearAnalysisFileCache,
|
|
96
|
-
getAnalysisFileCacheSize,
|
|
97
|
-
evictAnalysisFileCacheForFiles,
|
|
98
|
-
} from "./analysis-file-cache.ts";
|
|
99
|
-
export {
|
|
100
|
-
clearFnAnalysisCache,
|
|
101
|
-
evictFnAnalysisCacheForFiles,
|
|
102
|
-
} from "./fn-analysis-cache.ts";
|
|
103
|
-
export {
|
|
104
|
-
evictAnalysisCachesForFiles,
|
|
105
|
-
clearAnalysisSessionCaches,
|
|
106
|
-
resetAllAnalysisCaches,
|
|
107
|
-
} from "./session-cache.ts";
|
|
108
|
-
export { envValueToAbs } from "./env-to-abs.ts";
|
|
109
|
-
export type { BMemberDiag } from "@nudojs/core";
|
|
110
|
-
|
|
111
|
-
export {
|
|
112
|
-
collectBPathDiagnostics,
|
|
113
|
-
type BPathDiagnostics,
|
|
114
|
-
type BPathUnreachable,
|
|
115
|
-
type BPathBuiltinUnknown,
|
|
116
|
-
} from "./bpath-diagnostics.ts";
|
|
117
|
-
export {
|
|
118
|
-
harvestNodeTypes,
|
|
119
|
-
summarizeNodeEnv,
|
|
120
|
-
type NodeEnvResult,
|
|
121
|
-
} from "./harvest-node.ts";
|
|
122
|
-
|
|
123
|
-
export {
|
|
124
|
-
buildSemanticTokens,
|
|
125
|
-
encodeSemanticTokens,
|
|
126
|
-
SEMANTIC_TOKEN_TYPES,
|
|
127
|
-
SEMANTIC_TOKEN_MODIFIERS,
|
|
128
|
-
type SemanticToken,
|
|
129
|
-
} from "./semantic-tokens.ts";
|
|
130
|
-
|
|
131
|
-
export {
|
|
132
|
-
typeValueToTSType,
|
|
133
|
-
generateDts,
|
|
134
|
-
generateFunctionDtsLines,
|
|
135
|
-
} from "./dts-generator.ts";
|
|
136
|
-
|
|
137
|
-
export { typeValueToZodSchema } from "./schema-generator.ts";
|
|
138
|
-
export { generateGuardFunction, generateGuardFunctionFromAbs } from "./guard-generator.ts";
|
|
139
|
-
|
|
140
|
-
export {
|
|
141
|
-
serializeCaseArg,
|
|
142
|
-
buildCaseDirective,
|
|
143
|
-
stripGeneratedCaseDirectives,
|
|
144
|
-
insertGeneratedCaseDirectives,
|
|
145
|
-
unifiedDiff,
|
|
146
|
-
type EmitSkipReason,
|
|
147
|
-
type EmitResult,
|
|
148
|
-
} from "./case-emitter.ts";
|
|
149
|
-
|
|
150
|
-
export { mockDirectivesToAbsSeeds, type AbsMockSeeds } from "./mock-abs.ts";
|
package/src/infer-json.ts
DELETED
|
@@ -1,137 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `nudo infer --json` 稳定契约 v1(CI / Agent)。
|
|
3
|
-
*
|
|
4
|
-
* 字段只增不改语义:
|
|
5
|
-
* - ext_*:TypeValue 投影字符串(有损,兼容)
|
|
6
|
-
* - intension.abs*:无损 Abs 展示(主线)
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import { typeValueToString, type TypeValue } from "@nudojs/core";
|
|
10
|
-
import type { AnalysisResult, CaseResult, FunctionAnalysis, SourceLocation } from "./analyzer.ts";
|
|
11
|
-
|
|
12
|
-
export type InferJsonCase = {
|
|
13
|
-
name: string;
|
|
14
|
-
/** TypeValue 投影(有损外延) */
|
|
15
|
-
args: string[];
|
|
16
|
-
result: string;
|
|
17
|
-
throws: string | null;
|
|
18
|
-
source: string | null;
|
|
19
|
-
aggregatedFrom?: number;
|
|
20
|
-
/** 无损内涵(Abs);无则省略 */
|
|
21
|
-
intension?: {
|
|
22
|
-
display?: string;
|
|
23
|
-
abs?: string;
|
|
24
|
-
absMultiline?: string;
|
|
25
|
-
term?: string;
|
|
26
|
-
pred?: string;
|
|
27
|
-
conf?: string;
|
|
28
|
-
};
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
export type InferJsonFunction = {
|
|
32
|
-
name: string;
|
|
33
|
-
loc: SourceLocation;
|
|
34
|
-
entryOnly: boolean;
|
|
35
|
-
noDeclaration?: boolean;
|
|
36
|
-
cases: InferJsonCase[];
|
|
37
|
-
combined?: string;
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
export type InferJson = {
|
|
41
|
-
version: 1;
|
|
42
|
-
file: string;
|
|
43
|
-
summary: {
|
|
44
|
-
functions: number;
|
|
45
|
-
externalFunctions: number;
|
|
46
|
-
cases: number;
|
|
47
|
-
diagnostics: number;
|
|
48
|
-
};
|
|
49
|
-
functions: InferJsonFunction[];
|
|
50
|
-
externalFunctions?: Array<{
|
|
51
|
-
name: string;
|
|
52
|
-
fromModule?: string;
|
|
53
|
-
cases: InferJsonCase[];
|
|
54
|
-
}>;
|
|
55
|
-
diagnostics: Array<{
|
|
56
|
-
range: SourceLocation;
|
|
57
|
-
severity: string;
|
|
58
|
-
message: string;
|
|
59
|
-
code?: string;
|
|
60
|
-
suggestions?: string[];
|
|
61
|
-
tags?: string[];
|
|
62
|
-
origin?: { line: number; column: number };
|
|
63
|
-
}>;
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
function mapCase(c: CaseResult): InferJsonCase {
|
|
67
|
-
const out: InferJsonCase = {
|
|
68
|
-
name: c.name,
|
|
69
|
-
args: c.args.map((a: TypeValue) => typeValueToString(a)),
|
|
70
|
-
result: typeValueToString(c.result),
|
|
71
|
-
throws: c.throws.kind !== "never" ? typeValueToString(c.throws) : null,
|
|
72
|
-
source: c.source ?? null,
|
|
73
|
-
};
|
|
74
|
-
if (c.aggregatedFrom !== undefined) out.aggregatedFrom = c.aggregatedFrom;
|
|
75
|
-
if (c.intension) {
|
|
76
|
-
const i = c.intension;
|
|
77
|
-
out.intension = {
|
|
78
|
-
...(i.display !== undefined ? { display: i.display } : {}),
|
|
79
|
-
...(i.abs !== undefined ? { abs: i.abs } : {}),
|
|
80
|
-
...(i.absMultiline !== undefined ? { absMultiline: i.absMultiline } : {}),
|
|
81
|
-
...(i.term !== undefined ? { term: i.term } : {}),
|
|
82
|
-
...(i.pred !== undefined ? { pred: i.pred } : {}),
|
|
83
|
-
...(i.conf !== undefined ? { conf: i.conf } : {}),
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
return out;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
function mapFunction(f: FunctionAnalysis): InferJsonFunction {
|
|
90
|
-
const out: InferJsonFunction = {
|
|
91
|
-
name: f.name,
|
|
92
|
-
loc: f.loc,
|
|
93
|
-
entryOnly: f.entryOnly ?? false,
|
|
94
|
-
cases: f.cases.map(mapCase),
|
|
95
|
-
};
|
|
96
|
-
if (f.noDeclaration) out.noDeclaration = true;
|
|
97
|
-
if (f.combined) out.combined = typeValueToString(f.combined);
|
|
98
|
-
return out;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
export function serializeInferJson(
|
|
102
|
-
result: AnalysisResult,
|
|
103
|
-
file: string,
|
|
104
|
-
): InferJson {
|
|
105
|
-
const functions = result.functions.map(mapFunction);
|
|
106
|
-
const external = result.externalFunctions?.map((f) => ({
|
|
107
|
-
name: f.name,
|
|
108
|
-
fromModule: f.fromModule,
|
|
109
|
-
cases: f.cases.map(mapCase),
|
|
110
|
-
}));
|
|
111
|
-
const caseCount =
|
|
112
|
-
functions.reduce((n, f) => n + f.cases.length, 0) +
|
|
113
|
-
(external ?? []).reduce((n, f) => n + f.cases.length, 0);
|
|
114
|
-
|
|
115
|
-
const json: InferJson = {
|
|
116
|
-
version: 1,
|
|
117
|
-
file,
|
|
118
|
-
summary: {
|
|
119
|
-
functions: functions.length,
|
|
120
|
-
externalFunctions: external?.length ?? 0,
|
|
121
|
-
cases: caseCount,
|
|
122
|
-
diagnostics: result.diagnostics.length,
|
|
123
|
-
},
|
|
124
|
-
functions,
|
|
125
|
-
diagnostics: result.diagnostics.map((d) => ({
|
|
126
|
-
range: d.range,
|
|
127
|
-
severity: d.severity,
|
|
128
|
-
message: d.message,
|
|
129
|
-
...(d.code !== undefined ? { code: d.code } : {}),
|
|
130
|
-
...(d.suggestions ? { suggestions: d.suggestions } : {}),
|
|
131
|
-
...(d.tags ? { tags: d.tags } : {}),
|
|
132
|
-
...(d.origin ? { origin: d.origin } : {}),
|
|
133
|
-
})),
|
|
134
|
-
};
|
|
135
|
-
if (external) json.externalFunctions = external;
|
|
136
|
-
return json;
|
|
137
|
-
}
|
package/src/load-module.ts
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 相对/绝对 specifier → 模块源码。
|
|
3
|
-
* CLI / LSP / vite / check 共用同一扩展名表,避免门禁结果分叉。
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { existsSync, statSync, readFileSync } from "node:fs";
|
|
7
|
-
import { dirname, resolve, join } from "node:path";
|
|
8
|
-
|
|
9
|
-
export type LoadModule = (spec: string, fromFile: string) => string | undefined;
|
|
10
|
-
|
|
11
|
-
/** 默认 loadModule:支持 .js/.mjs/.ts 与 index 入口 */
|
|
12
|
-
export function defaultLoadModule(spec: string, fromFile: string): string | undefined {
|
|
13
|
-
if (!spec.startsWith(".") && !spec.startsWith("/")) return undefined;
|
|
14
|
-
try {
|
|
15
|
-
const base = dirname(resolve(fromFile));
|
|
16
|
-
const p = resolve(base, spec);
|
|
17
|
-
for (const cand of [
|
|
18
|
-
p,
|
|
19
|
-
`${p}.js`,
|
|
20
|
-
`${p}.mjs`,
|
|
21
|
-
`${p}.ts`,
|
|
22
|
-
join(p, "index.js"),
|
|
23
|
-
join(p, "index.mjs"),
|
|
24
|
-
join(p, "index.ts"),
|
|
25
|
-
]) {
|
|
26
|
-
if (existsSync(cand) && !statSync(cand).isDirectory()) {
|
|
27
|
-
return readFileSync(cand, "utf-8");
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
return undefined;
|
|
31
|
-
} catch {
|
|
32
|
-
return undefined;
|
|
33
|
-
}
|
|
34
|
-
}
|