@nudojs/harvester 0.1.0
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/index.d.ts +19 -0
- package/dist/index.js +562 -0
- package/package.json +28 -0
- package/src/__tests__/harvest.test.ts +110 -0
- package/src/index.ts +730 -0
- package/tsconfig.json +11 -0
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { describe, it, expect, beforeAll, afterAll } from "vitest";
|
|
2
|
+
import { rmSync, writeFileSync } from "node:fs";
|
|
3
|
+
import nodePath from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { harvestDts, emitEnvModule, type HarvestedEnv } from "../index.ts";
|
|
6
|
+
|
|
7
|
+
const typesNode = nodePath.resolve(
|
|
8
|
+
nodePath.dirname(fileURLToPath(import.meta.url)),
|
|
9
|
+
"../../../..",
|
|
10
|
+
"node_modules/@types/node",
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
const files = [
|
|
14
|
+
"fs.d.ts",
|
|
15
|
+
"path.d.ts",
|
|
16
|
+
"os.d.ts",
|
|
17
|
+
"buffer.d.ts",
|
|
18
|
+
"buffer.buffer.d.ts",
|
|
19
|
+
"url.d.ts",
|
|
20
|
+
"process.d.ts",
|
|
21
|
+
].map((f) => nodePath.join(typesNode, f));
|
|
22
|
+
|
|
23
|
+
let env: HarvestedEnv;
|
|
24
|
+
let code: string;
|
|
25
|
+
|
|
26
|
+
beforeAll(() => {
|
|
27
|
+
env = harvestDts(files);
|
|
28
|
+
code = emitEnvModule(env, "@types/node");
|
|
29
|
+
}, 120_000);
|
|
30
|
+
|
|
31
|
+
describe("harvestDts", () => {
|
|
32
|
+
it("registers both node:-prefixed and bare module keys", () => {
|
|
33
|
+
expect(env.modules["node:fs"]).toBeDefined();
|
|
34
|
+
expect(env.modules.fs).toBeDefined();
|
|
35
|
+
expect(env.modules["node:path"]).toBeDefined();
|
|
36
|
+
expect(env.modules.path).toBeDefined();
|
|
37
|
+
expect(env.modules["node:os"]).toBeDefined();
|
|
38
|
+
expect(env.modules.os).toBeDefined();
|
|
39
|
+
// The bare key aliases the same record as its node: twin.
|
|
40
|
+
expect(env.modules.fs).toBe(env.modules["node:fs"]);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it("maps fs.readFileSync to a function returning union(string, Buffer)", () => {
|
|
44
|
+
const fn = env.modules["node:fs"].readFileSync as Record<string, unknown>;
|
|
45
|
+
expect(fn.kind).toBe("function");
|
|
46
|
+
const sig = fn._signature as {
|
|
47
|
+
returnType: { kind: string; members?: Array<{ kind: string; type?: string; className?: string }> };
|
|
48
|
+
};
|
|
49
|
+
expect(sig).toBeDefined();
|
|
50
|
+
expect(sig.returnType.kind).toBe("union");
|
|
51
|
+
const members = sig.returnType.members ?? [];
|
|
52
|
+
const hasString = members.some((m) => m.kind === "primitive" && m.type === "string");
|
|
53
|
+
const hasBuffer = members.some((m) => m.kind === "instance" && m.className === "Buffer");
|
|
54
|
+
expect(hasString).toBe(true);
|
|
55
|
+
expect(hasBuffer).toBe(true);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it("maps path.join and os.platform", () => {
|
|
59
|
+
expect(env.modules.path.join.kind).toBe("function");
|
|
60
|
+
const platform = env.modules.os.platform as Record<string, unknown>;
|
|
61
|
+
expect(platform.kind).toBe("function");
|
|
62
|
+
const ret = (platform._signature as { returnType: { kind: string; type?: string; members?: unknown[] } })
|
|
63
|
+
.returnType;
|
|
64
|
+
const isString = ret.kind === "primitive" && ret.type === "string";
|
|
65
|
+
const isStringLiteralUnion =
|
|
66
|
+
ret.kind === "union" &&
|
|
67
|
+
(ret.members ?? []).every(
|
|
68
|
+
(m) => (m as { kind: string; value: unknown }).kind === "literal" && typeof (m as { value: unknown }).value === "string",
|
|
69
|
+
);
|
|
70
|
+
expect(isString || isStringLiteralUnion).toBe(true);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it("exposes harvest stats and global-block symbols", () => {
|
|
74
|
+
expect(env.stats.files).toBeGreaterThanOrEqual(3);
|
|
75
|
+
expect(env.stats.files).toBe(files.length);
|
|
76
|
+
expect(env.stats.symbols).toBeGreaterThan(50);
|
|
77
|
+
// process.d.ts declares `global { var process: NodeJS.Process; }`.
|
|
78
|
+
expect(env.globals.process).toBeDefined();
|
|
79
|
+
expect(env.globals.process.kind).toBe("instance");
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
describe("emitEnvModule", () => {
|
|
84
|
+
const generatedUrl = new URL("./generated-env.tmp.ts", import.meta.url);
|
|
85
|
+
const generatedPath = fileURLToPath(generatedUrl);
|
|
86
|
+
|
|
87
|
+
afterAll(() => {
|
|
88
|
+
rmSync(generatedPath, { force: true });
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it("emits importable TS source", () => {
|
|
92
|
+
expect(code).toContain("// Auto-generated by nudo harvest — DO NOT EDIT");
|
|
93
|
+
expect(code).toContain('import { type TypeValue, T } from "@nudojs/core"');
|
|
94
|
+
expect(code).toContain("export function defineEnv");
|
|
95
|
+
expect(code).toContain("T.fnSig");
|
|
96
|
+
expect(code).toContain("T.instanceOf");
|
|
97
|
+
writeFileSync(generatedPath, code);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it("emitted module evaluates and defines the env", { timeout: 120_000 }, async () => {
|
|
101
|
+
const mod = (await import("./generated-env.tmp.ts")) as {
|
|
102
|
+
defineEnv: () => { globals: Record<string, unknown>; modules: Record<string, Record<string, unknown>> };
|
|
103
|
+
};
|
|
104
|
+
const evaluated = mod.defineEnv();
|
|
105
|
+
expect(evaluated.modules.fs).toBeDefined();
|
|
106
|
+
expect(evaluated.modules["node:fs"].readFileSync).toBeDefined();
|
|
107
|
+
expect((evaluated.modules["node:fs"].readFileSync as { kind: string }).kind).toBe("function");
|
|
108
|
+
expect((evaluated.globals.process as { kind: string }).kind).toBe("instance");
|
|
109
|
+
});
|
|
110
|
+
});
|