@nudojs/service 1.0.0 → 1.0.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/chunk-2VHITMTM.js +488 -0
- package/dist/config-NqDRWWpn.d.ts +68 -0
- package/dist/evaluator/evaluator-api.d.ts +13 -15
- package/dist/evaluator/evaluator-api.js +9 -53
- package/dist/index.d.ts +182 -46
- package/dist/index.js +2034 -1330
- package/package.json +5 -5
- package/dist/chunk-FSIHAE7I.js +0 -5871
- package/dist/config-UlReSTfh.d.ts +0 -152
|
@@ -0,0 +1,488 @@
|
|
|
1
|
+
// src/evaluator/builtins/builtin-prototype.ts
|
|
2
|
+
import {
|
|
3
|
+
abs,
|
|
4
|
+
objOf,
|
|
5
|
+
formatAbs,
|
|
6
|
+
relationFn
|
|
7
|
+
} from "@nudojs/core";
|
|
8
|
+
function hasOwnProp(props, name) {
|
|
9
|
+
return Object.prototype.hasOwnProperty.call(props, name);
|
|
10
|
+
}
|
|
11
|
+
var BUILTIN_ERROR_CLASSES = /* @__PURE__ */ new Set([
|
|
12
|
+
"Error",
|
|
13
|
+
"TypeError",
|
|
14
|
+
"SyntaxError",
|
|
15
|
+
"RangeError",
|
|
16
|
+
"ReferenceError",
|
|
17
|
+
"URIError",
|
|
18
|
+
"EvalError"
|
|
19
|
+
]);
|
|
20
|
+
var BUILTIN_PROTOTYPE_CLASSES = /* @__PURE__ */ new Set([
|
|
21
|
+
...BUILTIN_ERROR_CLASSES,
|
|
22
|
+
"Date",
|
|
23
|
+
"Object",
|
|
24
|
+
"Map",
|
|
25
|
+
"Set",
|
|
26
|
+
"Promise",
|
|
27
|
+
"RegExp",
|
|
28
|
+
"Array",
|
|
29
|
+
"Function",
|
|
30
|
+
"String",
|
|
31
|
+
"Number",
|
|
32
|
+
"Boolean",
|
|
33
|
+
"Symbol",
|
|
34
|
+
"WeakMap",
|
|
35
|
+
"WeakSet",
|
|
36
|
+
"Buffer"
|
|
37
|
+
]);
|
|
38
|
+
var numA = { shape: { k: "prim", type: "number" }, conf: "exact" };
|
|
39
|
+
var strA = { shape: { k: "prim", type: "string" }, conf: "exact" };
|
|
40
|
+
var boolA = { shape: { k: "prim", type: "boolean" }, conf: "exact" };
|
|
41
|
+
var unkA = { shape: { k: "unknown" }, conf: "partial" };
|
|
42
|
+
var undefA = abs({ k: "unknown" }, { op: "lit", value: void 0 }, void 0, "exact");
|
|
43
|
+
var nullA = abs({ k: "unknown" }, { op: "lit", value: null }, void 0, "exact");
|
|
44
|
+
function arrOf(el) {
|
|
45
|
+
return { shape: { k: "arr", element: el }, conf: "exact" };
|
|
46
|
+
}
|
|
47
|
+
function tupleOf(els) {
|
|
48
|
+
return { shape: { k: "tuple", elements: els }, conf: "exact" };
|
|
49
|
+
}
|
|
50
|
+
function promiseOf(inner) {
|
|
51
|
+
return { shape: { k: "eff", eff: "promise", inner }, conf: "exact" };
|
|
52
|
+
}
|
|
53
|
+
function sumOf(...members) {
|
|
54
|
+
if (members.length === 1) return members[0];
|
|
55
|
+
return { shape: { k: "sum", members }, conf: "exact" };
|
|
56
|
+
}
|
|
57
|
+
function brand(name) {
|
|
58
|
+
return { shape: { k: "brand", name, shape: unkA }, conf: "path" };
|
|
59
|
+
}
|
|
60
|
+
function emptyObj() {
|
|
61
|
+
return objOf({});
|
|
62
|
+
}
|
|
63
|
+
function sig(params, ret) {
|
|
64
|
+
return relationFn(params, ret, {
|
|
65
|
+
conf: "exact",
|
|
66
|
+
params: params.map((_, i) => `_arg${i}`)
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
var OBJECT_PROTOTYPE_METHODS = {
|
|
70
|
+
hasOwnProperty: sig([unkA], boolA),
|
|
71
|
+
isPrototypeOf: sig([unkA], boolA),
|
|
72
|
+
propertyIsEnumerable: sig([unkA], boolA),
|
|
73
|
+
toString: sig([], strA),
|
|
74
|
+
toLocaleString: sig([], strA),
|
|
75
|
+
valueOf: sig([], unkA)
|
|
76
|
+
};
|
|
77
|
+
var BUILTIN_PROTOTYPE_METHOD_APPROXIMATIONS = {
|
|
78
|
+
Object: { ...OBJECT_PROTOTYPE_METHODS },
|
|
79
|
+
Array: {
|
|
80
|
+
push: sig([unkA], numA),
|
|
81
|
+
pop: sig([], unkA),
|
|
82
|
+
shift: sig([], unkA),
|
|
83
|
+
unshift: sig([unkA], numA),
|
|
84
|
+
slice: sig([numA, numA], arrOf(unkA)),
|
|
85
|
+
splice: sig([numA, numA], arrOf(unkA)),
|
|
86
|
+
concat: sig([unkA], arrOf(unkA)),
|
|
87
|
+
join: sig([strA], strA),
|
|
88
|
+
indexOf: sig([unkA], numA),
|
|
89
|
+
lastIndexOf: sig([unkA], numA),
|
|
90
|
+
includes: sig([unkA], boolA),
|
|
91
|
+
map: sig([unkA], arrOf(unkA)),
|
|
92
|
+
flatMap: sig([unkA], arrOf(unkA)),
|
|
93
|
+
filter: sig([unkA], arrOf(unkA)),
|
|
94
|
+
forEach: sig([unkA], undefA),
|
|
95
|
+
find: sig([unkA], unkA),
|
|
96
|
+
findIndex: sig([unkA], numA),
|
|
97
|
+
some: sig([unkA], boolA),
|
|
98
|
+
every: sig([unkA], boolA),
|
|
99
|
+
reduce: sig([unkA, unkA], unkA),
|
|
100
|
+
sort: sig([unkA], arrOf(unkA)),
|
|
101
|
+
reverse: sig([], arrOf(unkA)),
|
|
102
|
+
toString: sig([], strA)
|
|
103
|
+
},
|
|
104
|
+
Function: {
|
|
105
|
+
call: sig([unkA], unkA),
|
|
106
|
+
apply: sig([unkA, unkA], unkA),
|
|
107
|
+
bind: sig([unkA], unkA),
|
|
108
|
+
toString: sig([], strA)
|
|
109
|
+
},
|
|
110
|
+
Map: {
|
|
111
|
+
get: sig([unkA], unkA),
|
|
112
|
+
set: sig([unkA, unkA], unkA),
|
|
113
|
+
has: sig([unkA], boolA),
|
|
114
|
+
delete: sig([unkA], boolA),
|
|
115
|
+
clear: sig([], undefA),
|
|
116
|
+
forEach: sig([unkA], undefA),
|
|
117
|
+
keys: sig([], arrOf(unkA)),
|
|
118
|
+
values: sig([], arrOf(unkA)),
|
|
119
|
+
entries: sig([], arrOf(tupleOf([unkA, unkA]))),
|
|
120
|
+
toString: sig([], strA)
|
|
121
|
+
},
|
|
122
|
+
Set: {
|
|
123
|
+
add: sig([unkA], unkA),
|
|
124
|
+
has: sig([unkA], boolA),
|
|
125
|
+
delete: sig([unkA], boolA),
|
|
126
|
+
clear: sig([], undefA),
|
|
127
|
+
forEach: sig([unkA], undefA),
|
|
128
|
+
keys: sig([], arrOf(unkA)),
|
|
129
|
+
values: sig([], arrOf(unkA)),
|
|
130
|
+
entries: sig([], arrOf(tupleOf([unkA, unkA]))),
|
|
131
|
+
toString: sig([], strA)
|
|
132
|
+
},
|
|
133
|
+
WeakMap: {
|
|
134
|
+
get: sig([unkA], unkA),
|
|
135
|
+
set: sig([unkA, unkA], unkA),
|
|
136
|
+
has: sig([unkA], boolA),
|
|
137
|
+
delete: sig([unkA], boolA),
|
|
138
|
+
toString: sig([], strA)
|
|
139
|
+
},
|
|
140
|
+
WeakSet: {
|
|
141
|
+
add: sig([unkA], unkA),
|
|
142
|
+
has: sig([unkA], boolA),
|
|
143
|
+
delete: sig([unkA], boolA),
|
|
144
|
+
toString: sig([], strA)
|
|
145
|
+
},
|
|
146
|
+
Promise: {
|
|
147
|
+
then: sig([unkA], promiseOf(unkA)),
|
|
148
|
+
catch: sig([unkA], promiseOf(unkA)),
|
|
149
|
+
finally: sig([unkA], promiseOf(unkA)),
|
|
150
|
+
toString: sig([], strA)
|
|
151
|
+
},
|
|
152
|
+
Date: {
|
|
153
|
+
getTime: sig([], numA),
|
|
154
|
+
valueOf: sig([], numA),
|
|
155
|
+
toISOString: sig([], strA),
|
|
156
|
+
toJSON: sig([], strA),
|
|
157
|
+
toLocaleString: sig([], strA),
|
|
158
|
+
toString: sig([], strA)
|
|
159
|
+
},
|
|
160
|
+
RegExp: {
|
|
161
|
+
test: sig([strA], boolA),
|
|
162
|
+
exec: sig([strA], sumOf(emptyObj(), nullA)),
|
|
163
|
+
toString: sig([], strA)
|
|
164
|
+
},
|
|
165
|
+
String: {
|
|
166
|
+
charAt: sig([numA], strA),
|
|
167
|
+
charCodeAt: sig([numA], numA),
|
|
168
|
+
indexOf: sig([strA], numA),
|
|
169
|
+
lastIndexOf: sig([strA], numA),
|
|
170
|
+
includes: sig([strA], boolA),
|
|
171
|
+
startsWith: sig([strA], boolA),
|
|
172
|
+
endsWith: sig([strA], boolA),
|
|
173
|
+
slice: sig([numA, numA], strA),
|
|
174
|
+
substring: sig([numA, numA], strA),
|
|
175
|
+
toUpperCase: sig([], strA),
|
|
176
|
+
toLowerCase: sig([], strA),
|
|
177
|
+
trim: sig([], strA),
|
|
178
|
+
replace: sig([unkA, strA], strA),
|
|
179
|
+
split: sig([strA], arrOf(strA)),
|
|
180
|
+
toString: sig([], strA),
|
|
181
|
+
valueOf: sig([], strA)
|
|
182
|
+
},
|
|
183
|
+
Number: {
|
|
184
|
+
toFixed: sig([numA], strA),
|
|
185
|
+
toPrecision: sig([numA], strA),
|
|
186
|
+
valueOf: sig([], numA),
|
|
187
|
+
toString: sig([numA], strA)
|
|
188
|
+
},
|
|
189
|
+
Boolean: {
|
|
190
|
+
valueOf: sig([], boolA),
|
|
191
|
+
toString: sig([], strA)
|
|
192
|
+
},
|
|
193
|
+
Symbol: {
|
|
194
|
+
toString: sig([], strA),
|
|
195
|
+
valueOf: sig([], brand("Symbol"))
|
|
196
|
+
},
|
|
197
|
+
Buffer: {
|
|
198
|
+
equals: sig([unkA], boolA),
|
|
199
|
+
compare: sig([unkA], numA),
|
|
200
|
+
toString: sig([unkA], strA),
|
|
201
|
+
toJSON: sig([], unkA)
|
|
202
|
+
},
|
|
203
|
+
Error: {
|
|
204
|
+
toString: sig([], strA)
|
|
205
|
+
}
|
|
206
|
+
};
|
|
207
|
+
function fmtNoConf(a) {
|
|
208
|
+
return formatAbs(a).replace(/\s+#(exact|path|widened|mock|partial|opaque)$/, "");
|
|
209
|
+
}
|
|
210
|
+
function describeAbsMember(a) {
|
|
211
|
+
if (a.shape.k !== "fn") return fmtNoConf(a);
|
|
212
|
+
const s = a.shape;
|
|
213
|
+
const pts = s.paramTypes ?? [];
|
|
214
|
+
const params = pts.map((p, i) => `${s.params[i] ?? `arg${i}`}: ${fmtNoConf(p)}`).join(", ");
|
|
215
|
+
const ret = s.returnType ? fmtNoConf(s.returnType) : "unknown";
|
|
216
|
+
return `(${params}) => ${ret}`;
|
|
217
|
+
}
|
|
218
|
+
function builtinProtoMemberNames(className) {
|
|
219
|
+
const table = hasOwnProp(BUILTIN_PROTOTYPE_METHOD_APPROXIMATIONS, className) ? BUILTIN_PROTOTYPE_METHOD_APPROXIMATIONS[className] : void 0;
|
|
220
|
+
return table ? Object.keys(table) : [];
|
|
221
|
+
}
|
|
222
|
+
function builtinProtoMember(className, member) {
|
|
223
|
+
const table = hasOwnProp(BUILTIN_PROTOTYPE_METHOD_APPROXIMATIONS, className) ? BUILTIN_PROTOTYPE_METHOD_APPROXIMATIONS[className] : BUILTIN_ERROR_CLASSES.has(className) ? BUILTIN_PROTOTYPE_METHOD_APPROXIMATIONS.Error : void 0;
|
|
224
|
+
if (!table) return null;
|
|
225
|
+
return table[member] ?? null;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// src/evaluator/env-loader.ts
|
|
229
|
+
import { readFileSync, existsSync, statSync, mkdirSync, writeFileSync } from "fs";
|
|
230
|
+
import { resolve as resolvePath, join as joinPath } from "path";
|
|
231
|
+
import { pathToFileURL } from "url";
|
|
232
|
+
import { createRequire } from "module";
|
|
233
|
+
import { createHash } from "crypto";
|
|
234
|
+
import { tmpdir } from "os";
|
|
235
|
+
import { defineEnv as defineEsEnv } from "@nudojs/env/es";
|
|
236
|
+
import { defineEnv as defineWebEnv } from "@nudojs/env/web";
|
|
237
|
+
import { defineEnv as defineNodeEnv } from "@nudojs/env/node";
|
|
238
|
+
var envFactories = {
|
|
239
|
+
es: defineEsEnv,
|
|
240
|
+
web: defineWebEnv,
|
|
241
|
+
node: defineNodeEnv
|
|
242
|
+
};
|
|
243
|
+
var impliedDeps = {
|
|
244
|
+
web: ["es"],
|
|
245
|
+
node: ["es"]
|
|
246
|
+
};
|
|
247
|
+
function resolveEnvNames(names) {
|
|
248
|
+
const resolved = /* @__PURE__ */ new Set();
|
|
249
|
+
const visit = (name) => {
|
|
250
|
+
if (resolved.has(name)) return;
|
|
251
|
+
const deps = impliedDeps[name];
|
|
252
|
+
if (deps) deps.forEach(visit);
|
|
253
|
+
resolved.add(name);
|
|
254
|
+
};
|
|
255
|
+
names.forEach(visit);
|
|
256
|
+
return [...resolved];
|
|
257
|
+
}
|
|
258
|
+
var pathEnvCache = /* @__PURE__ */ new Map();
|
|
259
|
+
var pathEnvByPath = /* @__PURE__ */ new Map();
|
|
260
|
+
var pathEnvBaseDirs = /* @__PURE__ */ new Set();
|
|
261
|
+
function isPathEnvName(name, baseDir) {
|
|
262
|
+
if (name in envFactories) return false;
|
|
263
|
+
if (name.includes("/") || name.startsWith("./") || name.startsWith("../")) return true;
|
|
264
|
+
const resolved = resolvePath(baseDir, name);
|
|
265
|
+
return resolved.endsWith(".ts") && existsSync(resolved);
|
|
266
|
+
}
|
|
267
|
+
function rewriteBareImports(text) {
|
|
268
|
+
const require2 = createRequire(import.meta.url);
|
|
269
|
+
let rewrote = false;
|
|
270
|
+
const out = text.replace(/(["'])(@nudojs\/[a-z0-9-]+)\1/g, (_m, quote, spec) => {
|
|
271
|
+
try {
|
|
272
|
+
const entry = require2.resolve(spec);
|
|
273
|
+
const url = pathToFileURL(entry).href;
|
|
274
|
+
rewrote = true;
|
|
275
|
+
return `${quote}${url}${quote}`;
|
|
276
|
+
} catch {
|
|
277
|
+
return `${quote}${spec}${quote}`;
|
|
278
|
+
}
|
|
279
|
+
});
|
|
280
|
+
return rewrote ? out : null;
|
|
281
|
+
}
|
|
282
|
+
async function importPathEnv(resolvedPath, mtimeMs) {
|
|
283
|
+
const cacheKey = `${resolvedPath}:${mtimeMs}`;
|
|
284
|
+
if (pathEnvCache.has(cacheKey)) return;
|
|
285
|
+
let mod = null;
|
|
286
|
+
try {
|
|
287
|
+
const url = pathToFileURL(resolvedPath).href + `?mtime=${mtimeMs}`;
|
|
288
|
+
mod = await import(url);
|
|
289
|
+
} catch {
|
|
290
|
+
mod = null;
|
|
291
|
+
}
|
|
292
|
+
if (!mod) {
|
|
293
|
+
try {
|
|
294
|
+
const text = readFileSync(resolvedPath, "utf-8");
|
|
295
|
+
const rewritten = rewriteBareImports(text);
|
|
296
|
+
if (rewritten === null) return;
|
|
297
|
+
const cacheDir = joinPath(tmpdir(), "nudo-env");
|
|
298
|
+
mkdirSync(cacheDir, { recursive: true });
|
|
299
|
+
const hash = createHash("md5").update(`${resolvedPath}:${mtimeMs}`).digest("hex").slice(0, 16);
|
|
300
|
+
const copyPath = joinPath(cacheDir, `${hash}.ts`);
|
|
301
|
+
writeFileSync(copyPath, rewritten, "utf-8");
|
|
302
|
+
mod = await import(pathToFileURL(copyPath).href);
|
|
303
|
+
} catch {
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
if (mod && typeof mod.defineEnv === "function") {
|
|
308
|
+
pathEnvCache.set(cacheKey, mod.defineEnv);
|
|
309
|
+
pathEnvByPath.set(resolvedPath, mod.defineEnv);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
function lookupPathEnv(name) {
|
|
313
|
+
if (pathEnvByPath.size === 0) return void 0;
|
|
314
|
+
const candidates = name.startsWith("/") ? [name] : [name, ...[...pathEnvBaseDirs].map((d) => resolvePath(d, name))];
|
|
315
|
+
for (const candidate of candidates) {
|
|
316
|
+
const hit = pathEnvByPath.get(candidate);
|
|
317
|
+
if (hit) return hit;
|
|
318
|
+
}
|
|
319
|
+
return void 0;
|
|
320
|
+
}
|
|
321
|
+
async function preloadPathEnvs(envNames, baseDir) {
|
|
322
|
+
pathEnvBaseDirs.add(baseDir);
|
|
323
|
+
for (const name of envNames) {
|
|
324
|
+
if (!isPathEnvName(name, baseDir)) continue;
|
|
325
|
+
const resolved = resolvePath(baseDir, name);
|
|
326
|
+
if (!existsSync(resolved)) continue;
|
|
327
|
+
try {
|
|
328
|
+
const { mtimeMs } = statSync(resolved);
|
|
329
|
+
await importPathEnv(resolved, mtimeMs);
|
|
330
|
+
} catch {
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
async function loadEnvsAsync(envNames, globalEnv, baseDir = process.cwd()) {
|
|
335
|
+
await preloadPathEnvs(envNames, baseDir);
|
|
336
|
+
return loadEnvs(envNames, globalEnv);
|
|
337
|
+
}
|
|
338
|
+
function loadEnvs(envNames, globalEnv) {
|
|
339
|
+
const allModules = {};
|
|
340
|
+
const allGlobals = {};
|
|
341
|
+
const resolved = resolveEnvNames(envNames);
|
|
342
|
+
for (const name of resolved) {
|
|
343
|
+
const factory = envFactories[name] ?? lookupPathEnv(name);
|
|
344
|
+
if (!factory) continue;
|
|
345
|
+
const def = factory();
|
|
346
|
+
for (const [key, value] of Object.entries(def.globals)) {
|
|
347
|
+
allGlobals[key] = value;
|
|
348
|
+
globalEnv.bind(key, value);
|
|
349
|
+
}
|
|
350
|
+
if (def.modules) {
|
|
351
|
+
for (const [modName, exports] of Object.entries(def.modules)) {
|
|
352
|
+
allModules[modName] = { ...allModules[modName], ...exports };
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
return { modules: allModules, globals: allGlobals };
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// src/evaluator/config.ts
|
|
360
|
+
import { readFileSync as readFileSync2, existsSync as existsSync2 } from "fs";
|
|
361
|
+
import { resolve, dirname, relative, sep } from "path";
|
|
362
|
+
function interfaceConfig(config) {
|
|
363
|
+
const raw = config?.interface?.emit;
|
|
364
|
+
const emit = raw === void 0 ? [] : Array.isArray(raw) ? raw.filter((s) => typeof s === "string" && s.length > 0) : typeof raw === "string" && raw.length > 0 ? [raw] : [];
|
|
365
|
+
return {
|
|
366
|
+
autoBind: config?.interface?.autoBind ?? true,
|
|
367
|
+
emit
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
function matchesEmitAllowlist(absPath, projectDir, patterns) {
|
|
371
|
+
if (patterns.length === 0) return true;
|
|
372
|
+
if (!projectDir) return false;
|
|
373
|
+
const rel = relative(projectDir, absPath).split(sep).join("/");
|
|
374
|
+
if (rel.startsWith("..")) return false;
|
|
375
|
+
return patterns.some(
|
|
376
|
+
(p) => globMatch(
|
|
377
|
+
p.split(sep).join("/").replace(/^\.\//, ""),
|
|
378
|
+
rel
|
|
379
|
+
)
|
|
380
|
+
);
|
|
381
|
+
}
|
|
382
|
+
function globMatch(pattern, path) {
|
|
383
|
+
let rx = "";
|
|
384
|
+
for (let i = 0; i < pattern.length; i++) {
|
|
385
|
+
const ch = pattern[i];
|
|
386
|
+
if (ch === "*" && pattern[i + 1] === "*") {
|
|
387
|
+
if (pattern[i + 2] === "/") {
|
|
388
|
+
rx += "(?:.*/)?";
|
|
389
|
+
i += 2;
|
|
390
|
+
} else {
|
|
391
|
+
rx += ".*";
|
|
392
|
+
i += 1;
|
|
393
|
+
}
|
|
394
|
+
continue;
|
|
395
|
+
}
|
|
396
|
+
if (ch === "*") {
|
|
397
|
+
rx += "[^/]*";
|
|
398
|
+
continue;
|
|
399
|
+
}
|
|
400
|
+
if (ch === "?") {
|
|
401
|
+
rx += "[^/]";
|
|
402
|
+
continue;
|
|
403
|
+
}
|
|
404
|
+
rx += /[.+^${}()|[\]\\]/.test(ch) ? `\\${ch}` : ch;
|
|
405
|
+
}
|
|
406
|
+
return new RegExp(`^${rx}$`).test(path);
|
|
407
|
+
}
|
|
408
|
+
function findProjectConfig(startDir) {
|
|
409
|
+
let dir = resolve(startDir);
|
|
410
|
+
const root = resolve("/");
|
|
411
|
+
while (dir !== root) {
|
|
412
|
+
const pkgPath = resolve(dir, "package.json");
|
|
413
|
+
if (existsSync2(pkgPath)) {
|
|
414
|
+
try {
|
|
415
|
+
const pkg = JSON.parse(readFileSync2(pkgPath, "utf-8"));
|
|
416
|
+
if (pkg.nudo) {
|
|
417
|
+
return { config: pkg.nudo, projectDir: dir };
|
|
418
|
+
}
|
|
419
|
+
} catch {
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
const parent = dirname(dir);
|
|
423
|
+
if (parent === dir) break;
|
|
424
|
+
dir = parent;
|
|
425
|
+
}
|
|
426
|
+
return null;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
// src/evaluator/resolve-npm.ts
|
|
430
|
+
import { readFileSync as readFileSync3, existsSync as existsSync3 } from "fs";
|
|
431
|
+
import { resolve as resolve2, join, dirname as dirname2 } from "path";
|
|
432
|
+
function findNodeModules(startDir) {
|
|
433
|
+
let dir = resolve2(startDir);
|
|
434
|
+
const root = resolve2("/");
|
|
435
|
+
while (dir !== root) {
|
|
436
|
+
const nmPath = join(dir, "node_modules");
|
|
437
|
+
if (existsSync3(nmPath)) return nmPath;
|
|
438
|
+
const parent = dirname2(dir);
|
|
439
|
+
if (parent === dir) break;
|
|
440
|
+
dir = parent;
|
|
441
|
+
}
|
|
442
|
+
return null;
|
|
443
|
+
}
|
|
444
|
+
function resolveExportsNudo(exports, subpath) {
|
|
445
|
+
if (!exports || typeof exports !== "object") return null;
|
|
446
|
+
const entry = exports[subpath];
|
|
447
|
+
if (!entry) return null;
|
|
448
|
+
if (typeof entry === "object" && entry !== null && "nudo" in entry) {
|
|
449
|
+
const nudoEntry = entry["nudo"];
|
|
450
|
+
if (typeof nudoEntry === "string") return nudoEntry;
|
|
451
|
+
}
|
|
452
|
+
return null;
|
|
453
|
+
}
|
|
454
|
+
function resolveNpmNudo(source, fromDir) {
|
|
455
|
+
const isRelative = source.startsWith(".") || source.startsWith("/");
|
|
456
|
+
if (isRelative) return null;
|
|
457
|
+
const parts = source.startsWith("@") ? source.split("/").slice(0, 2) : source.split("/").slice(0, 1);
|
|
458
|
+
const pkgName = parts.join("/");
|
|
459
|
+
const subpath = source.slice(pkgName.length) || ".";
|
|
460
|
+
const nodeModules = findNodeModules(fromDir);
|
|
461
|
+
if (!nodeModules) return null;
|
|
462
|
+
const pkgJsonPath = join(nodeModules, pkgName, "package.json");
|
|
463
|
+
if (!existsSync3(pkgJsonPath)) return null;
|
|
464
|
+
try {
|
|
465
|
+
const pkg = JSON.parse(readFileSync3(pkgJsonPath, "utf-8"));
|
|
466
|
+
const nudoEntry = resolveExportsNudo(pkg.exports, subpath);
|
|
467
|
+
if (nudoEntry) {
|
|
468
|
+
const resolved = resolve2(dirname2(pkgJsonPath), nudoEntry);
|
|
469
|
+
if (existsSync3(resolved)) return resolved;
|
|
470
|
+
}
|
|
471
|
+
} catch {
|
|
472
|
+
}
|
|
473
|
+
return null;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
export {
|
|
477
|
+
preloadPathEnvs,
|
|
478
|
+
loadEnvsAsync,
|
|
479
|
+
loadEnvs,
|
|
480
|
+
interfaceConfig,
|
|
481
|
+
matchesEmitAllowlist,
|
|
482
|
+
findProjectConfig,
|
|
483
|
+
resolveNpmNudo,
|
|
484
|
+
BUILTIN_PROTOTYPE_METHOD_APPROXIMATIONS,
|
|
485
|
+
describeAbsMember,
|
|
486
|
+
builtinProtoMemberNames,
|
|
487
|
+
builtinProtoMember
|
|
488
|
+
};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { Abs } from '@nudojs/core';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 调用点记录(CallRecord)。Abs 唯一真理源。
|
|
5
|
+
* argAbs/resultAbs/throwsAbs 必填;展示/外延在 CaseResult 边界再桥。
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
type CallRecord = {
|
|
9
|
+
fnName: string;
|
|
10
|
+
/** 无损参数 Abs */
|
|
11
|
+
argAbs: Abs[];
|
|
12
|
+
/** 无损结果 Abs(threw 时为 never) */
|
|
13
|
+
resultAbs: Abs;
|
|
14
|
+
/** 无损抛出值 Abs(未抛为 never) */
|
|
15
|
+
throwsAbs: Abs;
|
|
16
|
+
/** Line-relative. Per-fn cache replay shifts this by lineDelta — if you
|
|
17
|
+
* add another position field (callee loc, arg loc), extend
|
|
18
|
+
* shiftCallRecordLines in analyzer.ts in the same change. */
|
|
19
|
+
callLoc?: {
|
|
20
|
+
line: number;
|
|
21
|
+
column: number;
|
|
22
|
+
};
|
|
23
|
+
targetModule?: string;
|
|
24
|
+
targetExport?: string;
|
|
25
|
+
/** export names the same function value was re-exported under after its
|
|
26
|
+
* defining module (barrel `index.js`, CJS forwarding shims); usage-site
|
|
27
|
+
* records stay name-matchable against them */
|
|
28
|
+
targetAliases?: string[];
|
|
29
|
+
/** module whose evaluation created the function value (definition site). */
|
|
30
|
+
fnModule?: string;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
type NudoConfig = {
|
|
34
|
+
env?: string[];
|
|
35
|
+
mocks?: Record<string, string>;
|
|
36
|
+
interface?: {
|
|
37
|
+
/** 侧车 ambient 绑定总开关(check/LSP 执法与 interface 打印共用) */
|
|
38
|
+
autoBind?: boolean;
|
|
39
|
+
/**
|
|
40
|
+
* emit 白名单(Phase 3,§7.3):glob 数组,相对 projectDir。
|
|
41
|
+
* 省略/空 = 不按路径过滤(仍受 --fn/--all 与「默认只刷已有生成段」约束)。
|
|
42
|
+
*/
|
|
43
|
+
emit?: string[] | string;
|
|
44
|
+
};
|
|
45
|
+
};
|
|
46
|
+
type InterfaceConfig = {
|
|
47
|
+
autoBind: boolean;
|
|
48
|
+
/** emit 路径白名单(已归一化;空数组 = 不限制) */
|
|
49
|
+
emit: string[];
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* 归一化 `nudo.interface` 配置段。
|
|
53
|
+
* - autoBind 默认 true
|
|
54
|
+
* - emit:string | string[] → string[](空 = 不限制路径)
|
|
55
|
+
*/
|
|
56
|
+
declare function interfaceConfig(config: NudoConfig | null | undefined): InterfaceConfig;
|
|
57
|
+
/**
|
|
58
|
+
* 极简 glob(`**` / `*` / `?`):相对 projectDir 匹配**源文件**绝对路径
|
|
59
|
+
* (不是侧车路径;侧车随源文件同目录写出)。无白名单 → true。
|
|
60
|
+
* 路径分隔符归一为 `/`。
|
|
61
|
+
*/
|
|
62
|
+
declare function matchesEmitAllowlist(absPath: string, projectDir: string | undefined, patterns: string[]): boolean;
|
|
63
|
+
declare function findProjectConfig(startDir: string): {
|
|
64
|
+
config: NudoConfig;
|
|
65
|
+
projectDir: string;
|
|
66
|
+
} | null;
|
|
67
|
+
|
|
68
|
+
export { type CallRecord as C, type InterfaceConfig as I, type NudoConfig as N, findProjectConfig as f, interfaceConfig as i, matchesEmitAllowlist as m };
|
|
@@ -1,23 +1,21 @@
|
|
|
1
|
-
export { C as CallRecord, I as InterfaceConfig, N as NudoConfig,
|
|
2
|
-
import {
|
|
3
|
-
import { Environment, TypeValue } from '@nudojs/core';
|
|
1
|
+
export { C as CallRecord, I as InterfaceConfig, N as NudoConfig, f as findProjectConfig, i as interfaceConfig } from '../config-NqDRWWpn.js';
|
|
2
|
+
import { Abs, Environment } from '@nudojs/core';
|
|
4
3
|
|
|
5
4
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* 内置类原型成员近似表(Abs 声明)。
|
|
6
|
+
* LSP 补全唯一真值;TypeValue 求值器已删,不再承载 impl 微求值。
|
|
8
7
|
*/
|
|
9
|
-
declare function narrow(test: Node, env: Environment): [trueEnv: Environment, falseEnv: Environment];
|
|
10
8
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
declare const BUILTIN_PROTOTYPE_METHOD_APPROXIMATIONS: Record<string, Record<string, TypeValue>>;
|
|
9
|
+
declare const BUILTIN_PROTOTYPE_METHOD_APPROXIMATIONS: Record<string, Record<string, Abs>>;
|
|
10
|
+
/** LSP detail:Abs fn → `(a: number) => string` 形态 */
|
|
11
|
+
declare function describeAbsMember(a: Abs): string | null;
|
|
12
|
+
declare function builtinProtoMemberNames(className: string): string[];
|
|
13
|
+
declare function builtinProtoMember(className: string, member: string): Abs | null;
|
|
18
14
|
|
|
19
15
|
type LoadedEnv = {
|
|
20
|
-
|
|
16
|
+
/** Abs 原生模块导出(B 路径 / Abs 模块图) */
|
|
17
|
+
modules: Record<string, Record<string, Abs>>;
|
|
18
|
+
globals: Record<string, Abs>;
|
|
21
19
|
};
|
|
22
20
|
declare function preloadPathEnvs(envNames: string[], baseDir: string): Promise<void>;
|
|
23
21
|
declare function loadEnvsAsync(envNames: string[], globalEnv: Environment, baseDir?: string): Promise<LoadedEnv>;
|
|
@@ -25,4 +23,4 @@ declare function loadEnvs(envNames: string[], globalEnv: Environment): LoadedEnv
|
|
|
25
23
|
|
|
26
24
|
declare function resolveNpmNudo(source: string, fromDir: string): string | null;
|
|
27
25
|
|
|
28
|
-
export { BUILTIN_PROTOTYPE_METHOD_APPROXIMATIONS, type LoadedEnv, loadEnvs, loadEnvsAsync,
|
|
26
|
+
export { BUILTIN_PROTOTYPE_METHOD_APPROXIMATIONS, type LoadedEnv, builtinProtoMember, builtinProtoMemberNames, describeAbsMember, loadEnvs, loadEnvsAsync, preloadPathEnvs, resolveNpmNudo };
|
|
@@ -1,68 +1,24 @@
|
|
|
1
1
|
import {
|
|
2
2
|
BUILTIN_PROTOTYPE_METHOD_APPROXIMATIONS,
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
evaluateFunctionFull,
|
|
7
|
-
evaluateProgram,
|
|
3
|
+
builtinProtoMember,
|
|
4
|
+
builtinProtoMemberNames,
|
|
5
|
+
describeAbsMember,
|
|
8
6
|
findProjectConfig,
|
|
9
|
-
getUnreachableRanges,
|
|
10
7
|
interfaceConfig,
|
|
11
8
|
loadEnvs,
|
|
12
9
|
loadEnvsAsync,
|
|
13
|
-
memberMayExistOn,
|
|
14
|
-
narrow,
|
|
15
10
|
preloadPathEnvs,
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
resetMockModules,
|
|
19
|
-
resetUnreachableRanges,
|
|
20
|
-
resolveNpmNudo,
|
|
21
|
-
setCallCollector,
|
|
22
|
-
setCurrentFileDir,
|
|
23
|
-
setCurrentSource,
|
|
24
|
-
setEnvModules,
|
|
25
|
-
setMaxConcreteIter,
|
|
26
|
-
setMockModules,
|
|
27
|
-
setModuleResolver,
|
|
28
|
-
setNodeTypeCollector,
|
|
29
|
-
setProvenanceTracking,
|
|
30
|
-
setSampleCount,
|
|
31
|
-
setUnknownBuiltinHandler,
|
|
32
|
-
setUnknownCollector,
|
|
33
|
-
setUsageSiteTag
|
|
34
|
-
} from "../chunk-FSIHAE7I.js";
|
|
11
|
+
resolveNpmNudo
|
|
12
|
+
} from "../chunk-2VHITMTM.js";
|
|
35
13
|
export {
|
|
36
14
|
BUILTIN_PROTOTYPE_METHOD_APPROXIMATIONS,
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
evaluateFunctionFull,
|
|
41
|
-
evaluateProgram,
|
|
15
|
+
builtinProtoMember,
|
|
16
|
+
builtinProtoMemberNames,
|
|
17
|
+
describeAbsMember,
|
|
42
18
|
findProjectConfig,
|
|
43
|
-
getUnreachableRanges,
|
|
44
19
|
interfaceConfig,
|
|
45
20
|
loadEnvs,
|
|
46
21
|
loadEnvsAsync,
|
|
47
|
-
memberMayExistOn,
|
|
48
|
-
narrow,
|
|
49
22
|
preloadPathEnvs,
|
|
50
|
-
|
|
51
|
-
resetMemo,
|
|
52
|
-
resetMockModules,
|
|
53
|
-
resetUnreachableRanges,
|
|
54
|
-
resolveNpmNudo,
|
|
55
|
-
setCallCollector,
|
|
56
|
-
setCurrentFileDir,
|
|
57
|
-
setCurrentSource,
|
|
58
|
-
setEnvModules,
|
|
59
|
-
setMaxConcreteIter,
|
|
60
|
-
setMockModules,
|
|
61
|
-
setModuleResolver,
|
|
62
|
-
setNodeTypeCollector,
|
|
63
|
-
setProvenanceTracking,
|
|
64
|
-
setSampleCount,
|
|
65
|
-
setUnknownBuiltinHandler,
|
|
66
|
-
setUnknownCollector,
|
|
67
|
-
setUsageSiteTag
|
|
23
|
+
resolveNpmNudo
|
|
68
24
|
};
|