@nudojs/service 5.0.0-beta.0 → 5.0.0-beta.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/README.md +7 -12
- package/dist/{analysis-CSXrOVlg.d.ts → analysis-_DlXLC-L.d.ts} +17 -3
- package/dist/analysis.d.ts +3 -2
- package/dist/analysis.js +9 -5
- package/dist/{analyzer-types-JyJiCt8w.d.ts → analyzer-types-CfBrPK9L.d.ts} +1 -1
- package/dist/{chunk-LFZRUXGK.js → chunk-EG6FYQLI.js} +1 -1
- package/dist/chunk-J2PUE4NV.js +235 -0
- package/dist/{chunk-QAFMPM2E.js → chunk-NQXAF4LJ.js} +2277 -2225
- package/dist/{chunk-YLALZXTZ.js → chunk-ZXVAX7DE.js} +255 -11
- package/dist/{interface-BGlP7aIk.d.ts → emit/index.d.ts} +258 -18
- package/dist/{chunk-HEU4WON5.js → emit/index.js} +1627 -299
- package/dist/evaluator/evaluator-api.d.ts +1 -1
- package/dist/evaluator/evaluator-api.js +5 -5
- package/dist/index.d.ts +17 -19
- package/dist/index.js +188 -197
- package/dist/what-if-mIo7I5Ii.d.ts +21 -0
- package/package.json +9 -25
- package/dist/case.d.ts +0 -124
- package/dist/case.js +0 -18
- package/dist/chunk-6IZR4ZYJ.js +0 -1107
- package/dist/chunk-E4N4A4JV.js +0 -651
- package/dist/chunk-K3ZPOTP2.js +0 -199
- package/dist/chunk-PVJIMQRI.js +0 -246
- package/dist/chunk-QYRH7Z2Q.js +0 -89
- package/dist/chunk-U7JYTRIB.js +0 -888
- package/dist/chunk-YLVZMHWC.js +0 -364
- package/dist/dts.d.ts +0 -142
- package/dist/dts.js +0 -30
- package/dist/harvest.d.ts +0 -254
- package/dist/harvest.js +0 -75
- package/dist/interface.d.ts +0 -3
- package/dist/interface.js +0 -43
- package/dist/lsp.d.ts +0 -103
- package/dist/lsp.js +0 -36
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @nudojs/service
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Nudo analysis core and emit products: Abs-native file analysis, evaluator host API, interface/dts/schema/guard projections, and session caches.
|
|
4
4
|
|
|
5
5
|
## What is Nudo?
|
|
6
6
|
|
|
@@ -8,28 +8,23 @@ Nudo is a type inference engine for JavaScript. The type system is Abs (`shape
|
|
|
8
8
|
|
|
9
9
|
## This package
|
|
10
10
|
|
|
11
|
-
`@nudojs/service` provides the
|
|
11
|
+
`@nudojs/service` provides the analysis core used by CLI, editor extensions, and build tools, plus the emit faces that project Abs to dts/schema/guard/interface.
|
|
12
12
|
|
|
13
13
|
Production evaluation is **Abs-native B-path** (`evalAbsModuleGraph` + `runTranspiled`); the TypeValue AST interpreter is gone. Prefer a focused subpath over the full barrel:
|
|
14
14
|
|
|
15
15
|
| Subpath | Face |
|
|
16
16
|
|---|---|
|
|
17
17
|
| `@nudojs/service/analysis` | File analysis, diagnostics, call records, Abs module-graph eval |
|
|
18
|
-
| `@nudojs/service/interface` | Interface / contract product (surface, emit, draft, derive) |
|
|
19
|
-
| `@nudojs/service/dts` | Extensional projections: dts / schema / standard / guard |
|
|
20
|
-
| `@nudojs/service/case` | Debug case reports + case directive emit (`nudo test`) |
|
|
21
|
-
| `@nudojs/service/lsp` | IDE surface (hover, completions, semantic tokens, inlays) |
|
|
22
|
-
| `@nudojs/service/harvest` | `@types` → Abs env harvesting |
|
|
23
18
|
| `@nudojs/service/evaluator` | Host API surface (env/config/CallRecord) — not the eval engine |
|
|
24
|
-
| `@nudojs/service` | Full barrel (stable;
|
|
19
|
+
| `@nudojs/service` | Full barrel (stable; analysis face) |
|
|
20
|
+
|
|
21
|
+
Emit products live in `@nudojs/service/emit` (interface/contract, dts, schema, guard, case reports). IDE surface lives in `@nudojs/lsp`; `@types` harvest in `@nudojs/harvester`.
|
|
25
22
|
|
|
26
23
|
Highlights:
|
|
27
24
|
|
|
28
25
|
- **File analysis** — `analyzeFile` returns diagnostics, function analyses, and case results
|
|
29
|
-
- **
|
|
30
|
-
- **
|
|
31
|
-
- **Schema projection** — `absToSchemaSource` / `projectAbsToSchema` produce dialect schema source
|
|
32
|
-
- **Guard generation** — `generateGuardFunction` produces zero-dependency runtime type guards
|
|
26
|
+
- **Module graph** — `evalAbsModuleGraph` evaluates a file's import closure as Abs
|
|
27
|
+
- **Session caches** — analysis / fn / B-path caches with eviction and project-config limits
|
|
33
28
|
|
|
34
29
|
## Install
|
|
35
30
|
|
|
@@ -1,10 +1,16 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { S as SourceLocation, a as AnalyzeLoadModule, D as DirectiveCaseMode, A as AnalysisResult } from './analyzer-types-CfBrPK9L.js';
|
|
2
|
+
import { parse } from '@nudojs/parser';
|
|
3
|
+
import { Node } from '@babel/types';
|
|
2
4
|
import { C as CallRecord } from './call-record-CkyCFkT9.js';
|
|
3
5
|
import { Abs, AbsModuleExports, BCallRecord, Phi, TranspiledCallResult } from '@nudojs/core';
|
|
4
|
-
import { Node } from '@babel/types';
|
|
5
6
|
import { BMemberDiag } from '@nudojs/core/internal';
|
|
6
7
|
import { D as DiagnosticsLevel, A as AnalysisConfig } from './config-DDB588oA.js';
|
|
7
8
|
|
|
9
|
+
declare function resolveModule(source: string, fromDir: string): {
|
|
10
|
+
ast: ReturnType<typeof parse>;
|
|
11
|
+
filePath: string;
|
|
12
|
+
json?: unknown;
|
|
13
|
+
} | null;
|
|
8
14
|
/** mtime 边缓存:key 为文件路径,edges 为已抽取的相对 import 边(与 buildModuleGraph 返回语义一致)。 */
|
|
9
15
|
type ModuleGraphCache = Map<string, {
|
|
10
16
|
mtimeMs: number;
|
|
@@ -21,6 +27,14 @@ declare function computeDirtySet(dependents: Map<string, Set<string>>, changedFi
|
|
|
21
27
|
/** Topological order with dependencies before dependents (only imports edges internal to dirty; cycles tolerated — remaining files appended in arbitrary order). */
|
|
22
28
|
declare function topoSortDirty(imports: Map<string, Set<string>>, dirty: string[]): string[];
|
|
23
29
|
|
|
30
|
+
/**
|
|
31
|
+
* AST 辅助:函数收集 / 形参 / 定位 / 节点 Abs 表。
|
|
32
|
+
* 自 analyzer.ts 机械拆出;语义未改。
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
declare function locFromNode(node: Node): SourceLocation;
|
|
36
|
+
|
|
37
|
+
declare function collectEnvNames(filePath: string, source: string, includeProject: boolean): string[];
|
|
24
38
|
/**
|
|
25
39
|
* 调用点发现(阶段一):在"使用现场"文件(测试 / 上层应用)中求值
|
|
26
40
|
* 顶层代码,收集它对(外部模块导出的)函数的调用记录。每条记录带
|
|
@@ -264,4 +278,4 @@ declare function hasNudoDirectives(source: string): boolean;
|
|
|
264
278
|
*/
|
|
265
279
|
declare function shouldAnalyzeFile(filePath: string, source: string | undefined, config?: AnalysisConfig): boolean;
|
|
266
280
|
|
|
267
|
-
export { type AbsGraphOptions as A, type BPathRunResult as B,
|
|
281
|
+
export { type AbsGraphOptions as A, type BPathRunResult as B, locFromNode as C, mergeHarvestUnderEnv as D, type EnvHarvestConflict as E, resolveModule as F, setEnvHarvestConflictCollector as G, shouldAnalyzeFile as H, hasNudoDirectives as I, topoSortDirty as J, trimBPathCache as K, tryBPathCall as L, type MergeHarvestOptions as M, tryBPathCallFull as N, tryRunBPath as O, type AbsModuleCacheEntry as a, type AbsModuleGraphResult as b, type AbsModuleLoadIssue as c, type ModuleGraphCache as d, analyzeFile as e, analyzeFileAsync as f, buildModuleGraph as g, clearAbsModuleCache as h, clearBPathCache as i, collectAbsBindingsFromGraph as j, collectBPathReplacements as k, collectCallRecords as l, collectEnvGlobals as m, collectEnvModules as n, collectEnvNames as o, computeDirtySet as p, defaultAbsLoadModule as q, diagnosticsLevelForFile as r, evalAbsModuleGraph as s, evictAbsModuleCacheFiles as t, evictBPathCacheForFiles as u, filterDiagnosticsByLevel as v, getAbsModuleCacheSize as w, getBPathCacheSize as x, getEnvHarvestConflictCollector as y, isBPathCapable as z };
|
package/dist/analysis.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export { A as AbsGraphOptions, a as AbsModuleCacheEntry, b as AbsModuleGraphResult, c as AbsModuleLoadIssue, B as BPathRunResult, d as ModuleGraphCache, e as analyzeFile, f as analyzeFileAsync, g as buildModuleGraph, h as clearAbsModuleCache, i as clearBPathCache, j as collectAbsBindingsFromGraph, l as collectCallRecords, o as
|
|
1
|
+
export { A as AnalysisResult, B as BindingInfo, C as CaseHint, b as CaseResult, c as CompletionItem, d as Diagnostic, e as DiagnosticSeverity, f as DiagnosticTag, D as DirectiveCaseMode, F as FunctionAnalysis, R as ReferenceInfo, S as SourceLocation, g as SymbolInfo, h as SymbolTable } from './analyzer-types-CfBrPK9L.js';
|
|
2
|
+
export { A as AbsGraphOptions, a as AbsModuleCacheEntry, b as AbsModuleGraphResult, c as AbsModuleLoadIssue, B as BPathRunResult, d as ModuleGraphCache, e as analyzeFile, f as analyzeFileAsync, g as buildModuleGraph, h as clearAbsModuleCache, i as clearBPathCache, j as collectAbsBindingsFromGraph, l as collectCallRecords, o as collectEnvNames, p as computeDirtySet, q as defaultAbsLoadModule, r as diagnosticsLevelForFile, s as evalAbsModuleGraph, t as evictAbsModuleCacheFiles, u as evictBPathCacheForFiles, v as filterDiagnosticsByLevel, w as getAbsModuleCacheSize, x as getBPathCacheSize, z as isBPathCapable, C as locFromNode, F as resolveModule, H as shouldAnalyzeFile, I as sourceHasNudoDirectives, J as topoSortDirty, K as trimBPathCache, L as tryBPathCall, N as tryBPathCallFull, O as tryRunBPath } from './analysis-_DlXLC-L.js';
|
|
3
3
|
export { C as CallRecord } from './call-record-CkyCFkT9.js';
|
|
4
4
|
import '@babel/types';
|
|
5
5
|
import '@nudojs/core';
|
|
6
|
+
import '@nudojs/parser';
|
|
6
7
|
import '@nudojs/core/internal';
|
|
7
8
|
import './config-DDB588oA.js';
|
package/dist/analysis.js
CHANGED
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
filterDiagnosticsByLevel,
|
|
4
4
|
hasNudoDirectives,
|
|
5
5
|
shouldAnalyzeFile
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-EG6FYQLI.js";
|
|
7
7
|
import {
|
|
8
8
|
analyzeFile,
|
|
9
9
|
analyzeFileAsync,
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
clearBPathCache,
|
|
13
13
|
collectAbsBindingsFromGraph,
|
|
14
14
|
collectCallRecords,
|
|
15
|
+
collectEnvNames,
|
|
15
16
|
computeDirtySet,
|
|
16
17
|
defaultAbsLoadModule,
|
|
17
18
|
evalAbsModuleGraph,
|
|
@@ -20,15 +21,15 @@ import {
|
|
|
20
21
|
getAbsModuleCacheSize,
|
|
21
22
|
getBPathCacheSize,
|
|
22
23
|
isBPathCapable,
|
|
24
|
+
locFromNode,
|
|
25
|
+
resolveModule,
|
|
23
26
|
topoSortDirty,
|
|
24
27
|
trimBPathCache,
|
|
25
28
|
tryBPathCall,
|
|
26
29
|
tryBPathCallFull,
|
|
27
30
|
tryRunBPath
|
|
28
|
-
} from "./chunk-
|
|
29
|
-
import "./chunk-
|
|
30
|
-
import "./chunk-YLALZXTZ.js";
|
|
31
|
-
import "./chunk-PVJIMQRI.js";
|
|
31
|
+
} from "./chunk-NQXAF4LJ.js";
|
|
32
|
+
import "./chunk-ZXVAX7DE.js";
|
|
32
33
|
export {
|
|
33
34
|
analyzeFile,
|
|
34
35
|
analyzeFileAsync,
|
|
@@ -37,6 +38,7 @@ export {
|
|
|
37
38
|
clearBPathCache,
|
|
38
39
|
collectAbsBindingsFromGraph,
|
|
39
40
|
collectCallRecords,
|
|
41
|
+
collectEnvNames,
|
|
40
42
|
computeDirtySet,
|
|
41
43
|
defaultAbsLoadModule,
|
|
42
44
|
diagnosticsLevelForFile,
|
|
@@ -47,6 +49,8 @@ export {
|
|
|
47
49
|
getAbsModuleCacheSize,
|
|
48
50
|
getBPathCacheSize,
|
|
49
51
|
isBPathCapable,
|
|
52
|
+
locFromNode,
|
|
53
|
+
resolveModule,
|
|
50
54
|
shouldAnalyzeFile,
|
|
51
55
|
hasNudoDirectives as sourceHasNudoDirectives,
|
|
52
56
|
topoSortDirty,
|
|
@@ -155,4 +155,4 @@ type AnalyzeLoadModule = (spec: string, fromFile: string) => string | undefined;
|
|
|
155
155
|
*/
|
|
156
156
|
type DirectiveCaseMode = "none" | "all" | "selected";
|
|
157
157
|
|
|
158
|
-
export type {
|
|
158
|
+
export type { AnalysisResult as A, BindingInfo as B, CaseHint as C, DirectiveCaseMode as D, FunctionAnalysis as F, ReferenceInfo as R, SourceLocation as S, AnalyzeLoadModule as a, CaseResult as b, CompletionItem as c, Diagnostic as d, DiagnosticSeverity as e, DiagnosticTag as f, SymbolInfo as g, SymbolTable as h };
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
// src/what-if.ts
|
|
2
|
+
import { parse } from "@nudojs/parser";
|
|
3
|
+
function splitTopLevelUnion(expr) {
|
|
4
|
+
const members = [];
|
|
5
|
+
let start = 0;
|
|
6
|
+
let depth = 0;
|
|
7
|
+
for (let i = 0; i < expr.length; i++) {
|
|
8
|
+
const c = expr[i];
|
|
9
|
+
if (c === "(" || c === "[" || c === "{") depth++;
|
|
10
|
+
else if (c === ")" || c === "]" || c === "}") depth--;
|
|
11
|
+
else if (c === "|" && depth === 0) {
|
|
12
|
+
members.push(expr.slice(start, i));
|
|
13
|
+
start = i + 1;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
members.push(expr.slice(start));
|
|
17
|
+
return members.map((m) => m.trim()).filter(Boolean);
|
|
18
|
+
}
|
|
19
|
+
function typeExprToDirective(expr) {
|
|
20
|
+
const members = splitTopLevelUnion(expr);
|
|
21
|
+
if (members.length === 0) return "any()";
|
|
22
|
+
const mapped = members.map((m) => {
|
|
23
|
+
if (m.startsWith("T.")) return "any()";
|
|
24
|
+
if (m === "number" || m === "string" || m === "boolean") return `${m}()`;
|
|
25
|
+
if (m === "unknown" || m === "any") return "any()";
|
|
26
|
+
if (m === "null" || m === "undefined" || m === "true" || m === "false") return m;
|
|
27
|
+
if (/^-?\d+(\.\d+)?$/.test(m)) return m;
|
|
28
|
+
if (/^["']/.test(m)) return m;
|
|
29
|
+
if (/[([{]|=>/.test(m) && !m.startsWith("T.")) return m;
|
|
30
|
+
if (/^(number|string|boolean|any|array|shape|lit|union|fn)\s*\(/.test(m)) return m;
|
|
31
|
+
return "any()";
|
|
32
|
+
});
|
|
33
|
+
return mapped.length === 1 ? mapped[0] : `union(${mapped.join(", ")})`;
|
|
34
|
+
}
|
|
35
|
+
function declaredNames(stmt, out) {
|
|
36
|
+
if (stmt.type === "FunctionDeclaration" && stmt.id) out.add(stmt.id.name);
|
|
37
|
+
else if (stmt.type === "ClassDeclaration" && stmt.id) out.add(stmt.id.name);
|
|
38
|
+
else if (stmt.type === "VariableDeclaration") {
|
|
39
|
+
for (const decl of stmt.declarations) {
|
|
40
|
+
if (decl.id?.type === "Identifier") out.add(decl.id.name);
|
|
41
|
+
}
|
|
42
|
+
} else if (stmt.type === "ExportNamedDeclaration" && stmt.declaration) {
|
|
43
|
+
declaredNames(stmt.declaration, out);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
function injectBindings(source, bindings) {
|
|
47
|
+
const applied = [];
|
|
48
|
+
const unapplied = [];
|
|
49
|
+
if (bindings.length === 0) return { source, applied, unapplied };
|
|
50
|
+
const ast = parse(source);
|
|
51
|
+
const declLines = /* @__PURE__ */ new Map();
|
|
52
|
+
for (const stmt of ast.program.body) {
|
|
53
|
+
const names = /* @__PURE__ */ new Set();
|
|
54
|
+
declaredNames(stmt, names);
|
|
55
|
+
if (names.size === 0 || !stmt.loc) continue;
|
|
56
|
+
const anchorLine = stmt.leadingComments?.[0]?.loc?.start.line ?? stmt.loc.start.line;
|
|
57
|
+
for (const name of names) {
|
|
58
|
+
if (!declLines.has(name)) declLines.set(name, anchorLine);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
const byLine = /* @__PURE__ */ new Map();
|
|
62
|
+
for (const binding of bindings) {
|
|
63
|
+
const line = declLines.get(binding.name);
|
|
64
|
+
if (line === void 0) {
|
|
65
|
+
unapplied.push(binding.name);
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
const group = byLine.get(line) ?? [];
|
|
69
|
+
group.push(binding);
|
|
70
|
+
byLine.set(line, group);
|
|
71
|
+
applied.push(binding.name);
|
|
72
|
+
}
|
|
73
|
+
const insertions = [];
|
|
74
|
+
for (const [line, group] of byLine) {
|
|
75
|
+
insertions.push({
|
|
76
|
+
index: line - 1,
|
|
77
|
+
text: `// @nudo:as ${typeExprToDirective(group[0].type)}`
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
insertions.sort((a, b) => b.index - a.index);
|
|
81
|
+
const lines = source.split("\n");
|
|
82
|
+
for (const ins of insertions) lines.splice(ins.index, 0, ins.text);
|
|
83
|
+
return { source: lines.join("\n"), applied, unapplied };
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// src/dep-contents.ts
|
|
87
|
+
import { loadModuleDepsFingerprint } from "@nudojs/core/internal";
|
|
88
|
+
function collectLoadDepContents(filePath, source, loadModule) {
|
|
89
|
+
const fp = loadModuleDepsFingerprint(source, loadModule, filePath);
|
|
90
|
+
const depContents = fp.contents.length > 0 ? fp.contents : fp.paths.map((path) => ({ path, content: null }));
|
|
91
|
+
return { depContents, truncated: fp.truncated };
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// src/disk-cache.ts
|
|
95
|
+
import { createHash } from "crypto";
|
|
96
|
+
import { createRequire } from "module";
|
|
97
|
+
import { mkdirSync, readFileSync, writeFileSync, existsSync, rmSync } from "fs";
|
|
98
|
+
import { join, dirname, relative, sep, isAbsolute } from "path";
|
|
99
|
+
function readServiceVersion() {
|
|
100
|
+
try {
|
|
101
|
+
const require2 = createRequire(import.meta.url);
|
|
102
|
+
for (const p of ["../package.json", "./package.json", "../../package.json"]) {
|
|
103
|
+
try {
|
|
104
|
+
const pkg = require2(p);
|
|
105
|
+
if (pkg?.name === "@nudojs/service" && pkg.version) return pkg.version;
|
|
106
|
+
if (pkg?.version && p.includes("service")) return pkg.version;
|
|
107
|
+
} catch {
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
} catch {
|
|
111
|
+
}
|
|
112
|
+
return "0";
|
|
113
|
+
}
|
|
114
|
+
var ANALYSIS_ABI = `nudo-check-cache-v3+${readServiceVersion()}`;
|
|
115
|
+
function sha256Hex(data) {
|
|
116
|
+
return createHash("sha256").update(data).digest("hex");
|
|
117
|
+
}
|
|
118
|
+
function relativizePath(p, root) {
|
|
119
|
+
const norm = p.split(sep).join("/");
|
|
120
|
+
if (!root) return norm;
|
|
121
|
+
const r = relative(root, p).split(sep).join("/");
|
|
122
|
+
if (!r.startsWith("..") && !isAbsolute(r)) return r;
|
|
123
|
+
return `ext:${createHash("sha256").update(norm).digest("hex").slice(0, 16)}`;
|
|
124
|
+
}
|
|
125
|
+
function sanitizeCacheNamespace(ns) {
|
|
126
|
+
return ns.replace(/[^a-z0-9_-]/gi, "_").replace(/^_+|_+$/g, "") || "cache";
|
|
127
|
+
}
|
|
128
|
+
var DiskCache = class {
|
|
129
|
+
root;
|
|
130
|
+
ns;
|
|
131
|
+
enabled = false;
|
|
132
|
+
constructor(opts) {
|
|
133
|
+
this.root = opts.root;
|
|
134
|
+
this.ns = sanitizeCacheNamespace(opts.namespace);
|
|
135
|
+
this.enabled = !!opts.root;
|
|
136
|
+
}
|
|
137
|
+
pathFor(key) {
|
|
138
|
+
if (!/^[a-f0-9]{16,128}$/i.test(key)) {
|
|
139
|
+
throw new Error("DiskCache key must be a hex digest");
|
|
140
|
+
}
|
|
141
|
+
return join(this.root, this.ns, key.slice(0, 2), `${key}.json`);
|
|
142
|
+
}
|
|
143
|
+
get(key) {
|
|
144
|
+
if (!this.enabled || !this.root) return void 0;
|
|
145
|
+
try {
|
|
146
|
+
const p = this.pathFor(key);
|
|
147
|
+
if (!existsSync(p)) return void 0;
|
|
148
|
+
const raw = readFileSync(p, "utf8");
|
|
149
|
+
const parsed = JSON.parse(raw);
|
|
150
|
+
if (parsed?.abi !== ANALYSIS_ABI) return void 0;
|
|
151
|
+
return parsed.value;
|
|
152
|
+
} catch {
|
|
153
|
+
return void 0;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
set(key, value) {
|
|
157
|
+
if (!this.enabled || !this.root) return;
|
|
158
|
+
try {
|
|
159
|
+
const p = this.pathFor(key);
|
|
160
|
+
mkdirSync(dirname(p), { recursive: true });
|
|
161
|
+
writeFileSync(p, JSON.stringify({ abi: ANALYSIS_ABI, value }), "utf8");
|
|
162
|
+
} catch {
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
clearNamespace() {
|
|
166
|
+
if (!this.enabled || !this.root) return;
|
|
167
|
+
try {
|
|
168
|
+
rmSync(join(this.root, this.ns), { recursive: true, force: true });
|
|
169
|
+
} catch {
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
function checkCacheKey(filePath, source, opts) {
|
|
174
|
+
const rel = relativizePath(filePath, opts.projectDir);
|
|
175
|
+
const sidecarSha = opts.sidecarContent != null ? sha256Hex(opts.sidecarContent) : "nosidecar";
|
|
176
|
+
const depSeg = (opts.depContents ?? []).map(
|
|
177
|
+
(d) => `${relativizePath(d.path, opts.projectDir)}\0${d.content != null ? sha256Hex(d.content) : "miss"}`
|
|
178
|
+
).join("\n");
|
|
179
|
+
const envSeg = (opts.projectEnvNames ?? []).length > 0 ? [...opts.projectEnvNames ?? []].sort().join(",") : "-";
|
|
180
|
+
const cfgSeg = opts.analysisCfg ? `${opts.analysisCfg.mode ?? "-"}|${opts.analysisCfg.evalMissingSlot ?? "-"}|${opts.analysisCfg.callSiteBudget ?? "-"}|${opts.analysisCfg.entryThrows ?? "-"}|${opts.analysisCfg.ignoreThrows ?? "-"}` : "-";
|
|
181
|
+
return sha256Hex(
|
|
182
|
+
[
|
|
183
|
+
ANALYSIS_ABI,
|
|
184
|
+
rel,
|
|
185
|
+
opts.autoBind ? "ab1" : "ab0",
|
|
186
|
+
sha256Hex(source),
|
|
187
|
+
sidecarSha,
|
|
188
|
+
depSeg,
|
|
189
|
+
envSeg,
|
|
190
|
+
cfgSeg
|
|
191
|
+
].join("\0")
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
function ifaceCacheKey(filePath, source, opts) {
|
|
195
|
+
const rel = relativizePath(filePath, opts.projectDir);
|
|
196
|
+
const sidecarSeg = opts.autoBind && opts.sidecarSource !== void 0 ? `sc:${sha256Hex(opts.sidecarSource)}` : "sc0";
|
|
197
|
+
const depSeg = (opts.depContents ?? []).map(
|
|
198
|
+
(d) => `${relativizePath(d.path, opts.projectDir)}\0${d.content != null ? sha256Hex(d.content) : "miss"}`
|
|
199
|
+
).join("\n");
|
|
200
|
+
const envSeg = (opts.projectEnvNames ?? []).length > 0 ? [...opts.projectEnvNames ?? []].sort().join(",") : "-";
|
|
201
|
+
return sha256Hex(
|
|
202
|
+
[
|
|
203
|
+
ANALYSIS_ABI,
|
|
204
|
+
"iface",
|
|
205
|
+
rel,
|
|
206
|
+
opts.autoBind ? "ab1" : "ab0",
|
|
207
|
+
sha256Hex(source),
|
|
208
|
+
sidecarSeg,
|
|
209
|
+
depSeg,
|
|
210
|
+
envSeg
|
|
211
|
+
].join("\0")
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
function extractNudoImportSpecs(source) {
|
|
215
|
+
const specs = /* @__PURE__ */ new Set();
|
|
216
|
+
const named = /@nudo:import\s*\{[^}]*\}\s*from\s*["']([^"']+)["']/g;
|
|
217
|
+
const ns = /@nudo:import\s+\*\s+as\s+\w+\s+from\s*["']([^"']+)["']/g;
|
|
218
|
+
let m;
|
|
219
|
+
while (m = named.exec(source)) specs.add(m[1]);
|
|
220
|
+
while (m = ns.exec(source)) specs.add(m[1]);
|
|
221
|
+
return [...specs];
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
export {
|
|
225
|
+
typeExprToDirective,
|
|
226
|
+
injectBindings,
|
|
227
|
+
collectLoadDepContents,
|
|
228
|
+
ANALYSIS_ABI,
|
|
229
|
+
sha256Hex,
|
|
230
|
+
relativizePath,
|
|
231
|
+
DiskCache,
|
|
232
|
+
checkCacheKey,
|
|
233
|
+
ifaceCacheKey,
|
|
234
|
+
extractNudoImportSpecs
|
|
235
|
+
};
|