@nudojs/cli 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.
Files changed (64) hide show
  1. package/dist/{chunk-3HCPXPEW.js → chunk-YDM4HHQ4.js} +1783 -1421
  2. package/dist/evaluator-api.d.ts +12 -1
  3. package/dist/evaluator-api.js +52 -2
  4. package/dist/index.d.ts +1 -2
  5. package/dist/index.js +366 -3572
  6. package/package.json +23 -11
  7. package/CHANGELOG.md +0 -41
  8. package/examples/real-world.js +0 -66
  9. package/examples/validate-real-world.ts +0 -160
  10. package/src/__tests__/builtin-advanced.test.ts +0 -292
  11. package/src/__tests__/builtin-api.test.ts +0 -308
  12. package/src/__tests__/builtin-functions.test.ts +0 -313
  13. package/src/__tests__/builtin-map.test.ts +0 -129
  14. package/src/__tests__/builtin-promise.test.ts +0 -150
  15. package/src/__tests__/builtin-regexp.test.ts +0 -133
  16. package/src/__tests__/builtin-set.test.ts +0 -163
  17. package/src/__tests__/builtin-url.test.ts +0 -256
  18. package/src/__tests__/builtin-web.test.ts +0 -340
  19. package/src/__tests__/combination-scenarios.test.ts +0 -384
  20. package/src/__tests__/edge-cases.test.ts +0 -749
  21. package/src/__tests__/evaluator-loops.test.ts +0 -283
  22. package/src/__tests__/evaluator-nullish-coalescing.test.ts +0 -86
  23. package/src/__tests__/evaluator-optional-chaining.test.ts +0 -37
  24. package/src/__tests__/evaluator-phase2.test.ts +0 -564
  25. package/src/__tests__/evaluator-phase3.test.ts +0 -864
  26. package/src/__tests__/evaluator-refined.test.ts +0 -121
  27. package/src/__tests__/evaluator-string-methods.test.ts +0 -151
  28. package/src/__tests__/evaluator.test.ts +0 -943
  29. package/src/__tests__/mock-arrow-function.test.ts +0 -169
  30. package/src/__tests__/mock-comparison.test.ts +0 -221
  31. package/src/__tests__/mock-comprehensive.test.ts +0 -250
  32. package/src/__tests__/mock-final-integration.test.ts +0 -263
  33. package/src/__tests__/mock-helpers.test.ts +0 -174
  34. package/src/__tests__/mock-realworld.test.ts +0 -191
  35. package/src/__tests__/mock-rest-debug.test.ts +0 -110
  36. package/src/__tests__/mock-rest-edge.test.ts +0 -176
  37. package/src/__tests__/mock-sinon-runtime.test.ts +0 -168
  38. package/src/__tests__/narrowing-discriminated.test.ts +0 -35
  39. package/src/__tests__/narrowing-in-operator.test.ts +0 -56
  40. package/src/__tests__/narrowing-switch.test.ts +0 -56
  41. package/src/__tests__/narrowing-truthiness.test.ts +0 -52
  42. package/src/__tests__/narrowing.test.ts +0 -82
  43. package/src/__tests__/nudo-mock-syntax.test.ts +0 -245
  44. package/src/__tests__/realworld-patterns.test.ts +0 -430
  45. package/src/__tests__/syntax-sugar.test.ts +0 -345
  46. package/src/builtins/builtin-intl.ts +0 -17
  47. package/src/builtins/builtin-map.ts +0 -174
  48. package/src/builtins/builtin-promise.ts +0 -116
  49. package/src/builtins/builtin-reflect.ts +0 -30
  50. package/src/builtins/builtin-regexp.ts +0 -34
  51. package/src/builtins/builtin-set.ts +0 -131
  52. package/src/builtins/builtin-symbol.ts +0 -16
  53. package/src/builtins/builtin-url.ts +0 -58
  54. package/src/builtins/builtin-weak.ts +0 -22
  55. package/src/builtins/builtin-web.ts +0 -111
  56. package/src/builtins/index.ts +0 -61
  57. package/src/config.ts +0 -32
  58. package/src/env-loader.ts +0 -174
  59. package/src/evaluator-api.ts +0 -36
  60. package/src/evaluator.ts +0 -5623
  61. package/src/index.ts +0 -931
  62. package/src/narrowing.ts +0 -537
  63. package/src/resolve-npm.ts +0 -63
  64. package/tsconfig.json +0 -9
