@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
@@ -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
- }
@@ -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
- }
@@ -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";