dirsql 0.3.17 → 0.3.19
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/cli/die.test.d.ts +2 -0
- package/dist/cli/die.test.d.ts.map +1 -0
- package/dist/cli/die.test.js +29 -0
- package/dist/cli/die.test.js.map +1 -0
- package/dist/cli/dirsql.js +4 -1
- package/dist/cli/dirsql.js.map +1 -1
- package/dist/cli/interpret/buildTables.d.ts +3 -0
- package/dist/cli/interpret/buildTables.d.ts.map +1 -0
- package/dist/cli/interpret/buildTables.js +18 -0
- package/dist/cli/interpret/buildTables.js.map +1 -0
- package/dist/cli/interpret/buildTables.test.d.ts +2 -0
- package/dist/cli/interpret/buildTables.test.d.ts.map +1 -0
- package/dist/cli/interpret/buildTables.test.js +62 -0
- package/dist/cli/interpret/buildTables.test.js.map +1 -0
- package/dist/cli/interpret/dispatchExtract.d.ts +16 -0
- package/dist/cli/interpret/dispatchExtract.d.ts.map +1 -0
- package/dist/cli/interpret/dispatchExtract.js +25 -0
- package/dist/cli/interpret/dispatchExtract.js.map +1 -0
- package/dist/cli/interpret/dispatchExtract.test.d.ts +2 -0
- package/dist/cli/interpret/dispatchExtract.test.d.ts.map +1 -0
- package/dist/cli/interpret/dispatchExtract.test.js +75 -0
- package/dist/cli/interpret/dispatchExtract.test.js.map +1 -0
- package/dist/cli/interpret/errMessage.d.ts +2 -0
- package/dist/cli/interpret/errMessage.d.ts.map +1 -0
- package/dist/cli/interpret/errMessage.js +7 -0
- package/dist/cli/interpret/errMessage.js.map +1 -0
- package/dist/cli/interpret/errMessage.test.d.ts +2 -0
- package/dist/cli/interpret/errMessage.test.d.ts.map +1 -0
- package/dist/cli/interpret/errMessage.test.js +23 -0
- package/dist/cli/interpret/errMessage.test.js.map +1 -0
- package/dist/cli/interpret/index.d.ts +2 -0
- package/dist/cli/interpret/index.d.ts.map +1 -0
- package/dist/cli/interpret/index.js +7 -0
- package/dist/cli/interpret/index.js.map +1 -0
- package/dist/cli/interpret/interpret.d.ts +2 -0
- package/dist/cli/interpret/interpret.d.ts.map +1 -0
- package/dist/cli/interpret/interpret.js +66 -0
- package/dist/cli/interpret/interpret.js.map +1 -0
- package/dist/cli/interpret/interpret.test.d.ts +2 -0
- package/dist/cli/interpret/interpret.test.d.ts.map +1 -0
- package/dist/cli/interpret/interpret.test.js +153 -0
- package/dist/cli/interpret/interpret.test.js.map +1 -0
- package/dist/cli/interpret/loadApp.d.ts +3 -0
- package/dist/cli/interpret/loadApp.d.ts.map +1 -0
- package/dist/cli/interpret/loadApp.js +18 -0
- package/dist/cli/interpret/loadApp.js.map +1 -0
- package/dist/cli/interpret/loadApp.test.d.ts +2 -0
- package/dist/cli/interpret/loadApp.test.d.ts.map +1 -0
- package/dist/cli/interpret/loadApp.test.js +41 -0
- package/dist/cli/interpret/loadApp.test.js.map +1 -0
- package/dist/cli/interpret/writeMessage.d.ts +2 -0
- package/dist/cli/interpret/writeMessage.d.ts.map +1 -0
- package/dist/cli/interpret/writeMessage.js +8 -0
- package/dist/cli/interpret/writeMessage.js.map +1 -0
- package/dist/cli/interpret/writeMessage.test.d.ts +2 -0
- package/dist/cli/interpret/writeMessage.test.d.ts.map +1 -0
- package/dist/cli/interpret/writeMessage.test.js +25 -0
- package/dist/cli/interpret/writeMessage.test.js.map +1 -0
- package/dist/cli/main.d.ts +1 -1
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/main.js +14 -4
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/main.test.d.ts +2 -0
- package/dist/cli/main.test.d.ts.map +1 -0
- package/dist/cli/main.test.js +109 -0
- package/dist/cli/main.test.js.map +1 -0
- package/dist/cli/resolveBinary.test.d.ts +2 -0
- package/dist/cli/resolveBinary.test.d.ts.map +1 -0
- package/dist/cli/resolveBinary.test.js +54 -0
- package/dist/cli/resolveBinary.test.js.map +1 -0
- package/dist/index.d.ts +10 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +13 -1
- package/dist/index.js.map +1 -1
- package/dist/loadNativeCore.test.js +6 -3
- package/dist/loadNativeCore.test.js.map +1 -1
- package/package.json +11 -11
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"die.test.d.ts","sourceRoot":"","sources":["../../src/cli/die.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// Unit tests for `die`.
|
|
2
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
3
|
+
import { die } from "./die.js";
|
|
4
|
+
describe("die", () => {
|
|
5
|
+
let stderrWrite;
|
|
6
|
+
let exit;
|
|
7
|
+
beforeEach(() => {
|
|
8
|
+
stderrWrite = vi.fn();
|
|
9
|
+
exit = vi.fn().mockImplementation((code) => {
|
|
10
|
+
throw new Error(`EXIT_${code}`);
|
|
11
|
+
});
|
|
12
|
+
vi.stubGlobal("process", {
|
|
13
|
+
...process,
|
|
14
|
+
stderr: { write: stderrWrite },
|
|
15
|
+
exit,
|
|
16
|
+
});
|
|
17
|
+
});
|
|
18
|
+
afterEach(() => vi.unstubAllGlobals());
|
|
19
|
+
it("writes a 'dirsql: ' prefixed message to stderr and exits with the given code", () => {
|
|
20
|
+
expect(() => die("boom", 2)).toThrow("EXIT_2");
|
|
21
|
+
expect(stderrWrite).toHaveBeenCalledWith("dirsql: boom\n");
|
|
22
|
+
expect(exit).toHaveBeenCalledWith(2);
|
|
23
|
+
});
|
|
24
|
+
it("defaults the exit code to 1", () => {
|
|
25
|
+
expect(() => die("boom")).toThrow("EXIT_1");
|
|
26
|
+
expect(exit).toHaveBeenCalledWith(1);
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
//# sourceMappingURL=die.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"die.test.js","sourceRoot":"","sources":["../../src/cli/die.test.ts"],"names":[],"mappings":"AAAA,wBAAwB;AAExB,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AACzE,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAE/B,QAAQ,CAAC,KAAK,EAAE,GAAG,EAAE;IACnB,IAAI,WAAqC,CAAC;IAC1C,IAAI,IAA8B,CAAC;IAEnC,UAAU,CAAC,GAAG,EAAE;QACd,WAAW,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;QACtB,IAAI,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,kBAAkB,CAAC,CAAC,IAAY,EAAE,EAAE;YACjD,MAAM,IAAI,KAAK,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC;QAClC,CAAC,CAAC,CAAC;QACH,EAAE,CAAC,UAAU,CAAC,SAAS,EAAE;YACvB,GAAG,OAAO;YACV,MAAM,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE;YAC9B,IAAI;SACL,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,gBAAgB,EAAE,CAAC,CAAC;IAEvC,EAAE,CAAC,8EAA8E,EAAE,GAAG,EAAE;QACtF,MAAM,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAC/C,MAAM,CAAC,WAAW,CAAC,CAAC,oBAAoB,CAAC,gBAAgB,CAAC,CAAC;QAC3D,MAAM,CAAC,IAAI,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6BAA6B,EAAE,GAAG,EAAE;QACrC,MAAM,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAC5C,MAAM,CAAC,IAAI,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
package/dist/cli/dirsql.js
CHANGED
|
@@ -10,5 +10,8 @@
|
|
|
10
10
|
// guard silently skipped main() so `dirsql --version` produced no
|
|
11
11
|
// output (caught by the pack-install build-CI smoke test).
|
|
12
12
|
import { main } from "./main.js";
|
|
13
|
-
main()
|
|
13
|
+
main().catch((e) => {
|
|
14
|
+
process.stderr.write(`dirsql: ${e instanceof Error ? e.message : String(e)}\n`);
|
|
15
|
+
process.exit(1);
|
|
16
|
+
});
|
|
14
17
|
//# sourceMappingURL=dirsql.js.map
|
package/dist/cli/dirsql.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dirsql.js","sourceRoot":"","sources":["../../src/cli/dirsql.ts"],"names":[],"mappings":";AACA,uEAAuE;AACvE,6EAA6E;AAC7E,qEAAqE;AACrE,qEAAqE;AACrE,EAAE;AACF,oEAAoE;AACpE,oEAAoE;AACpE,oEAAoE;AACpE,kEAAkE;AAClE,2DAA2D;AAE3D,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,IAAI,EAAE,CAAC"}
|
|
1
|
+
{"version":3,"file":"dirsql.js","sourceRoot":"","sources":["../../src/cli/dirsql.ts"],"names":[],"mappings":";AACA,uEAAuE;AACvE,6EAA6E;AAC7E,qEAAqE;AACrE,qEAAqE;AACrE,EAAE;AACF,oEAAoE;AACpE,oEAAoE;AACpE,oEAAoE;AACpE,kEAAkE;AAClE,2DAA2D;AAE3D,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,CAAU,EAAE,EAAE;IAC1B,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,WAAW,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAC1D,CAAC;IACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"buildTables.d.ts","sourceRoot":"","sources":["../../../src/cli/interpret/buildTables.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,KAAK,MAAM,EAAE,KAAK,QAAQ,EAAkB,MAAM,gBAAgB,CAAC;AAE5E,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAU9D"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// Build a `name -> TableDef` lookup the dispatcher can index by the
|
|
2
|
+
// `table` field on each extract request. Table name comes from the
|
|
3
|
+
// core's canonical `parseTableName` (Rust-side
|
|
4
|
+
// `dirsql::db::parse_table_name`) so the JS side and the orchestrator
|
|
5
|
+
// agree without a duplicate regex.
|
|
6
|
+
import { parseTableName } from "../../index.js";
|
|
7
|
+
export function buildTables(app) {
|
|
8
|
+
const out = new Map();
|
|
9
|
+
for (const t of app._options.tables ?? []) {
|
|
10
|
+
const name = parseTableName(t.ddl);
|
|
11
|
+
if (name === null) {
|
|
12
|
+
throw new Error(`could not parse table name from DDL: ${t.ddl}`);
|
|
13
|
+
}
|
|
14
|
+
out.set(name, t);
|
|
15
|
+
}
|
|
16
|
+
return out;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=buildTables.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"buildTables.js","sourceRoot":"","sources":["../../../src/cli/interpret/buildTables.ts"],"names":[],"mappings":"AAAA,oEAAoE;AACpE,mEAAmE;AACnE,+CAA+C;AAC/C,sEAAsE;AACtE,mCAAmC;AAEnC,OAAO,EAA8B,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAE5E,MAAM,UAAU,WAAW,CAAC,GAAW;IACrC,MAAM,GAAG,GAAG,IAAI,GAAG,EAAoB,CAAC;IACxC,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,MAAM,IAAI,EAAE,EAAE,CAAC;QAC1C,MAAM,IAAI,GAAG,cAAc,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QACnC,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;YAClB,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;QACnE,CAAC;QACD,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IACnB,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"buildTables.test.d.ts","sourceRoot":"","sources":["../../../src/cli/interpret/buildTables.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
+
import { __setCoreForTesting, } from "../../index.js";
|
|
3
|
+
import { buildTables } from "./buildTables.js";
|
|
4
|
+
const noopExtract = () => [];
|
|
5
|
+
function fakeApp(tables) {
|
|
6
|
+
return { _options: { tables } };
|
|
7
|
+
}
|
|
8
|
+
describe("buildTables", () => {
|
|
9
|
+
beforeEach(() => {
|
|
10
|
+
__setCoreForTesting({
|
|
11
|
+
// biome-ignore lint/suspicious/noExplicitAny: minimal core stub
|
|
12
|
+
DirSQL: {},
|
|
13
|
+
parseTableName: vi
|
|
14
|
+
.fn()
|
|
15
|
+
.mockImplementation((ddl) => /CREATE\s+TABLE\s+(\w+)/i.exec(ddl)?.[1] ?? null),
|
|
16
|
+
});
|
|
17
|
+
});
|
|
18
|
+
afterEach(() => {
|
|
19
|
+
__setCoreForTesting(null);
|
|
20
|
+
});
|
|
21
|
+
it("returns an empty map when the app has no tables", () => {
|
|
22
|
+
expect(buildTables(fakeApp([]))).toEqual(new Map());
|
|
23
|
+
});
|
|
24
|
+
it("treats undefined tables as empty", () => {
|
|
25
|
+
expect(buildTables(fakeApp(undefined))).toEqual(new Map());
|
|
26
|
+
});
|
|
27
|
+
it("keys the lookup by the SQL identifier parsed from each DDL", () => {
|
|
28
|
+
const t = {
|
|
29
|
+
ddl: "CREATE TABLE papers (title TEXT)",
|
|
30
|
+
glob: "**/*.json",
|
|
31
|
+
extract: noopExtract,
|
|
32
|
+
};
|
|
33
|
+
const tables = buildTables(fakeApp([t]));
|
|
34
|
+
expect(tables.get("papers")).toBe(t);
|
|
35
|
+
});
|
|
36
|
+
it("preserves multiple tables under their respective names", () => {
|
|
37
|
+
const a = {
|
|
38
|
+
ddl: "CREATE TABLE a (x TEXT)",
|
|
39
|
+
glob: "a/*",
|
|
40
|
+
extract: noopExtract,
|
|
41
|
+
};
|
|
42
|
+
const b = {
|
|
43
|
+
ddl: "CREATE TABLE b (y TEXT)",
|
|
44
|
+
glob: "b/*",
|
|
45
|
+
extract: noopExtract,
|
|
46
|
+
};
|
|
47
|
+
const tables = buildTables(fakeApp([a, b]));
|
|
48
|
+
expect(tables.get("a")).toBe(a);
|
|
49
|
+
expect(tables.get("b")).toBe(b);
|
|
50
|
+
expect(tables.size).toBe(2);
|
|
51
|
+
});
|
|
52
|
+
it("throws when parseTableName returns null for a DDL", () => {
|
|
53
|
+
const t = {
|
|
54
|
+
// DDL the fake regex won't match -- no `CREATE TABLE` prefix at all.
|
|
55
|
+
ddl: "DROP TABLE old_papers",
|
|
56
|
+
glob: "*.json",
|
|
57
|
+
extract: noopExtract,
|
|
58
|
+
};
|
|
59
|
+
expect(() => buildTables(fakeApp([t]))).toThrow(/could not parse table name/);
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
//# sourceMappingURL=buildTables.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"buildTables.test.js","sourceRoot":"","sources":["../../../src/cli/interpret/buildTables.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AACzE,OAAO,EAGL,mBAAmB,GACpB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE/C,MAAM,WAAW,GAAwB,GAAG,EAAE,CAAC,EAAE,CAAC;AAElD,SAAS,OAAO,CAAC,MAA8B;IAC7C,OAAO,EAAE,QAAQ,EAAE,EAAE,MAAM,EAAE,EAAuB,CAAC;AACvD,CAAC;AAED,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE;IAC3B,UAAU,CAAC,GAAG,EAAE;QACd,mBAAmB,CAAC;YAClB,gEAAgE;YAChE,MAAM,EAAE,EAAS;YACjB,cAAc,EAAE,EAAE;iBACf,EAAE,EAAE;iBACJ,kBAAkB,CACjB,CAAC,GAAW,EAAE,EAAE,CAAC,yBAAyB,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,CAClE;SACJ,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,GAAG,EAAE;QACb,mBAAmB,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iDAAiD,EAAE,GAAG,EAAE;QACzD,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC;IACtD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kCAAkC,EAAE,GAAG,EAAE;QAC1C,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC;IAC7D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4DAA4D,EAAE,GAAG,EAAE;QACpE,MAAM,CAAC,GAAa;YAClB,GAAG,EAAE,kCAAkC;YACvC,IAAI,EAAE,WAAW;YACjB,OAAO,EAAE,WAAW;SACrB,CAAC;QACF,MAAM,MAAM,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACzC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wDAAwD,EAAE,GAAG,EAAE;QAChE,MAAM,CAAC,GAAa;YAClB,GAAG,EAAE,yBAAyB;YAC9B,IAAI,EAAE,KAAK;YACX,OAAO,EAAE,WAAW;SACrB,CAAC;QACF,MAAM,CAAC,GAAa;YAClB,GAAG,EAAE,yBAAyB;YAC9B,IAAI,EAAE,KAAK;YACX,OAAO,EAAE,WAAW;SACrB,CAAC;QACF,MAAM,MAAM,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QAC5C,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAChC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAChC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC9B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mDAAmD,EAAE,GAAG,EAAE;QAC3D,MAAM,CAAC,GAAa;YAClB,qEAAqE;YACrE,GAAG,EAAE,uBAAuB;YAC5B,IAAI,EAAE,QAAQ;YACd,OAAO,EAAE,WAAW;SACrB,CAAC;QACF,MAAM,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAC7C,4BAA4B,CAC7B,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { TableDef } from "../../index.js";
|
|
2
|
+
export interface ExtractRequest {
|
|
3
|
+
type?: string;
|
|
4
|
+
id?: unknown;
|
|
5
|
+
table?: string;
|
|
6
|
+
path?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface ResultMessage {
|
|
9
|
+
type: "result";
|
|
10
|
+
id: unknown;
|
|
11
|
+
ok: boolean;
|
|
12
|
+
rows?: unknown[];
|
|
13
|
+
error?: string;
|
|
14
|
+
}
|
|
15
|
+
export declare function dispatchExtract(req: ExtractRequest, tables: Map<string, TableDef>): Promise<ResultMessage>;
|
|
16
|
+
//# sourceMappingURL=dispatchExtract.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dispatchExtract.d.ts","sourceRoot":"","sources":["../../../src/cli/interpret/dispatchExtract.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAG/C,MAAM,WAAW,cAAc;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,OAAO,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,QAAQ,CAAC;IACf,EAAE,EAAE,OAAO,CAAC;IACZ,EAAE,EAAE,OAAO,CAAC;IACZ,IAAI,CAAC,EAAE,OAAO,EAAE,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAsB,eAAe,CACnC,GAAG,EAAE,cAAc,EACnB,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,GAC5B,OAAO,CAAC,aAAa,CAAC,CAiBxB"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// Single-request handler. Given a parsed extract request and the
|
|
2
|
+
// `name -> TableDef` map, call the user's extract callback (which may
|
|
3
|
+
// be sync or async) and build the NDJSON response payload the loop
|
|
4
|
+
// will write back.
|
|
5
|
+
import { errMessage } from "./errMessage.js";
|
|
6
|
+
export async function dispatchExtract(req, tables) {
|
|
7
|
+
const { id, table: name, path } = req;
|
|
8
|
+
const table = name === undefined ? undefined : tables.get(name);
|
|
9
|
+
if (!table) {
|
|
10
|
+
return {
|
|
11
|
+
type: "result",
|
|
12
|
+
id,
|
|
13
|
+
ok: false,
|
|
14
|
+
error: `unknown table: ${JSON.stringify(name)}`,
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
try {
|
|
18
|
+
const rows = await table.extract(path);
|
|
19
|
+
return { type: "result", id, ok: true, rows };
|
|
20
|
+
}
|
|
21
|
+
catch (e) {
|
|
22
|
+
return { type: "result", id, ok: false, error: errMessage(e) };
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=dispatchExtract.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dispatchExtract.js","sourceRoot":"","sources":["../../../src/cli/interpret/dispatchExtract.ts"],"names":[],"mappings":"AAAA,iEAAiE;AACjE,sEAAsE;AACtE,mEAAmE;AACnE,mBAAmB;AAGnB,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAiB7C,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,GAAmB,EACnB,MAA6B;IAE7B,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,GAAG,CAAC;IACtC,MAAM,KAAK,GAAG,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAChE,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO;YACL,IAAI,EAAE,QAAQ;YACd,EAAE;YACF,EAAE,EAAE,KAAK;YACT,KAAK,EAAE,kBAAkB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE;SAChD,CAAC;IACJ,CAAC;IACD,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,OAAO,CAAC,IAAc,CAAC,CAAC;QACjD,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IAChD,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;IACjE,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dispatchExtract.test.d.ts","sourceRoot":"","sources":["../../../src/cli/interpret/dispatchExtract.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { dispatchExtract } from "./dispatchExtract.js";
|
|
3
|
+
function tableMap(entries) {
|
|
4
|
+
return new Map(entries.map(([n, extract]) => [
|
|
5
|
+
n,
|
|
6
|
+
{
|
|
7
|
+
ddl: `CREATE TABLE ${n} (x TEXT)`,
|
|
8
|
+
glob: "*",
|
|
9
|
+
extract,
|
|
10
|
+
},
|
|
11
|
+
]));
|
|
12
|
+
}
|
|
13
|
+
describe("dispatchExtract", () => {
|
|
14
|
+
it("returns ok=true with the rows the sync extract returned", async () => {
|
|
15
|
+
const tables = tableMap([["papers", (p) => [{ row: p }]]]);
|
|
16
|
+
const out = await dispatchExtract({ type: "extract", id: 1, table: "papers", path: "/a" }, tables);
|
|
17
|
+
expect(out).toEqual({
|
|
18
|
+
type: "result",
|
|
19
|
+
id: 1,
|
|
20
|
+
ok: true,
|
|
21
|
+
rows: [{ row: "/a" }],
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
it("echoes the request id verbatim on success", async () => {
|
|
25
|
+
const tables = tableMap([["t", () => []]]);
|
|
26
|
+
const out = await dispatchExtract({ type: "extract", id: 99, table: "t", path: "/" }, tables);
|
|
27
|
+
expect(out.id).toBe(99);
|
|
28
|
+
});
|
|
29
|
+
it("returns ok=false with a JSON-encoded name when the table is unknown", async () => {
|
|
30
|
+
const out = await dispatchExtract({ type: "extract", id: 5, table: "ghost", path: "/" }, tableMap([]));
|
|
31
|
+
expect(out.ok).toBe(false);
|
|
32
|
+
expect(out.error).toContain('"ghost"');
|
|
33
|
+
});
|
|
34
|
+
it("echoes the request id verbatim on unknown-table failure", async () => {
|
|
35
|
+
const out = await dispatchExtract({ type: "extract", id: 17, table: "ghost", path: "/" }, tableMap([]));
|
|
36
|
+
expect(out.id).toBe(17);
|
|
37
|
+
});
|
|
38
|
+
it("returns ok=false with the message when a sync extract throws", async () => {
|
|
39
|
+
const tables = tableMap([
|
|
40
|
+
[
|
|
41
|
+
"papers",
|
|
42
|
+
() => {
|
|
43
|
+
throw new Error("synthetic");
|
|
44
|
+
},
|
|
45
|
+
],
|
|
46
|
+
]);
|
|
47
|
+
const out = await dispatchExtract({ type: "extract", id: 7, table: "papers", path: "/" }, tables);
|
|
48
|
+
expect(out).toEqual({
|
|
49
|
+
type: "result",
|
|
50
|
+
id: 7,
|
|
51
|
+
ok: false,
|
|
52
|
+
error: "synthetic",
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
it("treats a missing table field as unknown table", async () => {
|
|
56
|
+
const out = await dispatchExtract({ type: "extract", id: 1, path: "/" }, tableMap([["t", () => []]]));
|
|
57
|
+
expect(out.ok).toBe(false);
|
|
58
|
+
expect(out.error).toMatch(/unknown table/);
|
|
59
|
+
});
|
|
60
|
+
it("passes the request path to the extract callback", async () => {
|
|
61
|
+
const seen = [];
|
|
62
|
+
const tables = tableMap([
|
|
63
|
+
[
|
|
64
|
+
"t",
|
|
65
|
+
(p) => {
|
|
66
|
+
seen.push(p);
|
|
67
|
+
return [];
|
|
68
|
+
},
|
|
69
|
+
],
|
|
70
|
+
]);
|
|
71
|
+
await dispatchExtract({ type: "extract", id: 1, table: "t", path: "/abs/x.json" }, tables);
|
|
72
|
+
expect(seen).toEqual(["/abs/x.json"]);
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
//# sourceMappingURL=dispatchExtract.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dispatchExtract.test.js","sourceRoot":"","sources":["../../../src/cli/interpret/dispatchExtract.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errMessage.d.ts","sourceRoot":"","sources":["../../../src/cli/interpret/errMessage.ts"],"names":[],"mappings":"AAIA,wBAAgB,UAAU,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,CAE7C"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// Coerce an unknown thrown value into a human-readable string for
|
|
2
|
+
// stderr / NDJSON `error` fields. `Error.message` when available,
|
|
3
|
+
// `String(e)` otherwise.
|
|
4
|
+
export function errMessage(e) {
|
|
5
|
+
return e instanceof Error ? e.message : String(e);
|
|
6
|
+
}
|
|
7
|
+
//# sourceMappingURL=errMessage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errMessage.js","sourceRoot":"","sources":["../../../src/cli/interpret/errMessage.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,kEAAkE;AAClE,yBAAyB;AAEzB,MAAM,UAAU,UAAU,CAAC,CAAU;IACnC,OAAO,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACpD,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errMessage.test.d.ts","sourceRoot":"","sources":["../../../src/cli/interpret/errMessage.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { errMessage } from "./errMessage.js";
|
|
3
|
+
describe("errMessage", () => {
|
|
4
|
+
it("returns Error.message when the value is an Error", () => {
|
|
5
|
+
expect(errMessage(new Error("boom"))).toBe("boom");
|
|
6
|
+
});
|
|
7
|
+
it("returns Error.message for a subclassed Error", () => {
|
|
8
|
+
expect(errMessage(new TypeError("bad type"))).toBe("bad type");
|
|
9
|
+
});
|
|
10
|
+
it("coerces a string to itself", () => {
|
|
11
|
+
expect(errMessage("plain")).toBe("plain");
|
|
12
|
+
});
|
|
13
|
+
it("coerces null to 'null'", () => {
|
|
14
|
+
expect(errMessage(null)).toBe("null");
|
|
15
|
+
});
|
|
16
|
+
it("coerces a number via String()", () => {
|
|
17
|
+
expect(errMessage(42)).toBe("42");
|
|
18
|
+
});
|
|
19
|
+
it("coerces a plain object via String()", () => {
|
|
20
|
+
expect(errMessage({})).toBe("[object Object]");
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
//# sourceMappingURL=errMessage.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errMessage.test.js","sourceRoot":"","sources":["../../../src/cli/interpret/errMessage.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,QAAQ,CAAC,YAAY,EAAE,GAAG,EAAE;IAC1B,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;QAC1D,MAAM,CAAC,UAAU,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACrD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8CAA8C,EAAE,GAAG,EAAE;QACtD,MAAM,CAAC,UAAU,CAAC,IAAI,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACjE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4BAA4B,EAAE,GAAG,EAAE;QACpC,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC5C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wBAAwB,EAAE,GAAG,EAAE;QAChC,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+BAA+B,EAAE,GAAG,EAAE;QACvC,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACpC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qCAAqC,EAAE,GAAG,EAAE;QAC7C,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cli/interpret/index.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// Re-export the `interpret` entry point so callers (the launcher's
|
|
2
|
+
// `main`) can `import { interpret } from "./interpret/index.js"`.
|
|
3
|
+
//
|
|
4
|
+
// Each helper lives in its own module so unit tests can exercise it in
|
|
5
|
+
// isolation without spawning a subprocess.
|
|
6
|
+
export { interpret } from "./interpret.js";
|
|
7
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/cli/interpret/index.ts"],"names":[],"mappings":"AAAA,mEAAmE;AACnE,kEAAkE;AAClE,EAAE;AACF,uEAAuE;AACvE,2CAA2C;AAE3C,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interpret.d.ts","sourceRoot":"","sources":["../../../src/cli/interpret/interpret.ts"],"names":[],"mappings":"AA2BA,wBAAsB,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CA4CnE"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
// Subcommand entry point for `dirsql interpret <config>`.
|
|
2
|
+
//
|
|
3
|
+
// Glues the per-purpose helpers (`loadApp`, `buildTables`,
|
|
4
|
+
// `dispatchExtract`, `writeMessage`) into the long-running NDJSON
|
|
5
|
+
// loop:
|
|
6
|
+
//
|
|
7
|
+
// handshake (helper -> caller, once on startup):
|
|
8
|
+
// {"type": "config", "state": <app.toJSON()>}
|
|
9
|
+
//
|
|
10
|
+
// extract request (caller -> helper):
|
|
11
|
+
// {"type": "extract", "id": <int>, "table": "<name>", "path": "<abs>"}
|
|
12
|
+
//
|
|
13
|
+
// extract response (helper -> caller):
|
|
14
|
+
// {"type": "result", "id": <int>, "ok": true, "rows": [...]}
|
|
15
|
+
// {"type": "result", "id": <int>, "ok": false, "error": "<msg>"}
|
|
16
|
+
//
|
|
17
|
+
// Exits 0 when stdin closes; non-zero with a single `dirsql interpret:`
|
|
18
|
+
// line on stderr if the config can't be loaded.
|
|
19
|
+
import { createInterface } from "node:readline";
|
|
20
|
+
import { buildTables } from "./buildTables.js";
|
|
21
|
+
import { dispatchExtract } from "./dispatchExtract.js";
|
|
22
|
+
import { errMessage } from "./errMessage.js";
|
|
23
|
+
import { loadApp } from "./loadApp.js";
|
|
24
|
+
import { writeMessage } from "./writeMessage.js";
|
|
25
|
+
export async function interpret(configPath) {
|
|
26
|
+
if (!configPath) {
|
|
27
|
+
process.stderr.write("dirsql interpret: expected one config path, got 0\n");
|
|
28
|
+
return 1;
|
|
29
|
+
}
|
|
30
|
+
let app;
|
|
31
|
+
try {
|
|
32
|
+
app = await loadApp(configPath);
|
|
33
|
+
}
|
|
34
|
+
catch (e) {
|
|
35
|
+
process.stderr.write(`dirsql interpret: ${errMessage(e)}\n`);
|
|
36
|
+
return 1;
|
|
37
|
+
}
|
|
38
|
+
// The SDK constructor kicks off a background scan that calls each
|
|
39
|
+
// table's `extract` for every matched file. If a user `extract`
|
|
40
|
+
// throws, the scan rejects -- and since interpret never awaits the
|
|
41
|
+
// scan (it dispatches to `extract` itself per request), the rejection
|
|
42
|
+
// would surface as an unhandled promise rejection and crash Node.
|
|
43
|
+
// Swallow it here; per-request errors are still reported to the
|
|
44
|
+
// caller in the extract-response.
|
|
45
|
+
app.ready.catch(() => { });
|
|
46
|
+
const tables = buildTables(app);
|
|
47
|
+
writeMessage({ type: "config", state: app.toJSON() });
|
|
48
|
+
for await (const line of createInterface({ input: process.stdin })) {
|
|
49
|
+
if (!line.trim()) {
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
let req;
|
|
53
|
+
try {
|
|
54
|
+
req = JSON.parse(line);
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
if (!req || typeof req !== "object" || req.type !== "extract") {
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
writeMessage(await dispatchExtract(req, tables));
|
|
63
|
+
}
|
|
64
|
+
return 0;
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=interpret.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interpret.js","sourceRoot":"","sources":["../../../src/cli/interpret/interpret.ts"],"names":[],"mappings":"AAAA,0DAA0D;AAC1D,EAAE;AACF,2DAA2D;AAC3D,kEAAkE;AAClE,QAAQ;AACR,EAAE;AACF,mDAAmD;AACnD,kDAAkD;AAClD,EAAE;AACF,wCAAwC;AACxC,2EAA2E;AAC3E,EAAE;AACF,yCAAyC;AACzC,kEAAkE;AAClE,qEAAqE;AACrE,EAAE;AACF,wEAAwE;AACxE,gDAAgD;AAEhD,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAEhD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,UAAkB;IAChD,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,qDAAqD,CAAC,CAAC;QAC5E,OAAO,CAAC,CAAC;IACX,CAAC;IAED,IAAI,GAAW,CAAC;IAChB,IAAI,CAAC;QACH,GAAG,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,CAAC;IAClC,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,qBAAqB,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAC7D,OAAO,CAAC,CAAC;IACX,CAAC;IAED,kEAAkE;IAClE,gEAAgE;IAChE,mEAAmE;IACnE,sEAAsE;IACtE,kEAAkE;IAClE,gEAAgE;IAChE,kCAAkC;IAClC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IAE1B,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;IAEhC,YAAY,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAEtD,IAAI,KAAK,EAAE,MAAM,IAAI,IAAI,eAAe,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC;QACnE,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC;YACjB,SAAS;QACX,CAAC;QACD,IAAI,GAAmE,CAAC;QACxE,IAAI,CAAC;YACH,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACzB,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;QACD,IAAI,CAAC,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YAC9D,SAAS;QACX,CAAC;QACD,YAAY,CAAC,MAAM,eAAe,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC;IACnD,CAAC;IAED,OAAO,CAAC,CAAC;AACX,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interpret.test.d.ts","sourceRoot":"","sources":["../../../src/cli/interpret/interpret.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { Readable } from "node:stream";
|
|
2
|
+
import { afterEach, beforeEach, describe, expect, it, vi, } from "vitest";
|
|
3
|
+
import * as buildTablesMod from "./buildTables.js";
|
|
4
|
+
import * as dispatchMod from "./dispatchExtract.js";
|
|
5
|
+
import { interpret } from "./interpret.js";
|
|
6
|
+
import * as loadAppMod from "./loadApp.js";
|
|
7
|
+
import * as writeMod from "./writeMessage.js";
|
|
8
|
+
function fakeApp(overrides = {}) {
|
|
9
|
+
const app = {
|
|
10
|
+
ready: Promise.resolve(),
|
|
11
|
+
toJSON: () => ({ root: "/x" }),
|
|
12
|
+
_options: { tables: [] },
|
|
13
|
+
...overrides,
|
|
14
|
+
};
|
|
15
|
+
return app;
|
|
16
|
+
}
|
|
17
|
+
function asLines(lines) {
|
|
18
|
+
return Readable.from(lines.map((l) => `${l}\n`));
|
|
19
|
+
}
|
|
20
|
+
describe("interpret", () => {
|
|
21
|
+
let stderrWrite;
|
|
22
|
+
beforeEach(() => {
|
|
23
|
+
stderrWrite = vi.fn();
|
|
24
|
+
vi.stubGlobal("process", {
|
|
25
|
+
...process,
|
|
26
|
+
stdin: asLines([]),
|
|
27
|
+
stderr: { write: stderrWrite },
|
|
28
|
+
});
|
|
29
|
+
vi.spyOn(writeMod, "writeMessage").mockImplementation(() => { });
|
|
30
|
+
vi.spyOn(buildTablesMod, "buildTables").mockReturnValue(new Map());
|
|
31
|
+
vi.spyOn(dispatchMod, "dispatchExtract").mockResolvedValue({
|
|
32
|
+
type: "result",
|
|
33
|
+
id: 1,
|
|
34
|
+
ok: true,
|
|
35
|
+
rows: [],
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
afterEach(() => {
|
|
39
|
+
vi.unstubAllGlobals();
|
|
40
|
+
vi.restoreAllMocks();
|
|
41
|
+
});
|
|
42
|
+
describe("startup", () => {
|
|
43
|
+
it("returns 1 and writes to stderr when configPath is empty", async () => {
|
|
44
|
+
expect(await interpret("")).toBe(1);
|
|
45
|
+
expect(stderrWrite).toHaveBeenCalledExactlyOnceWith("dirsql interpret: expected one config path, got 0\n");
|
|
46
|
+
});
|
|
47
|
+
it("returns 1 and writes a dirsql-prefixed line when loadApp throws", async () => {
|
|
48
|
+
vi.spyOn(loadAppMod, "loadApp").mockRejectedValue(new Error("no app"));
|
|
49
|
+
expect(await interpret("bad.mjs")).toBe(1);
|
|
50
|
+
expect(stderrWrite).toHaveBeenCalledExactlyOnceWith("dirsql interpret: no app\n");
|
|
51
|
+
});
|
|
52
|
+
it("coerces non-Error throws via String() in the stderr message", async () => {
|
|
53
|
+
vi.spyOn(loadAppMod, "loadApp").mockRejectedValue("plain string");
|
|
54
|
+
expect(await interpret("bad.mjs")).toBe(1);
|
|
55
|
+
expect(stderrWrite).toHaveBeenCalledExactlyOnceWith("dirsql interpret: plain string\n");
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
describe("handshake", () => {
|
|
59
|
+
it("writes one config message with app.toJSON() as state", async () => {
|
|
60
|
+
const app = fakeApp({
|
|
61
|
+
toJSON: () => ({ root: "/here", tables: [], ignore: [], persist: false }),
|
|
62
|
+
});
|
|
63
|
+
vi.spyOn(loadAppMod, "loadApp").mockResolvedValue(app);
|
|
64
|
+
await interpret("good.mjs");
|
|
65
|
+
expect(writeMod.writeMessage).toHaveBeenCalledWith({
|
|
66
|
+
type: "config",
|
|
67
|
+
state: { root: "/here", tables: [], ignore: [], persist: false },
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
it("attaches a no-op catch to app.ready to swallow background-scan failures", async () => {
|
|
71
|
+
// Verify the structural property -- interpret CALLS `.catch` on
|
|
72
|
+
// `app.ready` -- without exercising the runtime side effect
|
|
73
|
+
// (which fights vitest's own unhandled-rejection handling).
|
|
74
|
+
const catchSpy = vi.fn(() => Promise.resolve());
|
|
75
|
+
const app = fakeApp({
|
|
76
|
+
ready: { catch: catchSpy },
|
|
77
|
+
});
|
|
78
|
+
vi.spyOn(loadAppMod, "loadApp").mockResolvedValue(app);
|
|
79
|
+
await interpret("good.mjs");
|
|
80
|
+
expect(catchSpy).toHaveBeenCalledOnce();
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
describe("extract loop", () => {
|
|
84
|
+
it("dispatches one extract request and writes the response", async () => {
|
|
85
|
+
vi.spyOn(loadAppMod, "loadApp").mockResolvedValue(fakeApp());
|
|
86
|
+
const req = { type: "extract", id: 1, table: "t", path: "/a" };
|
|
87
|
+
vi.stubGlobal("process", {
|
|
88
|
+
...process,
|
|
89
|
+
stdin: asLines([JSON.stringify(req)]),
|
|
90
|
+
stderr: { write: stderrWrite },
|
|
91
|
+
});
|
|
92
|
+
const expected = {
|
|
93
|
+
type: "result",
|
|
94
|
+
id: 1,
|
|
95
|
+
ok: true,
|
|
96
|
+
rows: [{ row: "/a" }],
|
|
97
|
+
};
|
|
98
|
+
vi.mocked(dispatchMod.dispatchExtract).mockResolvedValue(expected);
|
|
99
|
+
expect(await interpret("good.mjs")).toBe(0);
|
|
100
|
+
expect(dispatchMod.dispatchExtract).toHaveBeenCalledWith(req, new Map());
|
|
101
|
+
// handshake first, then response
|
|
102
|
+
expect(writeMod.writeMessage).toHaveBeenCalledTimes(2);
|
|
103
|
+
expect(writeMod.writeMessage).toHaveBeenLastCalledWith(expected);
|
|
104
|
+
});
|
|
105
|
+
it("skips blank lines silently", async () => {
|
|
106
|
+
vi.spyOn(loadAppMod, "loadApp").mockResolvedValue(fakeApp());
|
|
107
|
+
vi.stubGlobal("process", {
|
|
108
|
+
...process,
|
|
109
|
+
stdin: asLines(["", " "]),
|
|
110
|
+
stderr: { write: stderrWrite },
|
|
111
|
+
});
|
|
112
|
+
expect(await interpret("good.mjs")).toBe(0);
|
|
113
|
+
expect(dispatchMod.dispatchExtract).not.toHaveBeenCalled();
|
|
114
|
+
// handshake only
|
|
115
|
+
expect(writeMod.writeMessage).toHaveBeenCalledOnce();
|
|
116
|
+
});
|
|
117
|
+
it("skips malformed JSON silently", async () => {
|
|
118
|
+
vi.spyOn(loadAppMod, "loadApp").mockResolvedValue(fakeApp());
|
|
119
|
+
vi.stubGlobal("process", {
|
|
120
|
+
...process,
|
|
121
|
+
stdin: asLines(["not json", "{also bad"]),
|
|
122
|
+
stderr: { write: stderrWrite },
|
|
123
|
+
});
|
|
124
|
+
expect(await interpret("good.mjs")).toBe(0);
|
|
125
|
+
expect(dispatchMod.dispatchExtract).not.toHaveBeenCalled();
|
|
126
|
+
});
|
|
127
|
+
it("skips non-extract messages silently", async () => {
|
|
128
|
+
vi.spyOn(loadAppMod, "loadApp").mockResolvedValue(fakeApp());
|
|
129
|
+
vi.stubGlobal("process", {
|
|
130
|
+
...process,
|
|
131
|
+
stdin: asLines([JSON.stringify({ type: "ping" })]),
|
|
132
|
+
stderr: { write: stderrWrite },
|
|
133
|
+
});
|
|
134
|
+
expect(await interpret("good.mjs")).toBe(0);
|
|
135
|
+
expect(dispatchMod.dispatchExtract).not.toHaveBeenCalled();
|
|
136
|
+
});
|
|
137
|
+
it("skips a null / non-object JSON payload silently", async () => {
|
|
138
|
+
vi.spyOn(loadAppMod, "loadApp").mockResolvedValue(fakeApp());
|
|
139
|
+
vi.stubGlobal("process", {
|
|
140
|
+
...process,
|
|
141
|
+
stdin: asLines(["null", "42", "[]"]),
|
|
142
|
+
stderr: { write: stderrWrite },
|
|
143
|
+
});
|
|
144
|
+
expect(await interpret("good.mjs")).toBe(0);
|
|
145
|
+
expect(dispatchMod.dispatchExtract).not.toHaveBeenCalled();
|
|
146
|
+
});
|
|
147
|
+
it("returns 0 when stdin closes", async () => {
|
|
148
|
+
vi.spyOn(loadAppMod, "loadApp").mockResolvedValue(fakeApp());
|
|
149
|
+
expect(await interpret("good.mjs")).toBe(0);
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
//# sourceMappingURL=interpret.test.js.map
|