package/src/narrowing.ts DELETED
@@ -1,537 +0,0 @@
1
- import type { Node } from "@babel/types";
2
- import {
3
- type TypeValue,
4
- type Environment,
5
- T,
6
- narrowType,
7
- subtractType,
8
- getPrimitiveTypeOf,
9
- typeValueEquals,
10
- isSubtypeOf,
11
- createRange,
12
- } from "@nudojs/core";
13
-
14
- /**
15
- * Given a test expression and the current environment, produce two
16
- * environments: one where the test is truthy, one where it is falsy.
17
- */
18
- export function narrow(
19
- test: Node,
20
- env: Environment,
21
- ): [trueEnv: Environment, falseEnv: Environment] {
22
- // a || b:fallthrough(both-false)是链式交集 —— narrow(a) 的 false
23
- // env 再 narrow(b) 的 false。这是 `if (typeof x !== 'object' || x === null)
24
- // return x;` 守卫模式的关键:后续代码里 x 只剩 object 成员。true 侧
25
- // 环境无法并集合并,保守退回未 narrow 的 env。
26
- // a && b 对称:true 侧链式(both-true),false 侧保守。
27
- if (test.type === "LogicalExpression" && (test.operator === "||" || test.operator === "&&")) {
28
- const [trueOfLeft, falseOfLeft] = narrow(test.left, env);
29
- const [, falseOfBoth] = narrow(test.right, falseOfLeft);
30
- const [trueOfBoth] = narrow(test.right, trueOfLeft);
31
- return test.operator === "||"
32
- ? [env, falseOfBoth]
33
- : [trueOfBoth, env];
34
- }
35
-
36
- // typeof x === "string"
37
- if (
38
- test.type === "BinaryExpression" &&
39
- test.operator === "===" &&
40
- isTypeofExpr(test.left) &&
41
- test.right.type === "StringLiteral"
42
- ) {
43
- const target = getTypeofTarget(test.left);
44
- if (target) {
45
- return target ? narrowByTypeof(target, test.right.value, env) : [env, env];
46
- }
47
- }
48
-
49
- // "string" === typeof x
50
- if (
51
- test.type === "BinaryExpression" &&
52
- test.operator === "===" &&
53
- test.left.type === "StringLiteral" &&
54
- isTypeofExpr(test.right)
55
- ) {
56
- const target = getTypeofTarget(test.right);
57
- if (target) {
58
- return target ? narrowByTypeof(target, test.left.value, env) : [env, env];
59
- }
60
- }
61
-
62
- // typeof x !== "string"
63
- if (
64
- test.type === "BinaryExpression" &&
65
- test.operator === "!==" &&
66
- isTypeofExpr(test.left) &&
67
- test.right.type === "StringLiteral"
68
- ) {
69
- const target = getTypeofTarget(test.left);
70
- if (target) {
71
- const [trueEnv, falseEnv] = target ? narrowByTypeof(target, test.right.value, env) : [env, env];
72
- return [falseEnv, trueEnv];
73
- }
74
- }
75
-
76
- // "string" !== typeof x
77
- if (
78
- test.type === "BinaryExpression" &&
79
- test.operator === "!==" &&
80
- test.left.type === "StringLiteral" &&
81
- isTypeofExpr(test.right)
82
- ) {
83
- const target = getTypeofTarget(test.right);
84
- if (target) {
85
- const [trueEnv, falseEnv] = narrowByTypeof(target, test.left.value, env);
86
- return [falseEnv, trueEnv];
87
- }
88
- }
89
-
90
- // obj.prop === literal (discriminated union)
91
- if (
92
- test.type === "BinaryExpression" &&
93
- test.operator === "===" &&
94
- test.left.type === "MemberExpression" &&
95
- test.left.object.type === "Identifier" &&
96
- test.left.property.type === "Identifier" &&
97
- isLiteralNode(test.right)
98
- ) {
99
- return narrowByDiscriminant(test.left.object.name, test.left.property.name, getLiteralValue(test.right), env);
100
- }
101
-
102
- // literal === obj.prop
103
- if (
104
- test.type === "BinaryExpression" &&
105
- test.operator === "===" &&
106
- isLiteralNode(test.left) &&
107
- test.right.type === "MemberExpression" &&
108
- test.right.object.type === "Identifier" &&
109
- test.right.property.type === "Identifier"
110
- ) {
111
- return narrowByDiscriminant(test.right.object.name, test.right.property.name, getLiteralValue(test.left), env);
112
- }
113
-
114
- // obj.prop !== literal
115
- if (
116
- test.type === "BinaryExpression" &&
117
- test.operator === "!==" &&
118
- test.left.type === "MemberExpression" &&
119
- test.left.object.type === "Identifier" &&
120
- test.left.property.type === "Identifier" &&
121
- isLiteralNode(test.right)
122
- ) {
123
- const [trueEnv, falseEnv] = narrowByDiscriminant(test.left.object.name, test.left.property.name, getLiteralValue(test.right), env);
124
- return [falseEnv, trueEnv];
125
- }
126
-
127
- // x === literal
128
- if (
129
- test.type === "BinaryExpression" &&
130
- test.operator === "===" &&
131
- test.left.type === "Identifier" &&
132
- isLiteralNode(test.right)
133
- ) {
134
- return narrowByStrictEqual(test.left.name, getLiteralValue(test.right), env);
135
- }
136
-
137
- // literal === x
138
- if (
139
- test.type === "BinaryExpression" &&
140
- test.operator === "===" &&
141
- isLiteralNode(test.left) &&
142
- test.right.type === "Identifier"
143
- ) {
144
- return narrowByStrictEqual(test.right.name, getLiteralValue(test.left), env);
145
- }
146
-
147
- // x !== literal
148
- if (
149
- test.type === "BinaryExpression" &&
150
- test.operator === "!==" &&
151
- test.left.type === "Identifier" &&
152
- isLiteralNode(test.right)
153
- ) {
154
- const [trueEnv, falseEnv] = narrowByStrictEqual(test.left.name, getLiteralValue(test.right), env);
155
- return [falseEnv, trueEnv];
156
- }
157
-
158
- // literal !== x
159
- if (
160
- test.type === "BinaryExpression" &&
161
- test.operator === "!==" &&
162
- isLiteralNode(test.left) &&
163
- test.right.type === "Identifier"
164
- ) {
165
- const [trueEnv, falseEnv] = narrowByStrictEqual(test.right.name, getLiteralValue(test.left), env);
166
- return [falseEnv, trueEnv];
167
- }
168
-
169
- // x instanceof C
170
- if (
171
- test.type === "BinaryExpression" &&
172
- test.operator === "instanceof" &&
173
- test.left.type === "Identifier" &&
174
- test.right.type === "Identifier"
175
- ) {
176
- return narrowByInstanceof(test.left.name, test.right.name, env);
177
- }
178
-
179
- // x >= literal / x > literal / x <= literal / x < literal
180
- if (
181
- test.type === "BinaryExpression" &&
182
- (test.operator === ">=" || test.operator === ">" || test.operator === "<=" || test.operator === "<") &&
183
- test.left.type === "Identifier" &&
184
- isLiteralNode(test.right)
185
- ) {
186
- const litVal = getLiteralValue(test.right);
187
- if (litVal.kind === "literal" && typeof litVal.value === "number") {
188
- return narrowByComparison(test.left.name, test.operator, litVal.value, env);
189
- }
190
- }
191
-
192
- // literal >= x / literal > x / literal <= x / literal < x
193
- if (
194
- test.type === "BinaryExpression" &&
195
- (test.operator === ">=" || test.operator === ">" || test.operator === "<=" || test.operator === "<") &&
196
- isLiteralNode(test.left) &&
197
- test.right.type === "Identifier"
198
- ) {
199
- const litVal = getLiteralValue(test.left);
200
- if (litVal.kind === "literal" && typeof litVal.value === "number") {
201
- const flipped = { ">=": "<=", ">": "<", "<=": ">=", "<": ">" } as const;
202
- return narrowByComparison(test.right.name, flipped[test.operator as keyof typeof flipped], litVal.value, env);
203
- }
204
- }
205
-
206
- // "key" in obj
207
- if (
208
- test.type === "BinaryExpression" &&
209
- test.operator === "in" &&
210
- test.left.type === "StringLiteral" &&
211
- test.right.type === "Identifier"
212
- ) {
213
- return narrowByPropertyIn(test.left.value, test.right.name, env);
214
- }
215
-
216
- // Array.isArray(x)
217
- if (
218
- test.type === "CallExpression" &&
219
- test.callee.type === "MemberExpression" &&
220
- test.callee.object.type === "Identifier" &&
221
- test.callee.object.name === "Array" &&
222
- test.callee.property.type === "Identifier" &&
223
- test.callee.property.name === "isArray" &&
224
- test.arguments.length === 1 &&
225
- test.arguments[0].type === "Identifier"
226
- ) {
227
- return narrowByIsArray(test.arguments[0].name, env);
228
- }
229
-
230
- // !expr (negate)
231
- if (test.type === "UnaryExpression" && test.operator === "!") {
232
- const [trueEnv, falseEnv] = narrow(test.argument, env);
233
- return [falseEnv, trueEnv];
234
- }
235
-
236
- // Truthiness narrowing: if (x)
237
- if (test.type === "Identifier") {
238
- return narrowByTruthy(test.name, env);
239
- }
240
-
241
- return [env, env];
242
- }
243
-
244
- function isTypeofExpr(node: Node): boolean {
245
- return node.type === "UnaryExpression" && node.operator === "typeof";
246
- }
247
-
248
- /** typeof 目标:标识符(x)或成员访问链(ref.has / ns.fn) */
249
- function getTypeofTarget(node: Node): { kind: "ident"; name: string } | { kind: "member"; objName: string; propName: string } | null {
250
- if (
251
- node.type === "UnaryExpression" &&
252
- node.operator === "typeof" &&
253
- node.argument.type === "Identifier"
254
- ) {
255
- return { kind: "ident", name: node.argument.name };
256
- }
257
- if (
258
- node.type === "UnaryExpression" &&
259
- node.operator === "typeof" &&
260
- node.argument.type === "MemberExpression" &&
261
- node.argument.object.type === "Identifier" &&
262
- !node.argument.computed &&
263
- node.argument.property.type === "Identifier"
264
- ) {
265
- return { kind: "member", objName: node.argument.object.name, propName: node.argument.property.name };
266
- }
267
- return null;
268
- }
269
-
270
- function isLiteralNode(node: Node): boolean {
271
- return (
272
- node.type === "NumericLiteral" ||
273
- node.type === "StringLiteral" ||
274
- node.type === "BooleanLiteral" ||
275
- node.type === "NullLiteral" ||
276
- (node.type === "Identifier" && node.name === "undefined")
277
- );
278
- }
279
-
280
- function getLiteralValue(node: Node): TypeValue {
281
- if (node.type === "NumericLiteral") return T.literal(node.value);
282
- if (node.type === "StringLiteral") return T.literal(node.value);
283
- if (node.type === "BooleanLiteral") return T.literal(node.value);
284
- if (node.type === "NullLiteral") return T.null;
285
- if (node.type === "Identifier" && node.name === "undefined") return T.undefined;
286
- return T.unknown;
287
- }
288
-
289
- const typeofToPrimitive: Record<string, TypeValue> = {
290
- number: T.number,
291
- string: T.string,
292
- boolean: T.boolean,
293
- bigint: T.bigint,
294
- symbol: T.symbol,
295
- };
296
-
297
- /** 内置类实例的原型方法归属(与 evaluator classMethods 表对齐的子集) */
298
- const INSTANCE_METHOD_OWNERS: Record<string, Set<string>> = {
299
- has: new Set(["Set", "Map", "WeakSet", "WeakMap"]),
300
- get: new Set(["Map", "WeakMap"]),
301
- set: new Set(["Map", "WeakMap", "Set"]),
302
- add: new Set(["Set", "WeakSet"]),
303
- delete: new Set(["Set", "Map", "WeakSet", "WeakMap"]),
304
- clear: new Set(["Set", "Map"]),
305
- forEach: new Set(["Set", "Map", "Array"]),
306
- size: new Set(["Set", "Map"]),
307
- keys: new Set(["Set", "Map"]),
308
- values: new Set(["Set", "Map"]),
309
- entries: new Set(["Set", "Map"]),
310
- test: new Set(["RegExp"]),
311
- exec: new Set(["RegExp"]),
312
- };
313
-
314
- function narrowByTypeof(
315
- target: { kind: "ident"; name: string } | { kind: "member"; objName: string; propName: string },
316
- typeStr: string,
317
- env: Environment,
318
- ): [Environment, Environment] {
319
- // 成员目标(typeof ref.has === 'function'):按对象成员中 prop 的类型
320
- // 过滤 union——留下 has 为函数的成员(如 Set),剔除 tuple/{}
321
- if (target.kind === "member") {
322
- const current = env.lookup(target.objName);
323
- if (!current || current.kind !== "union") return [env, env];
324
- const propMatches = (m: TypeValue): boolean => {
325
- let prop: TypeValue | undefined;
326
- if (m.kind === "object") prop = m.properties[target.propName];
327
- else if (m.kind === "instance") {
328
- // instance 的 properties 不含原型方法:按内置类方法表判断
329
- // (Set/Map 的 has 等——与 evaluator 的 classMethods 表保持一致)
330
- if (INSTANCE_METHOD_OWNERS[target.propName]?.has(m.className)) return true;
331
- prop = m.properties[target.propName];
332
- }
333
- if (typeStr === "function") return prop?.kind === "function" || prop?.kind === "unknown";
334
- return true;
335
- };
336
- const narrowed = narrowType(current, propMatches);
337
- const excluded = subtractType(current, propMatches);
338
- if (narrowed.kind === "never") return [env, env];
339
- const trueEnv = env.extend({});
340
- trueEnv.bind(target.objName, narrowed);
341
- const falseEnv = env.extend({});
342
- falseEnv.bind(target.objName, excluded.kind === "never" ? current : excluded);
343
- return [trueEnv, falseEnv];
344
- }
345
-
346
- const varName = target.name;
347
- const current = env.lookup(varName);
348
- const targetPrimitive = typeofToPrimitive[typeStr];
349
-
350
- const matchesPrimitive = (m: TypeValue): boolean => {
351
- const pt = getPrimitiveTypeOf(m);
352
- return pt === typeStr;
353
- };
354
-
355
- if (targetPrimitive) {
356
- const narrowed = narrowType(current, matchesPrimitive);
357
- const excluded = subtractType(current, matchesPrimitive);
358
-
359
- const trueEnv = env.extend({});
360
- trueEnv.bind(varName, narrowed.kind === "never" ? targetPrimitive : narrowed);
361
- const falseEnv = env.extend({});
362
- falseEnv.bind(varName, excluded.kind === "never" ? current : excluded);
363
- return [trueEnv, falseEnv];
364
- }
365
-
366
- if (typeStr === "object") {
367
- const narrowed = narrowType(current, (m) => {
368
- const pt = getPrimitiveTypeOf(m);
369
- return pt === "object";
370
- });
371
- const excluded = subtractType(current, (m) => {
372
- const pt = getPrimitiveTypeOf(m);
373
- return pt === "object";
374
- });
375
- const trueEnv = env.extend({});
376
- trueEnv.bind(varName, narrowed.kind === "never" ? current : narrowed);
377
- const falseEnv = env.extend({});
378
- falseEnv.bind(varName, excluded.kind === "never" ? current : excluded);
379
- return [trueEnv, falseEnv];
380
- }
381
-
382
- if (typeStr === "function") {
383
- const narrowed = narrowType(current, (m) => m.kind === "function");
384
- const excluded = subtractType(current, (m) => m.kind === "function");
385
- const trueEnv = env.extend({});
386
- trueEnv.bind(varName, narrowed.kind === "never" ? current : narrowed);
387
- const falseEnv = env.extend({});
388
- falseEnv.bind(varName, excluded.kind === "never" ? current : excluded);
389
- return [trueEnv, falseEnv];
390
- }
391
-
392
- return [env, env];
393
- }
394
-
395
- function narrowByInstanceof(
396
- varName: string,
397
- className: string,
398
- env: Environment,
399
- ): [Environment, Environment] {
400
- const current = env.lookup(varName);
401
-
402
- const narrowed = narrowType(current, (m) =>
403
- m.kind === "instance" && m.className === className,
404
- );
405
- const excluded = subtractType(current, (m) =>
406
- m.kind === "instance" && m.className === className,
407
- );
408
-
409
- const trueEnv = env.extend({});
410
- trueEnv.bind(varName, narrowed.kind === "never" ? T.instanceOf(className) : narrowed);
411
- const falseEnv = env.extend({});
412
- falseEnv.bind(varName, excluded.kind === "never" ? current : excluded);
413
- return [trueEnv, falseEnv];
414
- }
415
-
416
- function narrowByStrictEqual(
417
- varName: string,
418
- literalTV: TypeValue,
419
- env: Environment,
420
- ): [Environment, Environment] {
421
- const current = env.lookup(varName);
422
-
423
- const narrowed = narrowType(current, (m) => typeValueEquals(m, literalTV));
424
- const excluded = subtractType(current, (m) => typeValueEquals(m, literalTV));
425
-
426
- const trueEnv = env.extend({});
427
- trueEnv.bind(varName, narrowed.kind === "never" ? literalTV : narrowed);
428
- const falseEnv = env.extend({});
429
- falseEnv.bind(varName, excluded.kind === "never" ? current : excluded);
430
- return [trueEnv, falseEnv];
431
- }
432
-
433
- function narrowByComparison(
434
- varName: string,
435
- op: ">=" | ">" | "<=" | "<",
436
- value: number,
437
- env: Environment,
438
- ): [Environment, Environment] {
439
- const current = env.lookup(varName);
440
- if (!isSubtypeOf(current, T.number) && current.kind !== "union") return [env, env];
441
-
442
- const trueEnv = env.extend({});
443
- const falseEnv = env.extend({});
444
-
445
- const trueRange = op === ">=" ? createRange({ min: value })
446
- : op === ">" ? createRange({ min: value + 1 })
447
- : op === "<=" ? createRange({ max: value })
448
- : createRange({ max: value - 1 });
449
-
450
- const falseRange = op === ">=" ? createRange({ max: value - 1 })
451
- : op === ">" ? createRange({ max: value })
452
- : op === "<=" ? createRange({ min: value + 1 })
453
- : createRange({ min: value });
454
-
455
- trueEnv.bind(varName, trueRange);
456
- falseEnv.bind(varName, falseRange);
457
- return [trueEnv, falseEnv];
458
- }
459
-
460
- function narrowByPropertyIn(propName: string, varName: string, env: Environment): [Environment, Environment] {
461
- const current = env.lookup(varName);
462
-
463
- const narrowed = narrowType(current, (m) =>
464
- m.kind === "object" && propName in m.properties
465
- );
466
- const excluded = subtractType(current, (m) =>
467
- m.kind === "object" && propName in m.properties
468
- );
469
-
470
- const trueEnv = env.extend({});
471
- trueEnv.bind(varName, narrowed.kind === "never" ? current : narrowed);
472
- const falseEnv = env.extend({});
473
- falseEnv.bind(varName, excluded.kind === "never" ? current : excluded);
474
- return [trueEnv, falseEnv];
475
- }
476
-
477
- function narrowByIsArray(varName: string, env: Environment): [Environment, Environment] {
478
- const current = env.lookup(varName);
479
-
480
- const narrowed = narrowType(current, (m) => m.kind === "array" || m.kind === "tuple");
481
- const excluded = subtractType(current, (m) => m.kind === "array" || m.kind === "tuple");
482
-
483
- const trueEnv = env.extend({});
484
- trueEnv.bind(varName, narrowed.kind === "never" ? T.array(T.unknown) : narrowed);
485
- const falseEnv = env.extend({});
486
- falseEnv.bind(varName, excluded.kind === "never" ? current : excluded);
487
- return [trueEnv, falseEnv];
488
- }
489
-
490
- function narrowByDiscriminant(
491
- objName: string,
492
- propName: string,
493
- literalValue: TypeValue,
494
- env: Environment,
495
- ): [Environment, Environment] {
496
- const current = env.lookup(objName);
497
-
498
- const narrowed = narrowType(current, (m) => {
499
- if (m.kind !== "object") return false;
500
- const propType = m.properties[propName];
501
- if (!propType) return false;
502
- return typeValueEquals(propType, literalValue);
503
- });
504
-
505
- const excluded = subtractType(current, (m) => {
506
- if (m.kind !== "object") return false;
507
- const propType = m.properties[propName];
508
- if (!propType) return false;
509
- return typeValueEquals(propType, literalValue);
510
- });
511
-
512
- const trueEnv = env.extend({});
513
- trueEnv.bind(objName, narrowed.kind === "never" ? current : narrowed);
514
- const falseEnv = env.extend({});
515
- falseEnv.bind(objName, excluded.kind === "never" ? current : excluded);
516
- return [trueEnv, falseEnv];
517
- }
518
-
519
- function isFalsyType(tv: TypeValue): boolean {
520
- if (tv.kind === "literal") {
521
- return tv.value === null || tv.value === undefined || tv.value === false || tv.value === 0 || tv.value === "";
522
- }
523
- return false;
524
- }
525
-
526
- function narrowByTruthy(varName: string, env: Environment): [Environment, Environment] {
527
- const current = env.lookup(varName);
528
-
529
- const narrowed = narrowType(current, (m) => !isFalsyType(m));
530
- const excluded = subtractType(current, (m) => !isFalsyType(m));
531
-
532
- const trueEnv = env.extend({});
533
- trueEnv.bind(varName, narrowed.kind === "never" ? current : narrowed);
534
- const falseEnv = env.extend({});
535
- falseEnv.bind(varName, excluded.kind === "never" ? current : excluded);
536
- return [trueEnv, falseEnv];
537
- }
@@ -1,63 +0,0 @@
1
- import { readFileSync, existsSync } from "node:fs";
2
- import { resolve, join, dirname } from "node:path";
3
-
4
- function findNodeModules(startDir: string): string | null {
5
- let dir = resolve(startDir);
6
- const root = resolve("/");
7
-
8
- while (dir !== root) {
9
- const nmPath = join(dir, "node_modules");
10
- if (existsSync(nmPath)) return nmPath;
11
- const parent = dirname(dir);
12
- if (parent === dir) break;
13
- dir = parent;
14
- }
15
- return null;
16
- }
17
-
18
- function resolveExportsNudo(exports: unknown, subpath: string): string | null {
19
- if (!exports || typeof exports !== "object") return null;
20
-
21
- const entry = (exports as Record<string, unknown>)[subpath];
22
- if (!entry) return null;
23
-
24
- if (typeof entry === "object" && entry !== null && "nudo" in entry) {
25
- const nudoEntry = (entry as Record<string, unknown>)["nudo"];
26
- if (typeof nudoEntry === "string") return nudoEntry;
27
- }
28
-
29
- return null;
30
- }
31
-
32
- export function resolveNpmNudo(
33
- source: string,
34
- fromDir: string,
35
- ): string | null {
36
- const isRelative = source.startsWith(".") || source.startsWith("/");
37
- if (isRelative) return null;
38
-
39
- const parts = source.startsWith("@")
40
- ? source.split("/").slice(0, 2)
41
- : source.split("/").slice(0, 1);
42
- const pkgName = parts.join("/");
43
- const subpath = source.slice(pkgName.length) || ".";
44
-
45
- const nodeModules = findNodeModules(fromDir);
46
- if (!nodeModules) return null;
47
-
48
- const pkgJsonPath = join(nodeModules, pkgName, "package.json");
49
- if (!existsSync(pkgJsonPath)) return null;
50
-
51
- try {
52
- const pkg = JSON.parse(readFileSync(pkgJsonPath, "utf-8"));
53
- const nudoEntry = resolveExportsNudo(pkg.exports, subpath);
54
- if (nudoEntry) {
55
- const resolved = resolve(dirname(pkgJsonPath), nudoEntry);
56
- if (existsSync(resolved)) return resolved;
57
- }
58
- } catch {
59
- // ignore parse errors
60
- }
61
-
62
- return null;
63
- }
package/tsconfig.json DELETED
@@ -1,9 +0,0 @@
1
- {
2
- "extends": "../../tsconfig.base.json",
3
- "compilerOptions": {
4
- "outDir": "dist",
5
- "rootDir": "src"
6
- },
7
- "include": ["src"],
8
- "references": [{ "path": "../core" }, { "path": "../parser" }]
9
- }