@lotics/cli 0.64.0 → 0.65.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/app_commands.d.ts +16 -9
- package/dist/app_commands.js +67 -37
- package/dist/app_commands.test.js +32 -9
- package/dist/generate_app_workflows_dts.js +1 -1
- package/dist/generate_app_workflows_dts.test.js +10 -0
- package/dist/src/cli.js +448 -20
- package/package.json +1 -1
package/dist/app_commands.d.ts
CHANGED
|
@@ -87,16 +87,23 @@ export declare function writeWorkflowFile(projectDir: string, alias: string, sou
|
|
|
87
87
|
*/
|
|
88
88
|
export declare function stripWorkflowHeader(content: string): string;
|
|
89
89
|
/**
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
*
|
|
90
|
+
* Heal a pre-existing app's `tsconfig.json` so its generated types load and its
|
|
91
|
+
* `npm run typecheck` stays honest. Idempotent, run on every pull / codegen /
|
|
92
|
+
* deploy. Two things the current starter ships but an app SCAFFOLDED before those
|
|
93
|
+
* releases (or with a hand-written tsconfig) can lack:
|
|
94
|
+
*
|
|
95
|
+
* 1. `include`: a bare `.lotics` is rewritten to the recursive `LOTICS_INCLUDE_GLOB`.
|
|
96
|
+
* A bare dot-dir is skipped by TypeScript's include-glob walk, so the codegen'd
|
|
97
|
+
* `.d.ts` never enter the program — every `useQuery`/`useWorkflow`/`useAgentRun`
|
|
98
|
+
* param and result silently falls back to `unknown`.
|
|
99
|
+
* 2. `exclude`: the workflow-body globs — the bodies use the app's DOM lib (the
|
|
100
|
+
* server doesn't) and the per-alias ambient globals collide on `trigger`,
|
|
101
|
+
* poisoning typecheck. Checked separately by `lotics app workflow check`.
|
|
102
|
+
*
|
|
103
|
+
* A missing / unparseable tsconfig is a non-fatal warn (the caller still succeeds);
|
|
104
|
+
* the author fixes the config.
|
|
98
105
|
*/
|
|
99
|
-
export declare function
|
|
106
|
+
export declare function ensureAppTsconfig(projectDir: string): void;
|
|
100
107
|
/**
|
|
101
108
|
* `lotics app codegen [path]` — regenerate every `.lotics/` artifact from the
|
|
102
109
|
* manifest + workspace schema, WITHOUT a deploy. The `.d.ts` companions are
|
package/dist/app_commands.js
CHANGED
|
@@ -64,6 +64,17 @@ const WORKFLOW_GLOBALS_DIR = path.join(".lotics", "workflows");
|
|
|
64
64
|
* with `/` separators — tsconfig globs are POSIX even on Windows.
|
|
65
65
|
*/
|
|
66
66
|
const WORKFLOW_TSCONFIG_EXCLUDES = ["src/workflows", ".lotics/workflows"];
|
|
67
|
+
/**
|
|
68
|
+
* The include glob that actually loads the generated `.lotics/*.d.ts` companions.
|
|
69
|
+
* A BARE `.lotics` entry loads NONE of them: TypeScript's include-glob walk skips
|
|
70
|
+
* dot-directories, so `useQuery` / `useWorkflow` / `useAgentRun` fall back to their
|
|
71
|
+
* untyped string overloads and every param / input / result silently becomes
|
|
72
|
+
* `unknown`. The current starter emits the glob (`starter_template.ts`); apps
|
|
73
|
+
* scaffolded before that fix shipped the bare form and need healing.
|
|
74
|
+
*/
|
|
75
|
+
const LOTICS_INCLUDE_GLOB = ".lotics/**/*";
|
|
76
|
+
/** The bare `.lotics` forms an older starter emitted — all skipped by the glob walk. */
|
|
77
|
+
const STALE_LOTICS_INCLUDES = new Set([".lotics", "./.lotics", ".lotics/"]);
|
|
67
78
|
/**
|
|
68
79
|
* The `async function __workflow(...)` wrapper a workflow body sits inside —
|
|
69
80
|
* the SAME envelope the server compiles the body within at `set_app_workflow`
|
|
@@ -304,20 +315,27 @@ function writeAppMeta(projectDir, meta) {
|
|
|
304
315
|
fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
|
|
305
316
|
}
|
|
306
317
|
/**
|
|
307
|
-
*
|
|
308
|
-
*
|
|
309
|
-
*
|
|
310
|
-
*
|
|
311
|
-
*
|
|
312
|
-
*
|
|
313
|
-
*
|
|
314
|
-
*
|
|
318
|
+
* Heal a pre-existing app's `tsconfig.json` so its generated types load and its
|
|
319
|
+
* `npm run typecheck` stays honest. Idempotent, run on every pull / codegen /
|
|
320
|
+
* deploy. Two things the current starter ships but an app SCAFFOLDED before those
|
|
321
|
+
* releases (or with a hand-written tsconfig) can lack:
|
|
322
|
+
*
|
|
323
|
+
* 1. `include`: a bare `.lotics` is rewritten to the recursive `LOTICS_INCLUDE_GLOB`.
|
|
324
|
+
* A bare dot-dir is skipped by TypeScript's include-glob walk, so the codegen'd
|
|
325
|
+
* `.d.ts` never enter the program — every `useQuery`/`useWorkflow`/`useAgentRun`
|
|
326
|
+
* param and result silently falls back to `unknown`.
|
|
327
|
+
* 2. `exclude`: the workflow-body globs — the bodies use the app's DOM lib (the
|
|
328
|
+
* server doesn't) and the per-alias ambient globals collide on `trigger`,
|
|
329
|
+
* poisoning typecheck. Checked separately by `lotics app workflow check`.
|
|
330
|
+
*
|
|
331
|
+
* A missing / unparseable tsconfig is a non-fatal warn (the caller still succeeds);
|
|
332
|
+
* the author fixes the config.
|
|
315
333
|
*/
|
|
316
|
-
export function
|
|
334
|
+
export function ensureAppTsconfig(projectDir) {
|
|
317
335
|
const tsconfigPath = path.join(projectDir, "tsconfig.json");
|
|
318
336
|
if (!fs.existsSync(tsconfigPath)) {
|
|
319
|
-
console.error(`⚠ No tsconfig.json at ${projectDir} — could not ensure
|
|
320
|
-
`
|
|
337
|
+
console.error(`⚠ No tsconfig.json at ${projectDir} — could not ensure "include" has "${LOTICS_INCLUDE_GLOB}" ` +
|
|
338
|
+
`(a bare .lotics loads none of the generated types) or "exclude" has ${WORKFLOW_TSCONFIG_EXCLUDES.join(", ")}.`);
|
|
321
339
|
return;
|
|
322
340
|
}
|
|
323
341
|
let parsed;
|
|
@@ -326,30 +344,47 @@ export function ensureWorkflowTsconfigExcludes(projectDir) {
|
|
|
326
344
|
}
|
|
327
345
|
catch (err) {
|
|
328
346
|
console.error(`⚠ Could not parse tsconfig.json (${err instanceof Error ? err.message : String(err)}) — ` +
|
|
329
|
-
`
|
|
347
|
+
`ensure "include" has "${LOTICS_INCLUDE_GLOB}" and "exclude" has ${WORKFLOW_TSCONFIG_EXCLUDES.join(", ")} manually.`);
|
|
330
348
|
return;
|
|
331
349
|
}
|
|
332
350
|
if (!parsed || typeof parsed !== "object")
|
|
333
351
|
return;
|
|
334
|
-
|
|
335
|
-
//
|
|
336
|
-
//
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
352
|
+
const changes = [];
|
|
353
|
+
// 1. Heal a stale bare `.lotics` include so the generated `.d.ts` actually load
|
|
354
|
+
// (a bare dot-dir is invisible to TypeScript's include-glob walk).
|
|
355
|
+
if (Array.isArray(parsed.include)) {
|
|
356
|
+
const inc = parsed.include.filter((e) => typeof e === "string");
|
|
357
|
+
if (inc.some((e) => STALE_LOTICS_INCLUDES.has(e))) {
|
|
358
|
+
const healed = inc.map((e) => (STALE_LOTICS_INCLUDES.has(e) ? LOTICS_INCLUDE_GLOB : e));
|
|
359
|
+
parsed.include = healed.filter((e, i) => healed.indexOf(e) === i); // dedupe if the glob was already present
|
|
360
|
+
changes.push(`rewrote a bare ".lotics" to "${LOTICS_INCLUDE_GLOB}" in "include" (a dot-dir loads zero generated types)`);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
// 2. Ensure the workflow-body excludes. `exclude` is a TOP-LEVEL tsconfig field —
|
|
364
|
+
// tsc ignores `compilerOptions.exclude`, so they must land at the top level.
|
|
365
|
+
const currentEx = Array.isArray(parsed.exclude)
|
|
366
|
+
? parsed.exclude.filter((e) => typeof e === "string")
|
|
367
|
+
: [];
|
|
368
|
+
const toAdd = WORKFLOW_TSCONFIG_EXCLUDES.filter((g) => !currentEx.includes(g));
|
|
369
|
+
if (toAdd.length > 0) {
|
|
370
|
+
parsed.exclude = [...currentEx, ...toAdd];
|
|
371
|
+
changes.push(`added ${toAdd.join(", ")} to "exclude"`);
|
|
372
|
+
}
|
|
373
|
+
if (changes.length === 0)
|
|
341
374
|
return;
|
|
342
|
-
parsed.exclude = [...currentStrings, ...toAdd];
|
|
343
375
|
fs.writeFileSync(tsconfigPath, JSON.stringify(parsed, null, 2) + "\n");
|
|
344
|
-
console.error(`Patched tsconfig.json:
|
|
345
|
-
`(check them with: lotics app workflow check).`);
|
|
376
|
+
console.error(`Patched tsconfig.json: ${changes.join("; ")}.`);
|
|
346
377
|
}
|
|
347
378
|
/**
|
|
348
|
-
* Write
|
|
349
|
-
* manifest's
|
|
350
|
-
* dev / deploy
|
|
351
|
-
*
|
|
352
|
-
*
|
|
379
|
+
* Write the three `.lotics/app_{workflows,queries,agents}.d.ts` companions from
|
|
380
|
+
* the manifest's maps, then heal the app's tsconfig so they actually load. Called
|
|
381
|
+
* from `app create / pull / dev / deploy / codegen`, so the augmented `AppWorkflows`
|
|
382
|
+
* / `AppQueries` / `AppAgents` types stay in sync with the manifest.
|
|
383
|
+
*
|
|
384
|
+
* The heal is at the write boundary on purpose: a `.d.ts` written but not loaded is
|
|
385
|
+
* useless (a bare `.lotics` include is skipped by TypeScript's include-glob walk and
|
|
386
|
+
* loads zero of them), so `ensureAppTsconfig` couples "wrote the types" with "the
|
|
387
|
+
* program can see them" — no caller can do one without the other.
|
|
353
388
|
*/
|
|
354
389
|
function writeAppDts(projectDir, manifest) {
|
|
355
390
|
const dotLotics = path.join(projectDir, ".lotics");
|
|
@@ -361,6 +396,7 @@ function writeAppDts(projectDir, manifest) {
|
|
|
361
396
|
];
|
|
362
397
|
for (const [file, content] of written)
|
|
363
398
|
fs.writeFileSync(file, content);
|
|
399
|
+
ensureAppTsconfig(projectDir);
|
|
364
400
|
return written.map(([file]) => file);
|
|
365
401
|
}
|
|
366
402
|
/**
|
|
@@ -450,10 +486,6 @@ export async function appCodegen(args) {
|
|
|
450
486
|
// it, so the local typecheck tracks the current workspace schema. Aliases
|
|
451
487
|
// never pulled (no body file yet) are skipped — codegen isn't a pull.
|
|
452
488
|
await refreshWorkflowGlobals(args.client, projectDir, meta.app_id, Object.keys(meta.workflows ?? {}));
|
|
453
|
-
// Keep the main tsconfig excluding the workflow-body globs (idempotent) so
|
|
454
|
-
// npm run typecheck never loads the bodies or their colliding per-alias globals.
|
|
455
|
-
if (Object.keys(meta.workflows ?? {}).length > 0)
|
|
456
|
-
ensureWorkflowTsconfigExcludes(projectDir);
|
|
457
489
|
}
|
|
458
490
|
/**
|
|
459
491
|
* For each bound alias that already has a local body file, fetch its current
|
|
@@ -745,9 +777,6 @@ export async function appPull(client, args) {
|
|
|
745
777
|
if (written.length > 0) {
|
|
746
778
|
console.error(`Wrote ${written.length} workflow ${written.length === 1 ? "body" : "bodies"} to ${WORKFLOWS_DIR}/ (${written.join(", ")})`);
|
|
747
779
|
}
|
|
748
|
-
// A pre-existing app's tsconfig may predate the workflow-body excludes; pulling
|
|
749
|
-
// bodies into it would break its npm run typecheck. Patch it idempotently.
|
|
750
|
-
ensureWorkflowTsconfigExcludes(targetPath);
|
|
751
780
|
}
|
|
752
781
|
console.error(`Installing npm dependencies...`);
|
|
753
782
|
await runNpm(["install"], targetPath);
|
|
@@ -1187,9 +1216,10 @@ export async function appWorkflowPull(client) {
|
|
|
1187
1216
|
const written = await writeWorkflowFiles(client, projectDir, meta.app_id, aliases);
|
|
1188
1217
|
console.error(`Wrote ${written.length} workflow ${written.length === 1 ? "body" : "bodies"} to ${WORKFLOWS_DIR}/` +
|
|
1189
1218
|
(written.length > 0 ? ` (${written.join(", ")})` : ""));
|
|
1190
|
-
//
|
|
1191
|
-
//
|
|
1192
|
-
|
|
1219
|
+
// This command writes workflow BODIES, not the `.d.ts` — so it doesn't reach
|
|
1220
|
+
// `writeAppDts`'s heal. Heal here so the bodies land excluded and a stale
|
|
1221
|
+
// `.lotics` include doesn't leave the app's other generated types dead.
|
|
1222
|
+
ensureAppTsconfig(projectDir);
|
|
1193
1223
|
}
|
|
1194
1224
|
/**
|
|
1195
1225
|
* `lotics app workflow check [alias]` — local TypeScript type check of the
|
|
@@ -2,7 +2,7 @@ import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
|
|
|
2
2
|
import fs from "node:fs";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { tmpdir } from "node:os";
|
|
5
|
-
import { stampPulledManifest, undeclaredCapabilities, appDirName, defaultPullTarget,
|
|
5
|
+
import { stampPulledManifest, undeclaredCapabilities, appDirName, defaultPullTarget, ensureAppTsconfig, appCodegen, appUiLink, appVersions, appWorkflowSet, appWorkflowPull, appExecuteWorkflow, writeWorkflowFile, writeWorkflowGlobals, stripWorkflowHeader, FALLBACK_ENVELOPE_PREFIX, FALLBACK_ENVELOPE_SUFFIX, } from "./app_commands.js";
|
|
6
6
|
/**
|
|
7
7
|
* `appPull` reads workflows from the live App row (server response), NOT from
|
|
8
8
|
* the manifest embedded in the extracted source archive. The frozen archive
|
|
@@ -680,7 +680,7 @@ describe("defaultPullTarget", () => {
|
|
|
680
680
|
expect(defaultPullTarget("app_X", "Sales Tracker")).toBe("Sales Tracker");
|
|
681
681
|
});
|
|
682
682
|
});
|
|
683
|
-
describe("
|
|
683
|
+
describe("ensureAppTsconfig", () => {
|
|
684
684
|
let dir;
|
|
685
685
|
beforeEach(() => {
|
|
686
686
|
dir = fs.mkdtempSync(path.join(tmpdir(), "lotics-tsconfig-"));
|
|
@@ -692,37 +692,60 @@ describe("ensureWorkflowTsconfigExcludes", () => {
|
|
|
692
692
|
const read = () => JSON.parse(fs.readFileSync(tsconfigPath(), "utf-8"));
|
|
693
693
|
it("adds both workflow globs to the TOP-LEVEL exclude", () => {
|
|
694
694
|
fs.writeFileSync(tsconfigPath(), JSON.stringify({ compilerOptions: {}, exclude: ["node_modules"] }));
|
|
695
|
-
|
|
695
|
+
ensureAppTsconfig(dir);
|
|
696
696
|
expect(read().exclude).toEqual(["node_modules", "src/workflows", ".lotics/workflows"]);
|
|
697
697
|
});
|
|
698
698
|
it("writes TOP-LEVEL even when a compilerOptions.exclude exists (tsc ignores the nested key)", () => {
|
|
699
699
|
fs.writeFileSync(tsconfigPath(), JSON.stringify({ compilerOptions: { exclude: ["x"] } }));
|
|
700
|
-
|
|
700
|
+
ensureAppTsconfig(dir);
|
|
701
701
|
const cfg = read();
|
|
702
702
|
expect(cfg.exclude).toEqual(["src/workflows", ".lotics/workflows"]);
|
|
703
703
|
expect(cfg.compilerOptions.exclude).toEqual(["x"]); // left untouched (and tsc-ignored)
|
|
704
704
|
});
|
|
705
705
|
it("preserves pre-existing top-level excludes", () => {
|
|
706
706
|
fs.writeFileSync(tsconfigPath(), JSON.stringify({ exclude: ["node_modules", "dist"] }));
|
|
707
|
-
|
|
707
|
+
ensureAppTsconfig(dir);
|
|
708
708
|
expect(read().exclude).toEqual(["node_modules", "dist", "src/workflows", ".lotics/workflows"]);
|
|
709
709
|
});
|
|
710
710
|
it("is idempotent — a second call writes nothing new", () => {
|
|
711
711
|
fs.writeFileSync(tsconfigPath(), JSON.stringify({ exclude: ["node_modules"] }));
|
|
712
|
-
|
|
712
|
+
ensureAppTsconfig(dir);
|
|
713
713
|
const afterFirst = fs.readFileSync(tsconfigPath(), "utf-8");
|
|
714
|
-
|
|
714
|
+
ensureAppTsconfig(dir);
|
|
715
715
|
expect(fs.readFileSync(tsconfigPath(), "utf-8")).toBe(afterFirst);
|
|
716
716
|
});
|
|
717
717
|
it("warns + does not throw or create a file when there is no tsconfig", () => {
|
|
718
|
-
expect(() =>
|
|
718
|
+
expect(() => ensureAppTsconfig(dir)).not.toThrow();
|
|
719
719
|
expect(fs.existsSync(tsconfigPath())).toBe(false);
|
|
720
720
|
});
|
|
721
721
|
it("warns + does not throw on an unparseable tsconfig (left as-is)", () => {
|
|
722
722
|
fs.writeFileSync(tsconfigPath(), "{ not json,, }");
|
|
723
|
-
expect(() =>
|
|
723
|
+
expect(() => ensureAppTsconfig(dir)).not.toThrow();
|
|
724
724
|
expect(fs.readFileSync(tsconfigPath(), "utf-8")).toBe("{ not json,, }");
|
|
725
725
|
});
|
|
726
|
+
it("rewrites a bare .lotics include to the glob (a dot-dir loads zero generated types)", () => {
|
|
727
|
+
fs.writeFileSync(tsconfigPath(), JSON.stringify({ include: ["src", ".lotics"], exclude: ["node_modules"] }));
|
|
728
|
+
ensureAppTsconfig(dir);
|
|
729
|
+
expect(read().include).toEqual(["src", ".lotics/**/*"]);
|
|
730
|
+
});
|
|
731
|
+
it("leaves an already-correct .lotics/**/* include untouched (idempotent)", () => {
|
|
732
|
+
fs.writeFileSync(tsconfigPath(), JSON.stringify({ include: ["src", ".lotics/**/*"], exclude: ["node_modules", "src/workflows", ".lotics/workflows"] }));
|
|
733
|
+
const before = fs.readFileSync(tsconfigPath(), "utf-8");
|
|
734
|
+
ensureAppTsconfig(dir);
|
|
735
|
+
expect(fs.readFileSync(tsconfigPath(), "utf-8")).toBe(before);
|
|
736
|
+
});
|
|
737
|
+
it("dedupes when both a bare .lotics and the glob are present", () => {
|
|
738
|
+
fs.writeFileSync(tsconfigPath(), JSON.stringify({ include: [".lotics", ".lotics/**/*", "src"] }));
|
|
739
|
+
ensureAppTsconfig(dir);
|
|
740
|
+
expect(read().include).toEqual([".lotics/**/*", "src"]);
|
|
741
|
+
});
|
|
742
|
+
it("heals the include AND adds the excludes in a single write", () => {
|
|
743
|
+
fs.writeFileSync(tsconfigPath(), JSON.stringify({ include: ["src", ".lotics"], exclude: ["node_modules"] }));
|
|
744
|
+
ensureAppTsconfig(dir);
|
|
745
|
+
const cfg = read();
|
|
746
|
+
expect(cfg.include).toEqual(["src", ".lotics/**/*"]);
|
|
747
|
+
expect(cfg.exclude).toEqual(["node_modules", "src/workflows", ".lotics/workflows"]);
|
|
748
|
+
});
|
|
726
749
|
});
|
|
727
750
|
describe("appVersions", () => {
|
|
728
751
|
let logLines;
|
|
@@ -122,7 +122,7 @@ function inputDeclToTsType(decl) {
|
|
|
122
122
|
case "date_range":
|
|
123
123
|
return "{ start: string; end: string }";
|
|
124
124
|
case "file":
|
|
125
|
-
return "string";
|
|
125
|
+
return decl.multi === true ? "ReadonlyArray<string>" : "string";
|
|
126
126
|
case "object": {
|
|
127
127
|
const fields = decl.fields !== null && typeof decl.fields === "object"
|
|
128
128
|
? decl.fields
|
|
@@ -70,4 +70,14 @@ describe("generateAppWorkflowsDts", () => {
|
|
|
70
70
|
});
|
|
71
71
|
expect(dts).toContain('owner: string; tags: ReadonlyArray<"a" | "b">');
|
|
72
72
|
});
|
|
73
|
+
it("types a multi file input as ReadonlyArray<string>, single file as string", () => {
|
|
74
|
+
const dts = generateAppWorkflowsDts({
|
|
75
|
+
attach: {
|
|
76
|
+
workflow_id: "wfl_f",
|
|
77
|
+
inputs: { one: { type: "file" }, many: { type: "file", multi: true } },
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
expect(dts).toContain("one: string");
|
|
81
|
+
expect(dts).toContain("many: ReadonlyArray<string>");
|
|
82
|
+
});
|
|
73
83
|
});
|
package/dist/src/cli.js
CHANGED
|
@@ -3387,7 +3387,7 @@ var require_jstat = __commonJS({
|
|
|
3387
3387
|
}
|
|
3388
3388
|
})(exports2, function() {
|
|
3389
3389
|
var jStat = (function(Math2, undefined2) {
|
|
3390
|
-
var
|
|
3390
|
+
var concat2 = Array.prototype.concat;
|
|
3391
3391
|
var slice = Array.prototype.slice;
|
|
3392
3392
|
var toString = Object.prototype.toString;
|
|
3393
3393
|
function calcRdx(n, m) {
|
|
@@ -3407,7 +3407,7 @@ var require_jstat = __commonJS({
|
|
|
3407
3407
|
return typeof num === "number" ? num - num === 0 : false;
|
|
3408
3408
|
}
|
|
3409
3409
|
function toVector(arr) {
|
|
3410
|
-
return
|
|
3410
|
+
return concat2.apply([], arr);
|
|
3411
3411
|
}
|
|
3412
3412
|
function jStat2() {
|
|
3413
3413
|
return new jStat2._init(arguments);
|
|
@@ -20136,7 +20136,7 @@ var require_BufferList = __commonJS({
|
|
|
20136
20136
|
}
|
|
20137
20137
|
return ret;
|
|
20138
20138
|
};
|
|
20139
|
-
BufferList.prototype.concat = function
|
|
20139
|
+
BufferList.prototype.concat = function concat2(n) {
|
|
20140
20140
|
if (this.length === 0) return Buffer2.alloc(0);
|
|
20141
20141
|
var ret = Buffer2.allocUnsafe(n >>> 0);
|
|
20142
20142
|
var p = this.head;
|
|
@@ -23322,7 +23322,7 @@ var require_StreamHelper = __commonJS({
|
|
|
23322
23322
|
return utils.transformTo(type, content);
|
|
23323
23323
|
}
|
|
23324
23324
|
}
|
|
23325
|
-
function
|
|
23325
|
+
function concat2(type, dataArray) {
|
|
23326
23326
|
var i2, index = 0, res = null, totalLength = 0;
|
|
23327
23327
|
for (i2 = 0; i2 < dataArray.length; i2++) {
|
|
23328
23328
|
totalLength += dataArray[i2].length;
|
|
@@ -23359,7 +23359,7 @@ var require_StreamHelper = __commonJS({
|
|
|
23359
23359
|
reject2(err2);
|
|
23360
23360
|
}).on("end", function() {
|
|
23361
23361
|
try {
|
|
23362
|
-
var result = transformZipOutput(resultType,
|
|
23362
|
+
var result = transformZipOutput(resultType, concat2(chunkType, dataArray), mimeType);
|
|
23363
23363
|
resolve(result);
|
|
23364
23364
|
} catch (e) {
|
|
23365
23365
|
reject2(e);
|
|
@@ -31803,7 +31803,7 @@ function inputDeclToTsType(decl) {
|
|
|
31803
31803
|
case "date_range":
|
|
31804
31804
|
return "{ start: string; end: string }";
|
|
31805
31805
|
case "file":
|
|
31806
|
-
return "string";
|
|
31806
|
+
return decl.multi === true ? "ReadonlyArray<string>" : "string";
|
|
31807
31807
|
case "object": {
|
|
31808
31808
|
const fields = decl.fields !== null && typeof decl.fields === "object" ? decl.fields : {};
|
|
31809
31809
|
return inputsToType(fields);
|
|
@@ -32219,6 +32219,8 @@ async function fetchLatestNpmVersion(packageName) {
|
|
|
32219
32219
|
var WORKFLOWS_DIR = path5.join("src", "workflows");
|
|
32220
32220
|
var WORKFLOW_GLOBALS_DIR = path5.join(".lotics", "workflows");
|
|
32221
32221
|
var WORKFLOW_TSCONFIG_EXCLUDES = ["src/workflows", ".lotics/workflows"];
|
|
32222
|
+
var LOTICS_INCLUDE_GLOB = ".lotics/**/*";
|
|
32223
|
+
var STALE_LOTICS_INCLUDES = /* @__PURE__ */ new Set([".lotics", "./.lotics", ".lotics/"]);
|
|
32222
32224
|
var FALLBACK_ENVELOPE_PREFIX = "async function __workflow(): Promise<__WorkflowReturn | void> {\n";
|
|
32223
32225
|
var FALLBACK_ENVELOPE_SUFFIX = "\n}";
|
|
32224
32226
|
function workflowFileHeader(alias) {
|
|
@@ -32362,11 +32364,11 @@ function writeAppMeta(projectDir, meta) {
|
|
|
32362
32364
|
pkg2.lotics = meta;
|
|
32363
32365
|
fs4.writeFileSync(pkgPath2, JSON.stringify(pkg2, null, 2) + "\n");
|
|
32364
32366
|
}
|
|
32365
|
-
function
|
|
32367
|
+
function ensureAppTsconfig(projectDir) {
|
|
32366
32368
|
const tsconfigPath = path5.join(projectDir, "tsconfig.json");
|
|
32367
32369
|
if (!fs4.existsSync(tsconfigPath)) {
|
|
32368
32370
|
console.error(
|
|
32369
|
-
`\u26A0 No tsconfig.json at ${projectDir} \u2014 could not ensure
|
|
32371
|
+
`\u26A0 No tsconfig.json at ${projectDir} \u2014 could not ensure "include" has "${LOTICS_INCLUDE_GLOB}" (a bare .lotics loads none of the generated types) or "exclude" has ${WORKFLOW_TSCONFIG_EXCLUDES.join(", ")}.`
|
|
32370
32372
|
);
|
|
32371
32373
|
return;
|
|
32372
32374
|
}
|
|
@@ -32375,20 +32377,29 @@ function ensureWorkflowTsconfigExcludes(projectDir) {
|
|
|
32375
32377
|
parsed = JSON.parse(fs4.readFileSync(tsconfigPath, "utf-8"));
|
|
32376
32378
|
} catch (err2) {
|
|
32377
32379
|
console.error(
|
|
32378
|
-
`\u26A0 Could not parse tsconfig.json (${err2 instanceof Error ? err2.message : String(err2)}) \u2014
|
|
32380
|
+
`\u26A0 Could not parse tsconfig.json (${err2 instanceof Error ? err2.message : String(err2)}) \u2014 ensure "include" has "${LOTICS_INCLUDE_GLOB}" and "exclude" has ${WORKFLOW_TSCONFIG_EXCLUDES.join(", ")} manually.`
|
|
32379
32381
|
);
|
|
32380
32382
|
return;
|
|
32381
32383
|
}
|
|
32382
32384
|
if (!parsed || typeof parsed !== "object") return;
|
|
32383
|
-
const
|
|
32384
|
-
|
|
32385
|
-
|
|
32386
|
-
|
|
32387
|
-
|
|
32385
|
+
const changes = [];
|
|
32386
|
+
if (Array.isArray(parsed.include)) {
|
|
32387
|
+
const inc = parsed.include.filter((e) => typeof e === "string");
|
|
32388
|
+
if (inc.some((e) => STALE_LOTICS_INCLUDES.has(e))) {
|
|
32389
|
+
const healed = inc.map((e) => STALE_LOTICS_INCLUDES.has(e) ? LOTICS_INCLUDE_GLOB : e);
|
|
32390
|
+
parsed.include = healed.filter((e, i2) => healed.indexOf(e) === i2);
|
|
32391
|
+
changes.push(`rewrote a bare ".lotics" to "${LOTICS_INCLUDE_GLOB}" in "include" (a dot-dir loads zero generated types)`);
|
|
32392
|
+
}
|
|
32393
|
+
}
|
|
32394
|
+
const currentEx = Array.isArray(parsed.exclude) ? parsed.exclude.filter((e) => typeof e === "string") : [];
|
|
32395
|
+
const toAdd = WORKFLOW_TSCONFIG_EXCLUDES.filter((g) => !currentEx.includes(g));
|
|
32396
|
+
if (toAdd.length > 0) {
|
|
32397
|
+
parsed.exclude = [...currentEx, ...toAdd];
|
|
32398
|
+
changes.push(`added ${toAdd.join(", ")} to "exclude"`);
|
|
32399
|
+
}
|
|
32400
|
+
if (changes.length === 0) return;
|
|
32388
32401
|
fs4.writeFileSync(tsconfigPath, JSON.stringify(parsed, null, 2) + "\n");
|
|
32389
|
-
console.error(
|
|
32390
|
-
`Patched tsconfig.json: added ${toAdd.join(", ")} to "exclude" so npm run typecheck skips the workflow bodies (check them with: lotics app workflow check).`
|
|
32391
|
-
);
|
|
32402
|
+
console.error(`Patched tsconfig.json: ${changes.join("; ")}.`);
|
|
32392
32403
|
}
|
|
32393
32404
|
function writeAppDts(projectDir, manifest) {
|
|
32394
32405
|
const dotLotics = path5.join(projectDir, ".lotics");
|
|
@@ -32399,6 +32410,7 @@ function writeAppDts(projectDir, manifest) {
|
|
|
32399
32410
|
[path5.join(dotLotics, "app_agents.d.ts"), generateAppAgentsDts(manifest.agents)]
|
|
32400
32411
|
];
|
|
32401
32412
|
for (const [file, content] of written) fs4.writeFileSync(file, content);
|
|
32413
|
+
ensureAppTsconfig(projectDir);
|
|
32402
32414
|
return written.map(([file]) => file);
|
|
32403
32415
|
}
|
|
32404
32416
|
function readCodegenTablesAllowlist(projectDir) {
|
|
@@ -32447,7 +32459,6 @@ async function appCodegen(args) {
|
|
|
32447
32459
|
);
|
|
32448
32460
|
}
|
|
32449
32461
|
await refreshWorkflowGlobals(args.client, projectDir, meta.app_id, Object.keys(meta.workflows ?? {}));
|
|
32450
|
-
if (Object.keys(meta.workflows ?? {}).length > 0) ensureWorkflowTsconfigExcludes(projectDir);
|
|
32451
32462
|
}
|
|
32452
32463
|
async function refreshWorkflowGlobals(client, projectDir, app_id, aliases) {
|
|
32453
32464
|
for (const alias of aliases) {
|
|
@@ -32630,7 +32641,6 @@ async function appPull(client, args) {
|
|
|
32630
32641
|
`Wrote ${written.length} workflow ${written.length === 1 ? "body" : "bodies"} to ${WORKFLOWS_DIR}/ (${written.join(", ")})`
|
|
32631
32642
|
);
|
|
32632
32643
|
}
|
|
32633
|
-
ensureWorkflowTsconfigExcludes(targetPath);
|
|
32634
32644
|
}
|
|
32635
32645
|
console.error(`Installing npm dependencies...`);
|
|
32636
32646
|
await runNpm(["install"], targetPath);
|
|
@@ -32945,7 +32955,7 @@ async function appWorkflowPull(client) {
|
|
|
32945
32955
|
console.error(
|
|
32946
32956
|
`Wrote ${written.length} workflow ${written.length === 1 ? "body" : "bodies"} to ${WORKFLOWS_DIR}/` + (written.length > 0 ? ` (${written.join(", ")})` : "")
|
|
32947
32957
|
);
|
|
32948
|
-
|
|
32958
|
+
ensureAppTsconfig(projectDir);
|
|
32949
32959
|
}
|
|
32950
32960
|
async function appWorkflowCheck(args) {
|
|
32951
32961
|
const projectDir = process.cwd();
|
|
@@ -42644,8 +42654,426 @@ function ensureVmlArray(val) {
|
|
|
42644
42654
|
return Array.isArray(val) ? val : [val];
|
|
42645
42655
|
}
|
|
42646
42656
|
|
|
42657
|
+
// ../xlsx/src/biff8_reader.ts
|
|
42658
|
+
var OLE2_MAGIC2 = [208, 207, 17, 224, 161, 177, 26, 225];
|
|
42659
|
+
var ENDOFCHAIN = 4294967294;
|
|
42660
|
+
var FREESECT = 4294967295;
|
|
42661
|
+
var DEFAULT_MAX_ROWS = 1e4;
|
|
42662
|
+
function isOle2(bytes) {
|
|
42663
|
+
return bytes.length >= 8 && OLE2_MAGIC2.every((b, i2) => bytes[i2] === b);
|
|
42664
|
+
}
|
|
42665
|
+
function readCfbStreams(bytes) {
|
|
42666
|
+
const dv = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
42667
|
+
const u162 = (o) => dv.getUint16(o, true);
|
|
42668
|
+
const u32 = (o) => dv.getUint32(o, true);
|
|
42669
|
+
const sectorSize = 1 << u162(30);
|
|
42670
|
+
const miniSectorSize = 1 << u162(32);
|
|
42671
|
+
const firstDirSector = u32(48);
|
|
42672
|
+
const miniCutoff = u32(56);
|
|
42673
|
+
const firstMiniFatSector = u32(60);
|
|
42674
|
+
const firstDifatSector = u32(68);
|
|
42675
|
+
if (sectorSize < 512 || sectorSize > 1 << 20) {
|
|
42676
|
+
throw new Error("Unsupported .xls: invalid OLE2 sector size");
|
|
42677
|
+
}
|
|
42678
|
+
const sectorOffset = (n) => sectorSize * (n + 1);
|
|
42679
|
+
const difat = [];
|
|
42680
|
+
for (let i2 = 0; i2 < 109; i2++) {
|
|
42681
|
+
const v = u32(76 + i2 * 4);
|
|
42682
|
+
if (v !== FREESECT) difat.push(v);
|
|
42683
|
+
}
|
|
42684
|
+
let ds = firstDifatSector;
|
|
42685
|
+
const entriesPerSector = sectorSize / 4;
|
|
42686
|
+
for (let guard = 0; ds !== ENDOFCHAIN && ds !== FREESECT && guard < 1 << 20; guard++) {
|
|
42687
|
+
const base = sectorOffset(ds);
|
|
42688
|
+
for (let i2 = 0; i2 < entriesPerSector - 1; i2++) {
|
|
42689
|
+
const v = u32(base + i2 * 4);
|
|
42690
|
+
if (v !== FREESECT) difat.push(v);
|
|
42691
|
+
}
|
|
42692
|
+
ds = u32(base + (entriesPerSector - 1) * 4);
|
|
42693
|
+
}
|
|
42694
|
+
const fat = [];
|
|
42695
|
+
for (const fatSector of difat) {
|
|
42696
|
+
const base = sectorOffset(fatSector);
|
|
42697
|
+
for (let i2 = 0; i2 < entriesPerSector; i2++) fat.push(u32(base + i2 * 4));
|
|
42698
|
+
}
|
|
42699
|
+
const readChain = (src, start, size, ss, offOf, chain) => {
|
|
42700
|
+
const maxSectors = Math.floor(src.length / ss) + 2;
|
|
42701
|
+
const parts = [];
|
|
42702
|
+
let s = start;
|
|
42703
|
+
for (let guard = 0; s !== ENDOFCHAIN && s !== FREESECT && s < chain.length && guard < maxSectors; guard++) {
|
|
42704
|
+
const o = offOf(s);
|
|
42705
|
+
parts.push(src.subarray(o, o + ss));
|
|
42706
|
+
s = chain[s];
|
|
42707
|
+
}
|
|
42708
|
+
const merged = concat(parts);
|
|
42709
|
+
return size != null ? merged.subarray(0, size) : merged;
|
|
42710
|
+
};
|
|
42711
|
+
const readBig = (start, size) => readChain(bytes, start, size, sectorSize, sectorOffset, fat);
|
|
42712
|
+
const dirBytes = readBig(firstDirSector, null);
|
|
42713
|
+
const ddv = new DataView(dirBytes.buffer, dirBytes.byteOffset, dirBytes.byteLength);
|
|
42714
|
+
const dir = [];
|
|
42715
|
+
for (let off = 0; off + 128 <= dirBytes.length; off += 128) {
|
|
42716
|
+
const nameLen = ddv.getUint16(off + 64, true);
|
|
42717
|
+
const type = ddv.getUint8(off + 66);
|
|
42718
|
+
if (nameLen < 2 || type === 0) continue;
|
|
42719
|
+
const name = utf16le(dirBytes.subarray(off, off + nameLen - 2));
|
|
42720
|
+
dir.push({ name, type, start: ddv.getUint32(off + 116, true), size: Number(ddv.getBigUint64(off + 120, true)) });
|
|
42721
|
+
}
|
|
42722
|
+
const root = dir.find((e) => e.type === 5);
|
|
42723
|
+
const miniStream = root ? readBig(root.start, root.size) : new Uint8Array(0);
|
|
42724
|
+
const miniFatBytes = readBig(firstMiniFatSector, null);
|
|
42725
|
+
const miniFat = [];
|
|
42726
|
+
for (let i2 = 0; i2 + 4 <= miniFatBytes.length; i2 += 4) miniFat.push(miniFatBytes[i2] | miniFatBytes[i2 + 1] << 8 | miniFatBytes[i2 + 2] << 16 | miniFatBytes[i2 + 3] << 24);
|
|
42727
|
+
const readMini = (start, size) => readChain(miniStream, start, size, miniSectorSize, (n) => n * miniSectorSize, miniFat);
|
|
42728
|
+
const readStream = (e) => e.size >= miniCutoff ? readBig(e.start, e.size) : readMini(e.start, e.size);
|
|
42729
|
+
return dir.filter((e) => e.type === 2).map((e) => ({ name: e.name, bytes: readStream(e) }));
|
|
42730
|
+
}
|
|
42731
|
+
var REC = {
|
|
42732
|
+
FORMULA: 6,
|
|
42733
|
+
EOF: 10,
|
|
42734
|
+
CONTINUE: 60,
|
|
42735
|
+
DATEMODE: 34,
|
|
42736
|
+
FILEPASS: 47,
|
|
42737
|
+
BLANK: 513,
|
|
42738
|
+
NUMBER: 515,
|
|
42739
|
+
LABEL: 516,
|
|
42740
|
+
STRING: 519,
|
|
42741
|
+
BOOLERR: 517,
|
|
42742
|
+
BOUNDSHEET: 133,
|
|
42743
|
+
FORMAT: 1054,
|
|
42744
|
+
XF: 224,
|
|
42745
|
+
RK: 638,
|
|
42746
|
+
MULRK: 189,
|
|
42747
|
+
MULBLANK: 190,
|
|
42748
|
+
LABELSST: 253,
|
|
42749
|
+
SST: 252,
|
|
42750
|
+
BOF: 2057
|
|
42751
|
+
};
|
|
42752
|
+
function* iterRecords(stream, from, to) {
|
|
42753
|
+
const dv = new DataView(stream.buffer, stream.byteOffset, stream.byteLength);
|
|
42754
|
+
let p = from;
|
|
42755
|
+
while (p + 4 <= to) {
|
|
42756
|
+
const type = dv.getUint16(p, true);
|
|
42757
|
+
const len = dv.getUint16(p + 2, true);
|
|
42758
|
+
const bodyStart = p + 4;
|
|
42759
|
+
if (bodyStart + len > stream.length) break;
|
|
42760
|
+
yield { type, body: stream.subarray(bodyStart, bodyStart + len), offset: p };
|
|
42761
|
+
p = bodyStart + len;
|
|
42762
|
+
}
|
|
42763
|
+
}
|
|
42764
|
+
function parseGlobals(stream) {
|
|
42765
|
+
const sstChunks = [];
|
|
42766
|
+
const formats = /* @__PURE__ */ new Map();
|
|
42767
|
+
const xfFormatIds = [];
|
|
42768
|
+
const boundsheets = [];
|
|
42769
|
+
let date1904 = false;
|
|
42770
|
+
let sawSst = false;
|
|
42771
|
+
let sstUnique = 0;
|
|
42772
|
+
let end = stream.length;
|
|
42773
|
+
let started = false;
|
|
42774
|
+
const dv = new DataView(stream.buffer, stream.byteOffset, stream.byteLength);
|
|
42775
|
+
for (const r of iterRecords(stream, 0, stream.length)) {
|
|
42776
|
+
if (r.type === REC.BOF) {
|
|
42777
|
+
if (started) {
|
|
42778
|
+
end = r.offset;
|
|
42779
|
+
break;
|
|
42780
|
+
}
|
|
42781
|
+
started = true;
|
|
42782
|
+
continue;
|
|
42783
|
+
}
|
|
42784
|
+
if (r.type === REC.EOF) {
|
|
42785
|
+
end = r.offset;
|
|
42786
|
+
break;
|
|
42787
|
+
}
|
|
42788
|
+
}
|
|
42789
|
+
for (const r of iterRecords(stream, 0, end)) {
|
|
42790
|
+
switch (r.type) {
|
|
42791
|
+
case REC.FILEPASS:
|
|
42792
|
+
throw new PasswordProtectedError();
|
|
42793
|
+
case REC.DATEMODE:
|
|
42794
|
+
date1904 = readU16(r.body, 0) === 1;
|
|
42795
|
+
break;
|
|
42796
|
+
case REC.SST:
|
|
42797
|
+
sawSst = true;
|
|
42798
|
+
sstUnique = readU32(r.body, 4);
|
|
42799
|
+
sstChunks.push(r.body.subarray(8));
|
|
42800
|
+
break;
|
|
42801
|
+
case REC.CONTINUE:
|
|
42802
|
+
if (sawSst) sstChunks.push(r.body);
|
|
42803
|
+
break;
|
|
42804
|
+
case REC.FORMAT: {
|
|
42805
|
+
const id = readU16(r.body, 0);
|
|
42806
|
+
formats.set(id, readUnicodeShort(r.body, 2, 2));
|
|
42807
|
+
break;
|
|
42808
|
+
}
|
|
42809
|
+
case REC.XF: {
|
|
42810
|
+
xfFormatIds.push(readU16(r.body, 2));
|
|
42811
|
+
break;
|
|
42812
|
+
}
|
|
42813
|
+
case REC.BOUNDSHEET: {
|
|
42814
|
+
const pos = dv.getUint32(r.offset + 4, true);
|
|
42815
|
+
boundsheets.push({ name: readUnicodeShort(r.body, 6, 1), pos });
|
|
42816
|
+
break;
|
|
42817
|
+
}
|
|
42818
|
+
default:
|
|
42819
|
+
break;
|
|
42820
|
+
}
|
|
42821
|
+
}
|
|
42822
|
+
const sst = parseSst(sstChunks, sstUnique);
|
|
42823
|
+
const xfFormats = xfFormatIds.map((id) => formats.get(id) ?? builtinFormat(id));
|
|
42824
|
+
return { sst, date1904, xfFormats, boundsheets };
|
|
42825
|
+
}
|
|
42826
|
+
function parseSst(chunks, count) {
|
|
42827
|
+
const out = [];
|
|
42828
|
+
if (chunks.length === 0) return out;
|
|
42829
|
+
let ci = 0;
|
|
42830
|
+
let off = 0;
|
|
42831
|
+
const atEnd = () => ci >= chunks.length;
|
|
42832
|
+
const cur = () => chunks[ci];
|
|
42833
|
+
const advanceChunk = () => {
|
|
42834
|
+
ci++;
|
|
42835
|
+
off = 0;
|
|
42836
|
+
};
|
|
42837
|
+
const rawU8 = () => {
|
|
42838
|
+
while (!atEnd() && off >= cur().length) advanceChunk();
|
|
42839
|
+
if (atEnd()) return 0;
|
|
42840
|
+
return cur()[off++];
|
|
42841
|
+
};
|
|
42842
|
+
const rawU16 = () => rawU8() | rawU8() << 8;
|
|
42843
|
+
const rawU32 = () => rawU8() | rawU8() << 8 | rawU8() << 16 | rawU8() << 24;
|
|
42844
|
+
const skip = (n) => {
|
|
42845
|
+
for (let i2 = 0; i2 < n; i2++) rawU8();
|
|
42846
|
+
};
|
|
42847
|
+
for (let s = 0; s < count && !atEnd(); s++) {
|
|
42848
|
+
const cch = rawU16();
|
|
42849
|
+
const grbit = rawU8();
|
|
42850
|
+
let high = (grbit & 1) !== 0;
|
|
42851
|
+
const rich = (grbit & 8) !== 0 ? rawU16() : 0;
|
|
42852
|
+
const ext = (grbit & 4) !== 0 ? rawU32() : 0;
|
|
42853
|
+
let str = "";
|
|
42854
|
+
let read = 0;
|
|
42855
|
+
while (read < cch) {
|
|
42856
|
+
if (off >= cur().length) {
|
|
42857
|
+
advanceChunk();
|
|
42858
|
+
if (atEnd()) break;
|
|
42859
|
+
high = (cur()[off++] & 1) !== 0;
|
|
42860
|
+
}
|
|
42861
|
+
if (high) {
|
|
42862
|
+
const code = cur()[off] | cur()[off + 1] << 8;
|
|
42863
|
+
off += 2;
|
|
42864
|
+
str += String.fromCharCode(code);
|
|
42865
|
+
} else {
|
|
42866
|
+
str += String.fromCharCode(cur()[off++]);
|
|
42867
|
+
}
|
|
42868
|
+
read++;
|
|
42869
|
+
}
|
|
42870
|
+
skip(rich * 4 + ext);
|
|
42871
|
+
out.push(str);
|
|
42872
|
+
}
|
|
42873
|
+
return out;
|
|
42874
|
+
}
|
|
42875
|
+
function parseSheet2(stream, start, name, g, maxRows) {
|
|
42876
|
+
const sheet = emptySheet(name);
|
|
42877
|
+
const grid = /* @__PURE__ */ new Map();
|
|
42878
|
+
let maxRow = -1;
|
|
42879
|
+
let truncated = false;
|
|
42880
|
+
const put = (row, col, cell) => {
|
|
42881
|
+
if (row >= maxRows) {
|
|
42882
|
+
truncated = true;
|
|
42883
|
+
return;
|
|
42884
|
+
}
|
|
42885
|
+
let r = grid.get(row);
|
|
42886
|
+
if (!r) {
|
|
42887
|
+
r = /* @__PURE__ */ new Map();
|
|
42888
|
+
grid.set(row, r);
|
|
42889
|
+
}
|
|
42890
|
+
r.set(col, cell);
|
|
42891
|
+
if (row > maxRow) maxRow = row;
|
|
42892
|
+
};
|
|
42893
|
+
let end = stream.length;
|
|
42894
|
+
let seenBof = false;
|
|
42895
|
+
for (const r of iterRecords(stream, start, stream.length)) {
|
|
42896
|
+
if (r.type === REC.BOF) {
|
|
42897
|
+
if (seenBof) {
|
|
42898
|
+
end = r.offset;
|
|
42899
|
+
break;
|
|
42900
|
+
}
|
|
42901
|
+
seenBof = true;
|
|
42902
|
+
continue;
|
|
42903
|
+
}
|
|
42904
|
+
if (r.type === REC.EOF) {
|
|
42905
|
+
end = r.offset;
|
|
42906
|
+
break;
|
|
42907
|
+
}
|
|
42908
|
+
}
|
|
42909
|
+
for (const r of iterRecords(stream, start, end)) {
|
|
42910
|
+
switch (r.type) {
|
|
42911
|
+
case REC.LABELSST: {
|
|
42912
|
+
const row = readU16(r.body, 0), col = readU16(r.body, 2), isst = readU32(r.body, 6);
|
|
42913
|
+
put(row, col, textCell(col, g.sst[isst] ?? ""));
|
|
42914
|
+
break;
|
|
42915
|
+
}
|
|
42916
|
+
case REC.LABEL: {
|
|
42917
|
+
const row = readU16(r.body, 0), col = readU16(r.body, 2);
|
|
42918
|
+
put(row, col, textCell(col, readUnicodeShort(r.body, 6, 2)));
|
|
42919
|
+
break;
|
|
42920
|
+
}
|
|
42921
|
+
case REC.NUMBER: {
|
|
42922
|
+
const row = readU16(r.body, 0), col = readU16(r.body, 2), xf = readU16(r.body, 4);
|
|
42923
|
+
put(row, col, numberCell(col, readF64(r.body, 6), g.xfFormats[xf]));
|
|
42924
|
+
break;
|
|
42925
|
+
}
|
|
42926
|
+
case REC.RK: {
|
|
42927
|
+
const row = readU16(r.body, 0), col = readU16(r.body, 2), xf = readU16(r.body, 4);
|
|
42928
|
+
put(row, col, numberCell(col, decodeRk(readU32(r.body, 6)), g.xfFormats[xf]));
|
|
42929
|
+
break;
|
|
42930
|
+
}
|
|
42931
|
+
case REC.MULRK: {
|
|
42932
|
+
const row = readU16(r.body, 0), first2 = readU16(r.body, 2);
|
|
42933
|
+
const n = (r.body.length - 6) / 6;
|
|
42934
|
+
for (let i2 = 0; i2 < n; i2++) {
|
|
42935
|
+
const xf = readU16(r.body, 4 + i2 * 6);
|
|
42936
|
+
const rk = readU32(r.body, 6 + i2 * 6);
|
|
42937
|
+
put(row, first2 + i2, numberCell(first2 + i2, decodeRk(rk), g.xfFormats[xf]));
|
|
42938
|
+
}
|
|
42939
|
+
break;
|
|
42940
|
+
}
|
|
42941
|
+
case REC.FORMULA: {
|
|
42942
|
+
const row = readU16(r.body, 0), col = readU16(r.body, 2), xf = readU16(r.body, 4);
|
|
42943
|
+
const cell = formulaCell(col, r.body, g.xfFormats[xf]);
|
|
42944
|
+
if (cell) put(row, col, cell);
|
|
42945
|
+
break;
|
|
42946
|
+
}
|
|
42947
|
+
// BLANK / MULBLANK / BOOLERR carry no data value we surface — skipped.
|
|
42948
|
+
default:
|
|
42949
|
+
break;
|
|
42950
|
+
}
|
|
42951
|
+
}
|
|
42952
|
+
const rows = [];
|
|
42953
|
+
for (let ri = 0; ri <= maxRow; ri++) {
|
|
42954
|
+
const r = grid.get(ri);
|
|
42955
|
+
if (!r) continue;
|
|
42956
|
+
const cells = [...r.values()].sort((a, b) => a.column - b.column);
|
|
42957
|
+
rows.push({ index: ri, height: sheet.defaultRowHeight, cells, hidden: false });
|
|
42958
|
+
}
|
|
42959
|
+
sheet.rows = rows;
|
|
42960
|
+
sheet.totalRowCount = maxRow + 1;
|
|
42961
|
+
sheet.truncated = truncated;
|
|
42962
|
+
return sheet;
|
|
42963
|
+
}
|
|
42964
|
+
function textCell(column, text) {
|
|
42965
|
+
return { column, value: text, typedValue: text, content: { type: "plain", text }, style: {} };
|
|
42966
|
+
}
|
|
42967
|
+
function numberCell(column, num, numFmt) {
|
|
42968
|
+
const value = Number.isFinite(num) ? String(num) : "";
|
|
42969
|
+
return {
|
|
42970
|
+
column,
|
|
42971
|
+
value,
|
|
42972
|
+
rawValue: num,
|
|
42973
|
+
typedValue: num,
|
|
42974
|
+
numFmtCode: numFmt && numFmt !== "General" ? numFmt : void 0,
|
|
42975
|
+
content: { type: "plain", text: value },
|
|
42976
|
+
style: {}
|
|
42977
|
+
};
|
|
42978
|
+
}
|
|
42979
|
+
function formulaCell(column, body, numFmt) {
|
|
42980
|
+
if (readU16(body, 12) === 65535) {
|
|
42981
|
+
const kind = body[6];
|
|
42982
|
+
if (kind === 1) {
|
|
42983
|
+
const b = body[8] !== 0;
|
|
42984
|
+
return { column, value: b ? "TRUE" : "FALSE", typedValue: b, content: { type: "plain", text: b ? "TRUE" : "FALSE" }, style: {} };
|
|
42985
|
+
}
|
|
42986
|
+
return null;
|
|
42987
|
+
}
|
|
42988
|
+
return numberCell(column, readF64(body, 6), numFmt);
|
|
42989
|
+
}
|
|
42990
|
+
function decodeRk(rk) {
|
|
42991
|
+
const div100 = (rk & 1) !== 0;
|
|
42992
|
+
const isInt = (rk & 2) !== 0;
|
|
42993
|
+
let n;
|
|
42994
|
+
if (isInt) {
|
|
42995
|
+
n = rk >> 2;
|
|
42996
|
+
} else {
|
|
42997
|
+
const buf = new ArrayBuffer(8);
|
|
42998
|
+
new DataView(buf).setUint32(4, rk & 4294967292, true);
|
|
42999
|
+
n = new DataView(buf).getFloat64(0, true);
|
|
43000
|
+
}
|
|
43001
|
+
return div100 ? n / 100 : n;
|
|
43002
|
+
}
|
|
43003
|
+
function readU16(b, o) {
|
|
43004
|
+
return b[o] | b[o + 1] << 8;
|
|
43005
|
+
}
|
|
43006
|
+
function readU32(b, o) {
|
|
43007
|
+
return (b[o] | b[o + 1] << 8 | b[o + 2] << 16 | b[o + 3] << 24) >>> 0;
|
|
43008
|
+
}
|
|
43009
|
+
function readF64(b, o) {
|
|
43010
|
+
return new DataView(b.buffer, b.byteOffset + o, 8).getFloat64(0, true);
|
|
43011
|
+
}
|
|
43012
|
+
function readUnicodeShort(b, offset, lenBytes) {
|
|
43013
|
+
const cch = lenBytes === 1 ? b[offset] : readU16(b, offset);
|
|
43014
|
+
const grbit = b[offset + lenBytes];
|
|
43015
|
+
const high = (grbit & 1) !== 0;
|
|
43016
|
+
let p = offset + lenBytes + 1;
|
|
43017
|
+
let s = "";
|
|
43018
|
+
for (let i2 = 0; i2 < cch; i2++) {
|
|
43019
|
+
if (high) {
|
|
43020
|
+
s += String.fromCharCode(b[p] | b[p + 1] << 8);
|
|
43021
|
+
p += 2;
|
|
43022
|
+
} else {
|
|
43023
|
+
s += String.fromCharCode(b[p]);
|
|
43024
|
+
p += 1;
|
|
43025
|
+
}
|
|
43026
|
+
}
|
|
43027
|
+
return s;
|
|
43028
|
+
}
|
|
43029
|
+
function utf16le(b) {
|
|
43030
|
+
let s = "";
|
|
43031
|
+
for (let i2 = 0; i2 + 1 < b.length; i2 += 2) s += String.fromCharCode(b[i2] | b[i2 + 1] << 8);
|
|
43032
|
+
return s;
|
|
43033
|
+
}
|
|
43034
|
+
function concat(parts) {
|
|
43035
|
+
let total = 0;
|
|
43036
|
+
for (const p of parts) total += p.length;
|
|
43037
|
+
const out = new Uint8Array(total);
|
|
43038
|
+
let o = 0;
|
|
43039
|
+
for (const p of parts) {
|
|
43040
|
+
out.set(p, o);
|
|
43041
|
+
o += p.length;
|
|
43042
|
+
}
|
|
43043
|
+
return out;
|
|
43044
|
+
}
|
|
43045
|
+
function builtinFormat(id) {
|
|
43046
|
+
const DATES = {
|
|
43047
|
+
14: "m/d/yyyy",
|
|
43048
|
+
15: "d-mmm-yy",
|
|
43049
|
+
16: "d-mmm",
|
|
43050
|
+
17: "mmm-yy",
|
|
43051
|
+
18: "h:mm AM/PM",
|
|
43052
|
+
19: "h:mm:ss AM/PM",
|
|
43053
|
+
20: "h:mm",
|
|
43054
|
+
21: "h:mm:ss",
|
|
43055
|
+
22: "m/d/yyyy h:mm",
|
|
43056
|
+
45: "mm:ss",
|
|
43057
|
+
46: "[h]:mm:ss",
|
|
43058
|
+
47: "mm:ss.0"
|
|
43059
|
+
};
|
|
43060
|
+
return DATES[id] ?? "General";
|
|
43061
|
+
}
|
|
43062
|
+
function parseBiff8(bytes, options) {
|
|
43063
|
+
const streams = readCfbStreams(bytes);
|
|
43064
|
+
if (streams.some((s) => /^EncryptedPackage$/i.test(s.name))) throw new PasswordProtectedError();
|
|
43065
|
+
const wb = streams.find((s) => /^workbook$/i.test(s.name)) ?? streams.find((s) => /^book$/i.test(s.name));
|
|
43066
|
+
if (!wb) throw new Error("Not a valid .xls: no Workbook stream in the OLE2 container");
|
|
43067
|
+
const g = parseGlobals(wb.bytes);
|
|
43068
|
+
const maxRows = options?.maxRowsPerSheet ?? DEFAULT_MAX_ROWS;
|
|
43069
|
+
const sheets = g.boundsheets.length > 0 ? g.boundsheets.map((bs) => parseSheet2(wb.bytes, bs.pos, bs.name, g, maxRows)) : [emptySheet("Sheet1")];
|
|
43070
|
+
return { sheets, activeSheetIndex: 0 };
|
|
43071
|
+
}
|
|
43072
|
+
|
|
42647
43073
|
// ../xlsx/src/excel_parser.ts
|
|
42648
43074
|
function parseExcelBuffer(arrayBuffer, options) {
|
|
43075
|
+
const bytes = new Uint8Array(arrayBuffer);
|
|
43076
|
+
if (isOle2(bytes)) return parseBiff8(bytes, options);
|
|
42649
43077
|
const zip = unzipXlsx(arrayBuffer);
|
|
42650
43078
|
return parseExcelFromZip(zip, options);
|
|
42651
43079
|
}
|