@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.
- package/dist/{chunk-3HCPXPEW.js → chunk-YDM4HHQ4.js} +1783 -1421
- package/dist/evaluator-api.d.ts +12 -1
- package/dist/evaluator-api.js +52 -2
- package/dist/index.d.ts +1 -2
- package/dist/index.js +366 -3572
- package/package.json +23 -11
- package/CHANGELOG.md +0 -41
- package/examples/real-world.js +0 -66
- package/examples/validate-real-world.ts +0 -160
- package/src/__tests__/builtin-advanced.test.ts +0 -292
- package/src/__tests__/builtin-api.test.ts +0 -308
- package/src/__tests__/builtin-functions.test.ts +0 -313
- package/src/__tests__/builtin-map.test.ts +0 -129
- package/src/__tests__/builtin-promise.test.ts +0 -150
- package/src/__tests__/builtin-regexp.test.ts +0 -133
- package/src/__tests__/builtin-set.test.ts +0 -163
- package/src/__tests__/builtin-url.test.ts +0 -256
- package/src/__tests__/builtin-web.test.ts +0 -340
- package/src/__tests__/combination-scenarios.test.ts +0 -384
- package/src/__tests__/edge-cases.test.ts +0 -749
- package/src/__tests__/evaluator-loops.test.ts +0 -283
- package/src/__tests__/evaluator-nullish-coalescing.test.ts +0 -86
- package/src/__tests__/evaluator-optional-chaining.test.ts +0 -37
- package/src/__tests__/evaluator-phase2.test.ts +0 -564
- package/src/__tests__/evaluator-phase3.test.ts +0 -864
- package/src/__tests__/evaluator-refined.test.ts +0 -121
- package/src/__tests__/evaluator-string-methods.test.ts +0 -151
- package/src/__tests__/evaluator.test.ts +0 -943
- package/src/__tests__/mock-arrow-function.test.ts +0 -169
- package/src/__tests__/mock-comparison.test.ts +0 -221
- package/src/__tests__/mock-comprehensive.test.ts +0 -250
- package/src/__tests__/mock-final-integration.test.ts +0 -263
- package/src/__tests__/mock-helpers.test.ts +0 -174
- package/src/__tests__/mock-realworld.test.ts +0 -191
- package/src/__tests__/mock-rest-debug.test.ts +0 -110
- package/src/__tests__/mock-rest-edge.test.ts +0 -176
- package/src/__tests__/mock-sinon-runtime.test.ts +0 -168
- package/src/__tests__/narrowing-discriminated.test.ts +0 -35
- package/src/__tests__/narrowing-in-operator.test.ts +0 -56
- package/src/__tests__/narrowing-switch.test.ts +0 -56
- package/src/__tests__/narrowing-truthiness.test.ts +0 -52
- package/src/__tests__/narrowing.test.ts +0 -82
- package/src/__tests__/nudo-mock-syntax.test.ts +0 -245
- package/src/__tests__/realworld-patterns.test.ts +0 -430
- package/src/__tests__/syntax-sugar.test.ts +0 -345
- package/src/builtins/builtin-intl.ts +0 -17
- package/src/builtins/builtin-map.ts +0 -174
- package/src/builtins/builtin-promise.ts +0 -116
- package/src/builtins/builtin-reflect.ts +0 -30
- package/src/builtins/builtin-regexp.ts +0 -34
- package/src/builtins/builtin-set.ts +0 -131
- package/src/builtins/builtin-symbol.ts +0 -16
- package/src/builtins/builtin-url.ts +0 -58
- package/src/builtins/builtin-weak.ts +0 -22
- package/src/builtins/builtin-web.ts +0 -111
- package/src/builtins/index.ts +0 -61
- package/src/config.ts +0 -32
- package/src/env-loader.ts +0 -174
- package/src/evaluator-api.ts +0 -36
- package/src/evaluator.ts +0 -5623
- package/src/index.ts +0 -931
- package/src/narrowing.ts +0 -537
- package/src/resolve-npm.ts +0 -63
- package/tsconfig.json +0 -9
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { type TypeValue, T } from "@nudojs/core";
|
|
2
|
-
|
|
3
|
-
export const REGEXP_INSTANCE_METHODS: Record<string, (...args: TypeValue[]) => TypeValue> = {
|
|
4
|
-
test: () => T.boolean,
|
|
5
|
-
exec: () => T.union(T.null, T.object({})),
|
|
6
|
-
toString: () => T.string,
|
|
7
|
-
};
|
|
8
|
-
|
|
9
|
-
export const REGEXP_PROPS: Record<string, TypeValue> = {
|
|
10
|
-
source: T.string,
|
|
11
|
-
flags: T.string,
|
|
12
|
-
global: T.boolean,
|
|
13
|
-
ignoreCase: T.boolean,
|
|
14
|
-
multiline: T.boolean,
|
|
15
|
-
dotAll: T.boolean,
|
|
16
|
-
unicode: T.boolean,
|
|
17
|
-
sticky: T.boolean,
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
export function createRegExpType(): TypeValue {
|
|
21
|
-
return T.instanceOf("RegExp", {
|
|
22
|
-
source: T.string,
|
|
23
|
-
flags: T.string,
|
|
24
|
-
global: T.boolean,
|
|
25
|
-
ignoreCase: T.boolean,
|
|
26
|
-
multiline: T.boolean,
|
|
27
|
-
dotAll: T.boolean,
|
|
28
|
-
unicode: T.boolean,
|
|
29
|
-
sticky: T.boolean,
|
|
30
|
-
test: T.fn(["...args"], { type: "BlockStatement", body: [] } as any, undefined as any),
|
|
31
|
-
exec: T.fn(["...args"], { type: "BlockStatement", body: [] } as any, undefined as any),
|
|
32
|
-
toString: T.fn(["...args"], { type: "BlockStatement", body: [] } as any, undefined as any),
|
|
33
|
-
});
|
|
34
|
-
}
|
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
import { type TypeValue, T, simplifyUnion, typeValueEquals } from "@nudojs/core";
|
|
2
|
-
|
|
3
|
-
// Literal/instance values recorded at construction (`new Set([a, b])`) or
|
|
4
|
-
// via add() — precise enough for typeValueEquals lookup in has(). Symbolic
|
|
5
|
-
// values are skipped and has() falls back to boolean.
|
|
6
|
-
function valueTrackable(v: TypeValue | undefined): boolean {
|
|
7
|
-
return v?.kind === "literal" || v?.kind === "instance";
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
// Union values distribute: every member present → true, none present →
|
|
11
|
-
// false, mixed/not comparable → null (symbolic boolean fallback).
|
|
12
|
-
function lookupValues(values: TypeValue[], value: TypeValue): boolean | null {
|
|
13
|
-
if (value.kind === "union") {
|
|
14
|
-
const results = value.members.map((m) => lookupValues(values, m));
|
|
15
|
-
if (results.some((r) => r === null)) return null;
|
|
16
|
-
return results.some((r) => r === true) && results.every((r) => r === true);
|
|
17
|
-
}
|
|
18
|
-
if (!valueTrackable(value)) return null;
|
|
19
|
-
return values.some((v) => typeValueEquals(v, value));
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export const SET_INSTANCE_METHODS: Record<string, (...args: TypeValue[]) => TypeValue> = {
|
|
23
|
-
add: (value: TypeValue, set?: TypeValue) => {
|
|
24
|
-
if (set) {
|
|
25
|
-
const typeArgs = (set as any)._typeArgs || { T: T.unknown };
|
|
26
|
-
(set as any)._typeArgs = {
|
|
27
|
-
T: typeArgs.T.kind === "unknown" ? value : simplifyUnion([typeArgs.T, value]),
|
|
28
|
-
};
|
|
29
|
-
if (valueTrackable(value)) {
|
|
30
|
-
// An exact list can start on the first trackable add (nothing
|
|
31
|
-
// untracked came before); once partial it stays partial.
|
|
32
|
-
if ((set as any)._values === undefined && (set as any)._valuesExact !== false) {
|
|
33
|
-
(set as any)._values = [];
|
|
34
|
-
(set as any)._valuesExact = true;
|
|
35
|
-
}
|
|
36
|
-
if ((set as any)._valuesExact) {
|
|
37
|
-
const values = (set as any)._values as TypeValue[];
|
|
38
|
-
if (!values.some((v) => typeValueEquals(v, value))) values.push(value);
|
|
39
|
-
}
|
|
40
|
-
} else {
|
|
41
|
-
(set as any)._valuesExact = false;
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
return set ?? T.unknown;
|
|
45
|
-
},
|
|
46
|
-
has: (value: TypeValue, set?: TypeValue) => {
|
|
47
|
-
const values = exactSetValues(set);
|
|
48
|
-
if (values) {
|
|
49
|
-
const looked = lookupValues(values, value);
|
|
50
|
-
if (looked !== null) return T.literal(looked);
|
|
51
|
-
}
|
|
52
|
-
return T.boolean;
|
|
53
|
-
},
|
|
54
|
-
delete: (value: TypeValue, set?: TypeValue) => {
|
|
55
|
-
const values = exactSetValues(set);
|
|
56
|
-
if (values && valueTrackable(value)) {
|
|
57
|
-
const idx = values.findIndex((v) => typeValueEquals(v, value));
|
|
58
|
-
if (idx >= 0) {
|
|
59
|
-
values.splice(idx, 1);
|
|
60
|
-
return T.literal(true);
|
|
61
|
-
}
|
|
62
|
-
return T.literal(false);
|
|
63
|
-
}
|
|
64
|
-
return T.boolean;
|
|
65
|
-
},
|
|
66
|
-
clear: (value?: TypeValue, set?: TypeValue) => {
|
|
67
|
-
// s.clear() arrives as clear(receiver): the set sits in the first
|
|
68
|
-
// param slot when the call has no arguments.
|
|
69
|
-
const target = set ?? value;
|
|
70
|
-
if (target && (target as any)._valuesExact) {
|
|
71
|
-
(target as any)._values = [];
|
|
72
|
-
}
|
|
73
|
-
return T.undefined;
|
|
74
|
-
},
|
|
75
|
-
forEach: () => T.undefined,
|
|
76
|
-
values: (set?: TypeValue) => setValuesIterable(set),
|
|
77
|
-
// For Set, keys() is the same as values()
|
|
78
|
-
keys: (set?: TypeValue) => setValuesIterable(set),
|
|
79
|
-
entries: (set?: TypeValue) => {
|
|
80
|
-
const values = exactSetValues(set);
|
|
81
|
-
if (values) return T.tuple(values.map((v) => T.tuple([v, v])));
|
|
82
|
-
const typeArgs = (set as any)?._typeArgs;
|
|
83
|
-
if (typeArgs?.T) return T.array(T.tuple([typeArgs.T, typeArgs.T]));
|
|
84
|
-
return T.array(T.tuple([T.unknown, T.unknown]));
|
|
85
|
-
},
|
|
86
|
-
};
|
|
87
|
-
|
|
88
|
-
// Exact membership side table: present only when every member seen so far
|
|
89
|
-
// (construction elements + adds) was trackable. Partial tables must not
|
|
90
|
-
// decide has()/delete()/iteration — an untracked member could be anything.
|
|
91
|
-
export function exactSetValues(set: TypeValue | undefined): TypeValue[] | undefined {
|
|
92
|
-
if (!set || (set as any)._valuesExact !== true) return undefined;
|
|
93
|
-
return (set as any)._values as TypeValue[] | undefined;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
// values()/keys() keep feeding `new Set(...)`-style consumers: a tuple of
|
|
97
|
-
// the exact members when the side table is complete, else array<T>.
|
|
98
|
-
export function setValuesIterable(set: TypeValue | undefined): TypeValue {
|
|
99
|
-
const values = exactSetValues(set);
|
|
100
|
-
if (values) return T.tuple([...values]);
|
|
101
|
-
const typeArgs = (set as any)?._typeArgs;
|
|
102
|
-
if (typeArgs?.T) return T.array(typeArgs.T);
|
|
103
|
-
return T.array(T.unknown);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
export function createSetType(args?: TypeValue[]): TypeValue {
|
|
107
|
-
const obj = T.instanceOf("Set", {});
|
|
108
|
-
|
|
109
|
-
if (args && args.length > 0) {
|
|
110
|
-
const arg = args[0];
|
|
111
|
-
if (arg.kind === "tuple" || arg.kind === "array") {
|
|
112
|
-
const elements = arg.kind === "tuple" ? arg.elements : [arg.element];
|
|
113
|
-
(obj as any)._typeArgs = { T: simplifyUnion(elements) };
|
|
114
|
-
// Only a fully trackable element list is exact: symbolic elements
|
|
115
|
-
// mean the recorded values are a subset of the real membership.
|
|
116
|
-
const exact = elements.every(valueTrackable);
|
|
117
|
-
if (exact && elements.length > 0) {
|
|
118
|
-
(obj as any)._values = elements;
|
|
119
|
-
(obj as any)._valuesExact = true;
|
|
120
|
-
} else if (!exact) {
|
|
121
|
-
(obj as any)._valuesExact = false;
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
if (!(obj as any)._typeArgs) {
|
|
127
|
-
(obj as any)._typeArgs = { T: T.unknown };
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
return obj;
|
|
131
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { type TypeValue, T } from "@nudojs/core";
|
|
2
|
-
|
|
3
|
-
export const SYMBOL_STATIC_METHODS: Record<string, TypeValue> = {
|
|
4
|
-
for: T.symbol,
|
|
5
|
-
keyFor: T.union(T.string, T.undefined),
|
|
6
|
-
};
|
|
7
|
-
|
|
8
|
-
export const SYMBOL_STATIC_PROPS: Record<string, TypeValue> = {
|
|
9
|
-
asyncIterator: T.symbol,
|
|
10
|
-
iterator: T.symbol,
|
|
11
|
-
toPrimitive: T.symbol,
|
|
12
|
-
toStringTag: T.symbol,
|
|
13
|
-
hasInstance: T.symbol,
|
|
14
|
-
species: T.symbol,
|
|
15
|
-
isConcatSpreadable: T.symbol,
|
|
16
|
-
};
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import { type TypeValue, T } from "@nudojs/core";
|
|
2
|
-
|
|
3
|
-
export const URL_PROPS: Record<string, TypeValue> = {
|
|
4
|
-
href: T.string,
|
|
5
|
-
origin: T.string,
|
|
6
|
-
protocol: T.string,
|
|
7
|
-
host: T.string,
|
|
8
|
-
hostname: T.string,
|
|
9
|
-
port: T.string,
|
|
10
|
-
pathname: T.string,
|
|
11
|
-
search: T.string,
|
|
12
|
-
hash: T.string,
|
|
13
|
-
username: T.string,
|
|
14
|
-
password: T.string,
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
export const URL_INSTANCE_METHODS: Record<string, (...args: TypeValue[]) => TypeValue> = {
|
|
18
|
-
toString: () => T.string,
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
export const URLSearchParams_INSTANCE_METHODS: Record<string, (...args: TypeValue[]) => TypeValue> = {
|
|
22
|
-
get: () => T.union(T.string, T.null),
|
|
23
|
-
set: () => T.undefined,
|
|
24
|
-
has: () => T.boolean,
|
|
25
|
-
delete: () => T.undefined,
|
|
26
|
-
append: () => T.undefined,
|
|
27
|
-
toString: () => T.string,
|
|
28
|
-
getAll: () => T.array(T.string),
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
export function createURLType(): TypeValue {
|
|
32
|
-
return T.instanceOf("URL", {
|
|
33
|
-
href: T.string,
|
|
34
|
-
origin: T.string,
|
|
35
|
-
protocol: T.string,
|
|
36
|
-
host: T.string,
|
|
37
|
-
hostname: T.string,
|
|
38
|
-
port: T.string,
|
|
39
|
-
pathname: T.string,
|
|
40
|
-
search: T.string,
|
|
41
|
-
hash: T.string,
|
|
42
|
-
username: T.string,
|
|
43
|
-
password: T.string,
|
|
44
|
-
toString: T.fn(["...args"], { type: "BlockStatement", body: [] } as any, undefined as any),
|
|
45
|
-
});
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export function createURLSearchParamsType(): TypeValue {
|
|
49
|
-
return T.instanceOf("URLSearchParams", {
|
|
50
|
-
get: T.fn(["...args"], { type: "BlockStatement", body: [] } as any, undefined as any),
|
|
51
|
-
set: T.fn(["...args"], { type: "BlockStatement", body: [] } as any, undefined as any),
|
|
52
|
-
has: T.fn(["...args"], { type: "BlockStatement", body: [] } as any, undefined as any),
|
|
53
|
-
delete: T.fn(["...args"], { type: "BlockStatement", body: [] } as any, undefined as any),
|
|
54
|
-
append: T.fn(["...args"], { type: "BlockStatement", body: [] } as any, undefined as any),
|
|
55
|
-
toString: T.fn(["...args"], { type: "BlockStatement", body: [] } as any, undefined as any),
|
|
56
|
-
getAll: T.fn(["...args"], { type: "BlockStatement", body: [] } as any, undefined as any),
|
|
57
|
-
});
|
|
58
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { type TypeValue, T } from "@nudojs/core";
|
|
2
|
-
|
|
3
|
-
export const WEAKMAP_INSTANCE_METHODS: Record<string, (...args: TypeValue[]) => TypeValue> = {
|
|
4
|
-
get: (_key: TypeValue) => T.union(T.unknown, T.undefined),
|
|
5
|
-
set: (_key: TypeValue, _value: TypeValue, map?: TypeValue) => map ?? T.unknown,
|
|
6
|
-
has: () => T.boolean,
|
|
7
|
-
delete: () => T.boolean,
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
export const WEAKSET_INSTANCE_METHODS: Record<string, (...args: TypeValue[]) => TypeValue> = {
|
|
11
|
-
add: (_value: TypeValue, set?: TypeValue) => set ?? T.unknown,
|
|
12
|
-
has: () => T.boolean,
|
|
13
|
-
delete: () => T.boolean,
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
export function createWeakMapType(): TypeValue {
|
|
17
|
-
return T.instanceOf("WeakMap", {});
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export function createWeakSetType(): TypeValue {
|
|
21
|
-
return T.instanceOf("WeakSet", {});
|
|
22
|
-
}
|
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
import { type TypeValue, T } from "@nudojs/core";
|
|
2
|
-
|
|
3
|
-
export const RESPONSE_PROPS: Record<string, TypeValue> = {
|
|
4
|
-
ok: T.boolean,
|
|
5
|
-
status: T.number,
|
|
6
|
-
statusText: T.string,
|
|
7
|
-
url: T.string,
|
|
8
|
-
type: T.string,
|
|
9
|
-
redirected: T.boolean,
|
|
10
|
-
headers: T.unknown, // Headers instance
|
|
11
|
-
body: T.unknown,
|
|
12
|
-
bodyUsed: T.boolean,
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
export const RESPONSE_INSTANCE_METHODS: Record<string, (...args: TypeValue[]) => TypeValue> = {
|
|
16
|
-
json: () => T.promise(T.unknown),
|
|
17
|
-
text: () => T.promise(T.string),
|
|
18
|
-
arrayBuffer: () => T.promise(T.unknown),
|
|
19
|
-
blob: () => T.promise(T.unknown),
|
|
20
|
-
clone: () => T.unknown,
|
|
21
|
-
formData: () => T.promise(T.unknown),
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
export const HEADERS_INSTANCE_METHODS: Record<string, (...args: TypeValue[]) => TypeValue> = {
|
|
25
|
-
get: () => T.union(T.string, T.null),
|
|
26
|
-
set: () => T.undefined,
|
|
27
|
-
has: () => T.boolean,
|
|
28
|
-
delete: () => T.undefined,
|
|
29
|
-
append: () => T.undefined,
|
|
30
|
-
entries: () => T.unknown,
|
|
31
|
-
keys: () => T.unknown,
|
|
32
|
-
values: () => T.unknown,
|
|
33
|
-
forEach: () => T.undefined,
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
export const FORMDATA_INSTANCE_METHODS: Record<string, (...args: TypeValue[]) => TypeValue> = {
|
|
37
|
-
get: () => T.union(T.string, T.null),
|
|
38
|
-
set: () => T.undefined,
|
|
39
|
-
has: () => T.boolean,
|
|
40
|
-
delete: () => T.undefined,
|
|
41
|
-
append: () => T.undefined,
|
|
42
|
-
getAll: () => T.array(T.unknown),
|
|
43
|
-
entries: () => T.unknown,
|
|
44
|
-
keys: () => T.unknown,
|
|
45
|
-
values: () => T.unknown,
|
|
46
|
-
forEach: () => T.undefined,
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
export const ABORTCONTROLLER_PROPS: Record<string, TypeValue> = {
|
|
50
|
-
signal: T.unknown,
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
export const ABORTCONTROLLER_INSTANCE_METHODS: Record<string, (...args: TypeValue[]) => TypeValue> = {
|
|
54
|
-
abort: () => T.undefined,
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
export function createResponseType(): TypeValue {
|
|
58
|
-
return T.instanceOf("Response", {
|
|
59
|
-
ok: T.boolean,
|
|
60
|
-
status: T.number,
|
|
61
|
-
statusText: T.string,
|
|
62
|
-
url: T.string,
|
|
63
|
-
type: T.string,
|
|
64
|
-
redirected: T.boolean,
|
|
65
|
-
headers: T.unknown,
|
|
66
|
-
body: T.unknown,
|
|
67
|
-
bodyUsed: T.boolean,
|
|
68
|
-
json: T.fn(["...args"], { type: "BlockStatement", body: [] } as any, undefined as any),
|
|
69
|
-
text: T.fn(["...args"], { type: "BlockStatement", body: [] } as any, undefined as any),
|
|
70
|
-
arrayBuffer: T.fn(["...args"], { type: "BlockStatement", body: [] } as any, undefined as any),
|
|
71
|
-
blob: T.fn(["...args"], { type: "BlockStatement", body: [] } as any, undefined as any),
|
|
72
|
-
clone: T.fn(["...args"], { type: "BlockStatement", body: [] } as any, undefined as any),
|
|
73
|
-
formData: T.fn(["...args"], { type: "BlockStatement", body: [] } as any, undefined as any),
|
|
74
|
-
});
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
export function createHeadersType(): TypeValue {
|
|
78
|
-
return T.instanceOf("Headers", {
|
|
79
|
-
get: T.fn(["...args"], { type: "BlockStatement", body: [] } as any, undefined as any),
|
|
80
|
-
set: T.fn(["...args"], { type: "BlockStatement", body: [] } as any, undefined as any),
|
|
81
|
-
has: T.fn(["...args"], { type: "BlockStatement", body: [] } as any, undefined as any),
|
|
82
|
-
delete: T.fn(["...args"], { type: "BlockStatement", body: [] } as any, undefined as any),
|
|
83
|
-
append: T.fn(["...args"], { type: "BlockStatement", body: [] } as any, undefined as any),
|
|
84
|
-
entries: T.fn(["...args"], { type: "BlockStatement", body: [] } as any, undefined as any),
|
|
85
|
-
keys: T.fn(["...args"], { type: "BlockStatement", body: [] } as any, undefined as any),
|
|
86
|
-
values: T.fn(["...args"], { type: "BlockStatement", body: [] } as any, undefined as any),
|
|
87
|
-
forEach: T.fn(["...args"], { type: "BlockStatement", body: [] } as any, undefined as any),
|
|
88
|
-
});
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
export function createFormDataType(): TypeValue {
|
|
92
|
-
return T.instanceOf("FormData", {
|
|
93
|
-
get: T.fn(["...args"], { type: "BlockStatement", body: [] } as any, undefined as any),
|
|
94
|
-
set: T.fn(["...args"], { type: "BlockStatement", body: [] } as any, undefined as any),
|
|
95
|
-
has: T.fn(["...args"], { type: "BlockStatement", body: [] } as any, undefined as any),
|
|
96
|
-
delete: T.fn(["...args"], { type: "BlockStatement", body: [] } as any, undefined as any),
|
|
97
|
-
append: T.fn(["...args"], { type: "BlockStatement", body: [] } as any, undefined as any),
|
|
98
|
-
getAll: T.fn(["...args"], { type: "BlockStatement", body: [] } as any, undefined as any),
|
|
99
|
-
entries: T.fn(["...args"], { type: "BlockStatement", body: [] } as any, undefined as any),
|
|
100
|
-
keys: T.fn(["...args"], { type: "BlockStatement", body: [] } as any, undefined as any),
|
|
101
|
-
values: T.fn(["...args"], { type: "BlockStatement", body: [] } as any, undefined as any),
|
|
102
|
-
forEach: T.fn(["...args"], { type: "BlockStatement", body: [] } as any, undefined as any),
|
|
103
|
-
});
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
export function createAbortControllerType(): TypeValue {
|
|
107
|
-
return T.instanceOf("AbortController", {
|
|
108
|
-
signal: T.unknown,
|
|
109
|
-
abort: T.fn(["...args"], { type: "BlockStatement", body: [] } as any, undefined as any),
|
|
110
|
-
});
|
|
111
|
-
}
|
package/src/builtins/index.ts
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import { type TypeValue } from "@nudojs/core";
|
|
2
|
-
import { PROMISE_STATIC_METHODS } from "./builtin-promise.ts";
|
|
3
|
-
import { MAP_INSTANCE_METHODS, createMapType } from "./builtin-map.ts";
|
|
4
|
-
import { SET_INSTANCE_METHODS, createSetType } from "./builtin-set.ts";
|
|
5
|
-
import { REGEXP_INSTANCE_METHODS, createRegExpType } from "./builtin-regexp.ts";
|
|
6
|
-
import { URL_INSTANCE_METHODS, URLSearchParams_INSTANCE_METHODS, createURLType, createURLSearchParamsType } from "./builtin-url.ts";
|
|
7
|
-
import {
|
|
8
|
-
RESPONSE_INSTANCE_METHODS,
|
|
9
|
-
HEADERS_INSTANCE_METHODS,
|
|
10
|
-
FORMDATA_INSTANCE_METHODS,
|
|
11
|
-
ABORTCONTROLLER_INSTANCE_METHODS,
|
|
12
|
-
createResponseType,
|
|
13
|
-
createHeadersType,
|
|
14
|
-
createFormDataType,
|
|
15
|
-
createAbortControllerType,
|
|
16
|
-
} from "./builtin-web.ts";
|
|
17
|
-
import { WEAKMAP_INSTANCE_METHODS, WEAKSET_INSTANCE_METHODS, createWeakMapType, createWeakSetType } from "./builtin-weak.ts";
|
|
18
|
-
import { SYMBOL_STATIC_METHODS, SYMBOL_STATIC_PROPS } from "./builtin-symbol.ts";
|
|
19
|
-
import { REFLECT_METHODS } from "./builtin-reflect.ts";
|
|
20
|
-
import { INTL_DATETIMEFORMAT_METHODS, INTL_NUMBERFORMAT_METHODS, createDateTimeFormatType, createNumberFormatType } from "./builtin-intl.ts";
|
|
21
|
-
|
|
22
|
-
export const ALL_STATIC_METHODS: Record<string, Record<string, TypeValue>> = {
|
|
23
|
-
Promise: PROMISE_STATIC_METHODS,
|
|
24
|
-
Symbol: SYMBOL_STATIC_METHODS,
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
export const ALL_STATIC_PROPS: Record<string, Record<string, TypeValue>> = {
|
|
28
|
-
Symbol: SYMBOL_STATIC_PROPS,
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
export const ALL_INSTANCE_METHODS: Record<string, Record<string, (...args: TypeValue[]) => TypeValue>> = {
|
|
32
|
-
Map: MAP_INSTANCE_METHODS,
|
|
33
|
-
Set: SET_INSTANCE_METHODS,
|
|
34
|
-
RegExp: REGEXP_INSTANCE_METHODS,
|
|
35
|
-
URL: URL_INSTANCE_METHODS,
|
|
36
|
-
URLSearchParams: URLSearchParams_INSTANCE_METHODS,
|
|
37
|
-
Response: RESPONSE_INSTANCE_METHODS,
|
|
38
|
-
Headers: HEADERS_INSTANCE_METHODS,
|
|
39
|
-
FormData: FORMDATA_INSTANCE_METHODS,
|
|
40
|
-
AbortController: ABORTCONTROLLER_INSTANCE_METHODS,
|
|
41
|
-
WeakMap: WEAKMAP_INSTANCE_METHODS,
|
|
42
|
-
WeakSet: WEAKSET_INSTANCE_METHODS,
|
|
43
|
-
DateTimeFormat: INTL_DATETIMEFORMAT_METHODS,
|
|
44
|
-
NumberFormat: INTL_NUMBERFORMAT_METHODS,
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
export {
|
|
48
|
-
createMapType,
|
|
49
|
-
createSetType,
|
|
50
|
-
createRegExpType,
|
|
51
|
-
createURLType,
|
|
52
|
-
createURLSearchParamsType,
|
|
53
|
-
createResponseType,
|
|
54
|
-
createHeadersType,
|
|
55
|
-
createFormDataType,
|
|
56
|
-
createAbortControllerType,
|
|
57
|
-
createWeakMapType,
|
|
58
|
-
createWeakSetType,
|
|
59
|
-
createDateTimeFormatType,
|
|
60
|
-
createNumberFormatType,
|
|
61
|
-
};
|
package/src/config.ts
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { readFileSync, existsSync } from "node:fs";
|
|
2
|
-
import { resolve, dirname } from "node:path";
|
|
3
|
-
|
|
4
|
-
export type NudoConfig = {
|
|
5
|
-
env?: string[];
|
|
6
|
-
mocks?: Record<string, string>;
|
|
7
|
-
};
|
|
8
|
-
|
|
9
|
-
export function findProjectConfig(startDir: string): { config: NudoConfig; projectDir: string } | null {
|
|
10
|
-
let dir = resolve(startDir);
|
|
11
|
-
const root = resolve("/");
|
|
12
|
-
|
|
13
|
-
while (dir !== root) {
|
|
14
|
-
const pkgPath = resolve(dir, "package.json");
|
|
15
|
-
if (existsSync(pkgPath)) {
|
|
16
|
-
try {
|
|
17
|
-
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
18
|
-
if (pkg.nudo) {
|
|
19
|
-
return { config: pkg.nudo as NudoConfig, projectDir: dir };
|
|
20
|
-
}
|
|
21
|
-
} catch {
|
|
22
|
-
// ignore parse errors
|
|
23
|
-
}
|
|
24
|
-
return null;
|
|
25
|
-
}
|
|
26
|
-
const parent = dirname(dir);
|
|
27
|
-
if (parent === dir) break;
|
|
28
|
-
dir = parent;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
return null;
|
|
32
|
-
}
|
package/src/env-loader.ts
DELETED
|
@@ -1,174 +0,0 @@
|
|
|
1
|
-
import { readFileSync, existsSync, statSync, mkdirSync, writeFileSync } from "node:fs";
|
|
2
|
-
import { resolve as resolvePath, join as joinPath } from "node:path";
|
|
3
|
-
import { pathToFileURL } from "node:url";
|
|
4
|
-
import { createRequire } from "node:module";
|
|
5
|
-
import { createHash } from "node:crypto";
|
|
6
|
-
import { tmpdir } from "node:os";
|
|
7
|
-
import { type TypeValue, type Environment } from "@nudojs/core";
|
|
8
|
-
import { defineEnv as defineEsEnv } from "@nudojs/env/es";
|
|
9
|
-
import { defineEnv as defineWebEnv } from "@nudojs/env/web";
|
|
10
|
-
import { defineEnv as defineNodeEnv } from "@nudojs/env/node";
|
|
11
|
-
|
|
12
|
-
type EnvDefinition = {
|
|
13
|
-
globals: Record<string, TypeValue>;
|
|
14
|
-
modules?: Record<string, Record<string, TypeValue>>;
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
const envFactories: Record<string, () => EnvDefinition> = {
|
|
18
|
-
es: defineEsEnv,
|
|
19
|
-
web: defineWebEnv,
|
|
20
|
-
node: defineNodeEnv,
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
const impliedDeps: Record<string, string[]> = {
|
|
24
|
-
web: ["es"],
|
|
25
|
-
node: ["es"],
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
function resolveEnvNames(names: string[]): string[] {
|
|
29
|
-
const resolved = new Set<string>();
|
|
30
|
-
const visit = (name: string) => {
|
|
31
|
-
if (resolved.has(name)) return;
|
|
32
|
-
const deps = impliedDeps[name];
|
|
33
|
-
if (deps) deps.forEach(visit);
|
|
34
|
-
resolved.add(name);
|
|
35
|
-
};
|
|
36
|
-
names.forEach(visit);
|
|
37
|
-
return [...resolved];
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export type LoadedEnv = {
|
|
41
|
-
modules: Record<string, Record<string, TypeValue>>;
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
// Path-based env files (`/// @nudo:env ./nudo-harvest-node.ts`) are imported
|
|
45
|
-
// asynchronously and cached here; the sync loadEnvs() below consults this map
|
|
46
|
-
// so sync consumers (analyzeFile & friends) see them after a preload pass.
|
|
47
|
-
const pathEnvCache = new Map<string, () => EnvDefinition>();
|
|
48
|
-
// resolvedPath → factory; looked up by trying the directive spelling as-is and
|
|
49
|
-
// resolved against every baseDir seen during preload (covers `./env.ts`,
|
|
50
|
-
// `../env.ts`, and bare `env.ts` spellings from different analyzed files).
|
|
51
|
-
const pathEnvByPath = new Map<string, () => EnvDefinition>();
|
|
52
|
-
const pathEnvBaseDirs = new Set<string>();
|
|
53
|
-
|
|
54
|
-
function isPathEnvName(name: string, baseDir: string): boolean {
|
|
55
|
-
if (name in envFactories) return false;
|
|
56
|
-
if (name.includes("/") || name.startsWith("./") || name.startsWith("../")) return true;
|
|
57
|
-
const resolved = resolvePath(baseDir, name);
|
|
58
|
-
return resolved.endsWith(".ts") && existsSync(resolved);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// A harvested env file lives anywhere on disk (e.g. /tmp) and imports
|
|
62
|
-
// "@nudojs/core" — a bare specifier that only resolves from inside the repo's
|
|
63
|
-
// packages. When the direct import fails, rewrite those specifiers to absolute
|
|
64
|
-
// file URLs (resolved from this package, which depends on them) and import a
|
|
65
|
-
// cached copy under the OS tmpdir.
|
|
66
|
-
function rewriteBareImports(text: string): string | null {
|
|
67
|
-
const require = createRequire(import.meta.url);
|
|
68
|
-
let rewrote = false;
|
|
69
|
-
const out = text.replace(/(["'])(@nudojs\/[a-z0-9-]+)\1/g, (_m, quote: string, spec: string) => {
|
|
70
|
-
try {
|
|
71
|
-
const entry = require.resolve(spec);
|
|
72
|
-
const url = pathToFileURL(entry).href;
|
|
73
|
-
rewrote = true;
|
|
74
|
-
return `${quote}${url}${quote}`;
|
|
75
|
-
} catch {
|
|
76
|
-
return `${quote}${spec}${quote}`;
|
|
77
|
-
}
|
|
78
|
-
});
|
|
79
|
-
return rewrote ? out : null;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
async function importPathEnv(resolvedPath: string, mtimeMs: number): Promise<void> {
|
|
83
|
-
const cacheKey = `${resolvedPath}:${mtimeMs}`;
|
|
84
|
-
if (pathEnvCache.has(cacheKey)) return;
|
|
85
|
-
|
|
86
|
-
let mod: { defineEnv?: unknown } | null = null;
|
|
87
|
-
try {
|
|
88
|
-
const url = pathToFileURL(resolvedPath).href + `?mtime=${mtimeMs}`;
|
|
89
|
-
mod = (await import(url)) as { defineEnv?: unknown };
|
|
90
|
-
} catch {
|
|
91
|
-
// Fall through to the rewritten-copy fallback below.
|
|
92
|
-
mod = null;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
if (!mod) {
|
|
96
|
-
try {
|
|
97
|
-
const text = readFileSync(resolvedPath, "utf-8");
|
|
98
|
-
const rewritten = rewriteBareImports(text);
|
|
99
|
-
if (rewritten === null) return; // nothing to fix; the import failure was something else
|
|
100
|
-
const cacheDir = joinPath(tmpdir(), "nudo-env");
|
|
101
|
-
mkdirSync(cacheDir, { recursive: true });
|
|
102
|
-
const hash = createHash("md5").update(`${resolvedPath}:${mtimeMs}`).digest("hex").slice(0, 16);
|
|
103
|
-
const copyPath = joinPath(cacheDir, `${hash}.ts`);
|
|
104
|
-
writeFileSync(copyPath, rewritten, "utf-8");
|
|
105
|
-
mod = (await import(pathToFileURL(copyPath).href)) as { defineEnv?: unknown };
|
|
106
|
-
} catch {
|
|
107
|
-
return;
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
if (mod && typeof mod.defineEnv === "function") {
|
|
112
|
-
pathEnvCache.set(cacheKey, mod.defineEnv as () => EnvDefinition);
|
|
113
|
-
pathEnvByPath.set(resolvedPath, mod.defineEnv as () => EnvDefinition);
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
function lookupPathEnv(name: string): (() => EnvDefinition) | undefined {
|
|
118
|
-
if (pathEnvByPath.size === 0) return undefined;
|
|
119
|
-
const candidates = name.startsWith("/")
|
|
120
|
-
? [name]
|
|
121
|
-
: [name, ...[...pathEnvBaseDirs].map((d) => resolvePath(d, name))];
|
|
122
|
-
for (const candidate of candidates) {
|
|
123
|
-
const hit = pathEnvByPath.get(candidate);
|
|
124
|
-
if (hit) return hit;
|
|
125
|
-
}
|
|
126
|
-
return undefined;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
export async function preloadPathEnvs(envNames: string[], baseDir: string): Promise<void> {
|
|
130
|
-
pathEnvBaseDirs.add(baseDir);
|
|
131
|
-
for (const name of envNames) {
|
|
132
|
-
if (!isPathEnvName(name, baseDir)) continue;
|
|
133
|
-
const resolved = resolvePath(baseDir, name);
|
|
134
|
-
if (!existsSync(resolved)) continue; // silent skip, matching registry behavior
|
|
135
|
-
try {
|
|
136
|
-
const { mtimeMs } = statSync(resolved);
|
|
137
|
-
await importPathEnv(resolved, mtimeMs);
|
|
138
|
-
} catch {
|
|
139
|
-
// unreadable/unstattable — skip
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
export async function loadEnvsAsync(
|
|
145
|
-
envNames: string[],
|
|
146
|
-
globalEnv: Environment,
|
|
147
|
-
baseDir: string = process.cwd(),
|
|
148
|
-
): Promise<LoadedEnv> {
|
|
149
|
-
await preloadPathEnvs(envNames, baseDir);
|
|
150
|
-
return loadEnvs(envNames, globalEnv);
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
export function loadEnvs(envNames: string[], globalEnv: Environment): LoadedEnv {
|
|
154
|
-
const allModules: Record<string, Record<string, TypeValue>> = {};
|
|
155
|
-
const resolved = resolveEnvNames(envNames);
|
|
156
|
-
|
|
157
|
-
for (const name of resolved) {
|
|
158
|
-
const factory = envFactories[name] ?? lookupPathEnv(name);
|
|
159
|
-
if (!factory) continue;
|
|
160
|
-
const def = factory();
|
|
161
|
-
|
|
162
|
-
for (const [key, value] of Object.entries(def.globals)) {
|
|
163
|
-
globalEnv.bind(key, value);
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
if (def.modules) {
|
|
167
|
-
for (const [modName, exports] of Object.entries(def.modules)) {
|
|
168
|
-
allModules[modName] = { ...allModules[modName], ...exports };
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
return { modules: allModules };
|
|
174
|
-
}
|
package/src/evaluator-api.ts
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
export {
|
|
2
|
-
evaluate,
|
|
3
|
-
evaluateFunction,
|
|
4
|
-
evaluateFunctionFull,
|
|
5
|
-
evaluateProgram,
|
|
6
|
-
setModuleResolver,
|
|
7
|
-
setCurrentFileDir,
|
|
8
|
-
resetMemo,
|
|
9
|
-
getUnreachableRanges,
|
|
10
|
-
resetUnreachableRanges,
|
|
11
|
-
setNodeTypeCollector,
|
|
12
|
-
setCallCollector,
|
|
13
|
-
type CallRecord,
|
|
14
|
-
setUnknownCollector,
|
|
15
|
-
setProvenanceTracking,
|
|
16
|
-
type UnknownRecord,
|
|
17
|
-
setSampleCount,
|
|
18
|
-
setMaxConcreteIter,
|
|
19
|
-
setUnknownBuiltinHandler,
|
|
20
|
-
setEnvModules,
|
|
21
|
-
resetEnvModules,
|
|
22
|
-
setMockModules,
|
|
23
|
-
resetMockModules,
|
|
24
|
-
setCurrentSource,
|
|
25
|
-
memberMayExistOn,
|
|
26
|
-
setUsageSiteTag,
|
|
27
|
-
USAGE_SITE_MODULE,
|
|
28
|
-
} from "./evaluator.ts";
|
|
29
|
-
|
|
30
|
-
export { narrow } from "./narrowing.ts";
|
|
31
|
-
|
|
32
|
-
export { loadEnvs, loadEnvsAsync, preloadPathEnvs, type LoadedEnv } from "./env-loader.ts";
|
|
33
|
-
|
|
34
|
-
export { findProjectConfig, type NudoConfig } from "./config.ts";
|
|
35
|
-
|
|
36
|
-
export { resolveNpmNudo } from "./resolve-npm.ts";
|