@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/static-imports.ts
DELETED
|
@@ -1,241 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Host 侧多文件解析(非代数层)。
|
|
3
|
-
*
|
|
4
|
-
* 分层:
|
|
5
|
-
* algebra = 纯抽象解释:吃 AST / source string,不碰 fs/path
|
|
6
|
-
* host = 读文件、解析相对 import/require、把 source 喂给代数
|
|
7
|
-
* Node/打包器 = 真正的模块加载与执行
|
|
8
|
-
*
|
|
9
|
-
* 引擎不做 bundler;这里只为「跨文件类型事实」做最薄的静态扫描。
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
import { parse } from "@nudojs/parser";
|
|
13
|
-
import type { File, Node } from "@babel/types";
|
|
14
|
-
import { readFileSync, existsSync } from "node:fs";
|
|
15
|
-
import { resolve, dirname, join } from "node:path";
|
|
16
|
-
import { generalizeFromAst, type PolyFn } from "@nudojs/core";
|
|
17
|
-
|
|
18
|
-
export type ModuleExports = {
|
|
19
|
-
path: string;
|
|
20
|
-
named: Map<string, string>;
|
|
21
|
-
defaultExport?: string;
|
|
22
|
-
source: string;
|
|
23
|
-
poly: Map<string, PolyFn>;
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
function resolveRelative(fromFile: string, spec: string): string | undefined {
|
|
27
|
-
if (!spec.startsWith(".") && !spec.startsWith("/")) return undefined;
|
|
28
|
-
const base = resolve(dirname(fromFile), spec);
|
|
29
|
-
for (const cand of [
|
|
30
|
-
base,
|
|
31
|
-
base + ".js",
|
|
32
|
-
base + ".cjs",
|
|
33
|
-
base + ".mjs",
|
|
34
|
-
base + ".ts",
|
|
35
|
-
base + ".mts",
|
|
36
|
-
base + ".cts",
|
|
37
|
-
join(base, "index.js"),
|
|
38
|
-
join(base, "index.cjs"),
|
|
39
|
-
join(base, "index.mjs"),
|
|
40
|
-
join(base, "index.ts"),
|
|
41
|
-
]) {
|
|
42
|
-
if (existsSync(cand)) return cand;
|
|
43
|
-
}
|
|
44
|
-
return undefined;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/** 从 AST 收集静态相对依赖(ESM import + CJS require) */
|
|
48
|
-
export function collectDependencySpecs(ast: File): string[] {
|
|
49
|
-
const specs: string[] = [];
|
|
50
|
-
for (const stmt of ast.program.body) {
|
|
51
|
-
if (stmt.type === "ImportDeclaration") {
|
|
52
|
-
specs.push(stmt.source.value);
|
|
53
|
-
}
|
|
54
|
-
if (stmt.type === "ExportNamedDeclaration" && stmt.source) {
|
|
55
|
-
specs.push(stmt.source.value);
|
|
56
|
-
}
|
|
57
|
-
if (stmt.type === "ExportAllDeclaration" && stmt.source) {
|
|
58
|
-
specs.push(stmt.source.value);
|
|
59
|
-
}
|
|
60
|
-
// require("...") / require.resolve
|
|
61
|
-
collectRequires(stmt, specs);
|
|
62
|
-
}
|
|
63
|
-
return specs;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
function collectRequires(node: Node, out: string[]): void {
|
|
67
|
-
const visit = (n: unknown): void => {
|
|
68
|
-
if (!n || typeof n !== "object") return;
|
|
69
|
-
const obj = n as {
|
|
70
|
-
type?: string;
|
|
71
|
-
callee?: { type?: string; name?: string };
|
|
72
|
-
arguments?: Array<{ type?: string; value?: unknown }>;
|
|
73
|
-
[k: string]: unknown;
|
|
74
|
-
};
|
|
75
|
-
if (
|
|
76
|
-
obj.type === "CallExpression" &&
|
|
77
|
-
obj.callee?.type === "Identifier" &&
|
|
78
|
-
obj.callee.name === "require" &&
|
|
79
|
-
obj.arguments?.[0]?.type === "StringLiteral"
|
|
80
|
-
) {
|
|
81
|
-
const spec = obj.arguments[0].value;
|
|
82
|
-
if (typeof spec === "string") out.push(spec);
|
|
83
|
-
}
|
|
84
|
-
for (const key of Object.keys(obj)) {
|
|
85
|
-
if (key === "loc" || key === "start" || key === "end") continue;
|
|
86
|
-
const v = obj[key];
|
|
87
|
-
if (Array.isArray(v)) v.forEach(visit);
|
|
88
|
-
else if (v && typeof v === "object") visit(v);
|
|
89
|
-
}
|
|
90
|
-
};
|
|
91
|
-
visit(node);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/** 分析单文件导出 + 内涵签名(source 由 host 提供) */
|
|
95
|
-
export function analyzeExportsFromSource(
|
|
96
|
-
filePath: string,
|
|
97
|
-
source: string,
|
|
98
|
-
): ModuleExports {
|
|
99
|
-
const file = parse(source);
|
|
100
|
-
const named = new Map<string, string>();
|
|
101
|
-
let defaultExport: string | undefined;
|
|
102
|
-
const poly = new Map<string, PolyFn>();
|
|
103
|
-
|
|
104
|
-
for (const stmt of file.program.body) {
|
|
105
|
-
let decl: Node = stmt;
|
|
106
|
-
if (stmt.type === "ExportNamedDeclaration" && stmt.declaration) {
|
|
107
|
-
decl = stmt.declaration;
|
|
108
|
-
}
|
|
109
|
-
if (decl.type === "FunctionDeclaration" && decl.id) {
|
|
110
|
-
named.set(decl.id.name, decl.id.name);
|
|
111
|
-
}
|
|
112
|
-
if (decl.type === "VariableDeclaration") {
|
|
113
|
-
for (const d of decl.declarations) {
|
|
114
|
-
if (d.id.type === "Identifier") named.set(d.id.name, d.id.name);
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
if (decl.type === "ClassDeclaration" && decl.id) {
|
|
118
|
-
named.set(decl.id.name, decl.id.name);
|
|
119
|
-
}
|
|
120
|
-
if (stmt.type === "ExportDefaultDeclaration") {
|
|
121
|
-
const d = stmt.declaration;
|
|
122
|
-
if (d.type === "FunctionDeclaration" && d.id) defaultExport = d.id.name;
|
|
123
|
-
if (d.type === "Identifier") defaultExport = d.name;
|
|
124
|
-
}
|
|
125
|
-
// CJS: exports.foo = fn / module.exports = fn / module.exports = { a, b }
|
|
126
|
-
collectCjsExports(stmt, named, (n) => {
|
|
127
|
-
defaultExport = n;
|
|
128
|
-
});
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
for (const name of named.values()) {
|
|
132
|
-
const g = generalizeFromAst(name, source);
|
|
133
|
-
if (g) poly.set(name, g);
|
|
134
|
-
}
|
|
135
|
-
if (defaultExport) {
|
|
136
|
-
const g = generalizeFromAst(defaultExport, source);
|
|
137
|
-
if (g) poly.set("default", g);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
return { path: filePath, named, defaultExport, source, poly };
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
function collectCjsExports(
|
|
144
|
-
stmt: Node,
|
|
145
|
-
named: Map<string, string>,
|
|
146
|
-
setDefault: (name: string) => void,
|
|
147
|
-
): void {
|
|
148
|
-
const visit = (n: unknown): void => {
|
|
149
|
-
if (!n || typeof n !== "object") return;
|
|
150
|
-
const obj = n as Record<string, unknown> & { type?: string };
|
|
151
|
-
if (obj.type !== "AssignmentExpression") {
|
|
152
|
-
for (const key of Object.keys(obj)) {
|
|
153
|
-
if (key === "loc" || key === "start" || key === "end") continue;
|
|
154
|
-
const v = obj[key];
|
|
155
|
-
if (Array.isArray(v)) v.forEach(visit);
|
|
156
|
-
else if (v && typeof v === "object") visit(v);
|
|
157
|
-
}
|
|
158
|
-
return;
|
|
159
|
-
}
|
|
160
|
-
const left = obj.left as {
|
|
161
|
-
type?: string;
|
|
162
|
-
object?: { type?: string; name?: string };
|
|
163
|
-
property?: { type?: string; name?: string; value?: string };
|
|
164
|
-
};
|
|
165
|
-
const right = obj.right as Record<string, unknown> & { type?: string };
|
|
166
|
-
|
|
167
|
-
// exports.foo = ...
|
|
168
|
-
if (
|
|
169
|
-
left?.type === "MemberExpression" &&
|
|
170
|
-
left.object?.type === "Identifier" &&
|
|
171
|
-
left.object.name === "exports" &&
|
|
172
|
-
left.property?.type === "Identifier" &&
|
|
173
|
-
left.property.name
|
|
174
|
-
) {
|
|
175
|
-
named.set(left.property.name, left.property.name);
|
|
176
|
-
}
|
|
177
|
-
// module.exports = fnName
|
|
178
|
-
if (
|
|
179
|
-
left?.type === "MemberExpression" &&
|
|
180
|
-
left.object?.type === "Identifier" &&
|
|
181
|
-
left.object.name === "module" &&
|
|
182
|
-
left.property?.type === "Identifier" &&
|
|
183
|
-
left.property.name === "exports"
|
|
184
|
-
) {
|
|
185
|
-
if (right?.type === "Identifier" && typeof right.name === "string") {
|
|
186
|
-
named.set(right.name, right.name);
|
|
187
|
-
setDefault(right.name);
|
|
188
|
-
}
|
|
189
|
-
// module.exports = { foo, bar: baz }
|
|
190
|
-
if (right?.type === "ObjectExpression") {
|
|
191
|
-
const props = right.properties as Array<Record<string, unknown>>;
|
|
192
|
-
for (const p of props) {
|
|
193
|
-
if (p.type !== "ObjectProperty") continue;
|
|
194
|
-
const key = p.key as { type?: string; name?: string; value?: string };
|
|
195
|
-
const val = p.value as { type?: string; name?: string };
|
|
196
|
-
const exportName =
|
|
197
|
-
key?.type === "Identifier" ? key.name : key?.type === "StringLiteral" ? key.value : undefined;
|
|
198
|
-
if (exportName) named.set(exportName, exportName);
|
|
199
|
-
if (val?.type === "Identifier" && val.name && exportName) {
|
|
200
|
-
// exported binding may differ from local name — generalize uses local
|
|
201
|
-
// keep exportName as key; generalizeFromAst(exportName) may fail if local differs
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
};
|
|
207
|
-
visit(stmt);
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
/**
|
|
211
|
-
* 从入口文件沿静态相对 import/require 收集(仅类型事实,不是运行时加载器)。
|
|
212
|
-
* bare specifier(npm 包)跳过——交给 harvest / env。
|
|
213
|
-
*/
|
|
214
|
-
export function collectStaticImports(
|
|
215
|
-
entryFile: string,
|
|
216
|
-
maxDepth = 8,
|
|
217
|
-
): Map<string, ModuleExports> {
|
|
218
|
-
const graph = new Map<string, ModuleExports>();
|
|
219
|
-
const queue: Array<{ file: string; depth: number }> = [
|
|
220
|
-
{ file: resolve(entryFile), depth: 0 },
|
|
221
|
-
];
|
|
222
|
-
const seen = new Set<string>();
|
|
223
|
-
|
|
224
|
-
while (queue.length > 0) {
|
|
225
|
-
const { file, depth } = queue.shift()!;
|
|
226
|
-
if (seen.has(file) || depth > maxDepth) continue;
|
|
227
|
-
seen.add(file);
|
|
228
|
-
if (!existsSync(file)) continue;
|
|
229
|
-
|
|
230
|
-
const source = readFileSync(file, "utf8");
|
|
231
|
-
const mod = analyzeExportsFromSource(file, source);
|
|
232
|
-
graph.set(file, mod);
|
|
233
|
-
|
|
234
|
-
const ast: File = parse(source);
|
|
235
|
-
for (const spec of collectDependencySpecs(ast)) {
|
|
236
|
-
const resolved = resolveRelative(file, spec);
|
|
237
|
-
if (resolved) queue.push({ file: resolved, depth: depth + 1 });
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
return graph;
|
|
241
|
-
}
|
package/src/target-path.ts
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* nudo 推断目标文件判定(纯扩展名规则,路径无需存在)。
|
|
3
|
-
*
|
|
4
|
-
* 规则:.js / .mjs / .ts 可作为推断目标;其余扩展(.cjs/.tsx/.jsx/.mts/.d.ts…)
|
|
5
|
-
* 一律 false。两类显式排除:
|
|
6
|
-
* - .d.ts —— 类型声明文件(harvester 的输入),不是可求值的实现源码;
|
|
7
|
-
* - .tsx / .jsx —— JSX 构造的求值超出 nudo 推断器范围。
|
|
8
|
-
*
|
|
9
|
-
* 消费方:CLI 的 collectNudoFiles/watch 过滤/doctor 目录展开(.ts 放开后统一
|
|
10
|
-
* 走本函数,避免各处手写 endsWith 漂移),以及 LSP 的 isNudoFile(接线由
|
|
11
|
-
* LSP 侧负责)。
|
|
12
|
-
*/
|
|
13
|
-
export function isNudoTargetPath(path: string): boolean {
|
|
14
|
-
const lower = path.toLowerCase();
|
|
15
|
-
if (lower.endsWith(".d.ts")) return false; // 类型声明,非推断目标
|
|
16
|
-
return lower.endsWith(".js") || lower.endsWith(".mjs") || lower.endsWith(".ts");
|
|
17
|
-
}
|
package/tsconfig.json
DELETED