@lotics/cli 0.56.0 → 0.60.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +36 -0
- package/dist/app_commands.d.ts +125 -3
- package/dist/app_commands.js +613 -6
- package/dist/app_commands.test.js +501 -2
- package/dist/args.d.ts +4 -0
- package/dist/args.js +9 -0
- package/dist/args.test.js +12 -0
- package/dist/child_env.d.ts +13 -0
- package/dist/child_env.js +24 -0
- package/dist/cli.js +132 -30
- package/dist/client.d.ts +66 -0
- package/dist/client.js +144 -1
- package/dist/client.test.d.ts +1 -0
- package/dist/client.test.js +47 -0
- package/dist/dev/server.js +2 -1
- package/dist/generate_app_fields.d.ts +54 -0
- package/dist/generate_app_fields.js +148 -0
- package/dist/generate_app_fields.test.d.ts +1 -0
- package/dist/generate_app_fields.test.js +108 -0
- package/dist/inputs.d.ts +38 -0
- package/dist/inputs.js +50 -0
- package/dist/inputs.test.d.ts +1 -0
- package/dist/inputs.test.js +89 -0
- package/dist/src/cli.js +2483 -1414
- package/dist/starter_template.js +89 -0
- package/dist/starter_template.test.js +11 -0
- package/package.json +2 -1
package/dist/src/cli.js
CHANGED
|
@@ -29579,6 +29579,8 @@ var require_lib3 = __commonJS({
|
|
|
29579
29579
|
});
|
|
29580
29580
|
|
|
29581
29581
|
// src/cli.ts
|
|
29582
|
+
import dns from "node:dns";
|
|
29583
|
+
import net2 from "node:net";
|
|
29582
29584
|
import fs7 from "node:fs";
|
|
29583
29585
|
import path6 from "node:path";
|
|
29584
29586
|
import readline from "node:readline";
|
|
@@ -29586,6 +29588,19 @@ import readline from "node:readline";
|
|
|
29586
29588
|
// src/client.ts
|
|
29587
29589
|
import fs from "node:fs";
|
|
29588
29590
|
import path from "node:path";
|
|
29591
|
+
function gatewayErrorMessage(status) {
|
|
29592
|
+
if (status === 524) {
|
|
29593
|
+
return "The request took too long to finish (gateway timeout). It may still be running \u2014 check back in a moment, or try again.";
|
|
29594
|
+
}
|
|
29595
|
+
if (status >= 500) {
|
|
29596
|
+
return "The service is temporarily unavailable. Please try again shortly.";
|
|
29597
|
+
}
|
|
29598
|
+
return "The service returned an unexpected response. Please try again.";
|
|
29599
|
+
}
|
|
29600
|
+
function transportErrorMessage(status, parsed) {
|
|
29601
|
+
const jsonMessage = parsed && typeof parsed.message === "string" ? parsed.message : null;
|
|
29602
|
+
return parsed === null || status >= 500 || jsonMessage === null ? gatewayErrorMessage(status) : jsonMessage;
|
|
29603
|
+
}
|
|
29589
29604
|
function findAvailableFilename(dir, filename, reserved) {
|
|
29590
29605
|
const isTaken = (name) => {
|
|
29591
29606
|
const full = path.join(dir, name);
|
|
@@ -29731,6 +29746,38 @@ var LoticsClient = class {
|
|
|
29731
29746
|
async createApp(body) {
|
|
29732
29747
|
return this.request("POST", "/v1/apps", body);
|
|
29733
29748
|
}
|
|
29749
|
+
/**
|
|
29750
|
+
* Resolve the display name + fields (incl. select options) of the given tables
|
|
29751
|
+
* — the schema `lotics app codegen` turns into the runtime `.lotics/app_fields.ts`
|
|
29752
|
+
* alias maps. One `get_table` call per id (the tool surface has no batch
|
|
29753
|
+
* variant); a missing/inaccessible table is dropped rather than throwing, so a
|
|
29754
|
+
* stale id in the scope set never fails codegen.
|
|
29755
|
+
*/
|
|
29756
|
+
async getWorkspaceSchema(tableIds) {
|
|
29757
|
+
const tables = await Promise.all(
|
|
29758
|
+
tableIds.map(async (table_id) => {
|
|
29759
|
+
const res = await this.execute("get_table", { table_id });
|
|
29760
|
+
if (res.error || res.result === null || typeof res.result !== "object") return null;
|
|
29761
|
+
const table = res.result;
|
|
29762
|
+
if (typeof table.id !== "string" || typeof table.name !== "string" || !Array.isArray(table.fields)) {
|
|
29763
|
+
return null;
|
|
29764
|
+
}
|
|
29765
|
+
const fields = table.fields.flatMap((field) => {
|
|
29766
|
+
if (field === null || typeof field !== "object") return [];
|
|
29767
|
+
const f = field;
|
|
29768
|
+
if (typeof f.key !== "string" || typeof f.name !== "string") return [];
|
|
29769
|
+
const options = Array.isArray(f.options) ? f.options.flatMap((opt) => {
|
|
29770
|
+
if (opt === null || typeof opt !== "object") return [];
|
|
29771
|
+
const o = opt;
|
|
29772
|
+
return typeof o.key === "string" && typeof o.name === "string" ? [{ id: o.key, label: o.name }] : [];
|
|
29773
|
+
}) : void 0;
|
|
29774
|
+
return [{ id: f.key, name: f.name, ...options && options.length > 0 ? { options } : {} }];
|
|
29775
|
+
});
|
|
29776
|
+
return { id: table.id, name: table.name, fields };
|
|
29777
|
+
})
|
|
29778
|
+
);
|
|
29779
|
+
return tables.filter((t) => t !== null);
|
|
29780
|
+
}
|
|
29734
29781
|
/**
|
|
29735
29782
|
* Rename an app's public subdomain — its `<slug>.lotics.app` address.
|
|
29736
29783
|
* Mirrors PUT /v1/apps/{app_id}/subdomain. The old subdomain stops
|
|
@@ -29785,10 +29832,70 @@ var LoticsClient = class {
|
|
|
29785
29832
|
* Mirrors POST /v1/apps/{app_id}/workflows/{alias}/execute.
|
|
29786
29833
|
*/
|
|
29787
29834
|
async appWorkflow(app_id, alias, inputs) {
|
|
29835
|
+
const url = `${this.baseUrl}/v1/apps/${encodeURIComponent(app_id)}/workflows/${encodeURIComponent(alias)}/execute`;
|
|
29836
|
+
const headers = this.buildHeaders();
|
|
29837
|
+
headers["Content-Type"] = "application/json";
|
|
29838
|
+
let response;
|
|
29839
|
+
try {
|
|
29840
|
+
response = await fetch(url, { method: "POST", headers, body: JSON.stringify({ inputs }) });
|
|
29841
|
+
} catch (err2) {
|
|
29842
|
+
return { status: "error", message: err2 instanceof Error ? err2.message : "The workflow request failed." };
|
|
29843
|
+
}
|
|
29844
|
+
const text = await response.text();
|
|
29845
|
+
let parsed = null;
|
|
29846
|
+
if (text) {
|
|
29847
|
+
try {
|
|
29848
|
+
parsed = JSON.parse(text);
|
|
29849
|
+
} catch {
|
|
29850
|
+
}
|
|
29851
|
+
}
|
|
29852
|
+
if (response.ok) return parsed ?? {};
|
|
29853
|
+
return { status: "error", message: transportErrorMessage(response.status, parsed) };
|
|
29854
|
+
}
|
|
29855
|
+
/**
|
|
29856
|
+
* Bind (create or replace) an app workflow by alias via the `set_app_workflow`
|
|
29857
|
+
* tool — the SINGLE author of `apps.workflows` + the workflow row. `source` is
|
|
29858
|
+
* the verbatim JS-subset body (no `on({...})` trigger). `inputs`/`outputs` are
|
|
29859
|
+
* the typed schemas declared in `package.json#lotics.workflows.<alias>`. The
|
|
29860
|
+
* server re-verifies the body and echoes the bound `outputs` (declared, else
|
|
29861
|
+
* DERIVED from `return({ data })`), so the CLI can show the author what shape
|
|
29862
|
+
* `result.data` will carry. Wraps the tool rather than a bespoke endpoint so
|
|
29863
|
+
* the file flow stays a convenience over the existing single-author contract.
|
|
29864
|
+
*/
|
|
29865
|
+
async setAppWorkflow(app_id, alias, body) {
|
|
29866
|
+
return this.execute("set_app_workflow", {
|
|
29867
|
+
app_id,
|
|
29868
|
+
alias,
|
|
29869
|
+
source: body.source,
|
|
29870
|
+
...body.inputs ? { inputs: body.inputs } : {},
|
|
29871
|
+
...body.outputs ? { outputs: body.outputs } : {},
|
|
29872
|
+
...body.name ? { name: body.name } : {},
|
|
29873
|
+
...body.description ? { description: body.description } : {}
|
|
29874
|
+
});
|
|
29875
|
+
}
|
|
29876
|
+
/**
|
|
29877
|
+
* Fetch one app workflow's faithful source + bound input/output schemas via
|
|
29878
|
+
* `get_app_workflow`. `source` is the JS-subset body re-rendered from the
|
|
29879
|
+
* persisted step tree (incl. the `return({ data })` clause, opaque field/option
|
|
29880
|
+
* keys) — the exact text `lotics app workflow set` would push back. Feeds
|
|
29881
|
+
* `lotics app pull`, which writes it to `src/workflows/<alias>.ts`.
|
|
29882
|
+
*/
|
|
29883
|
+
async getAppWorkflow(app_id, alias) {
|
|
29884
|
+
return this.execute("get_app_workflow", { app_id, alias });
|
|
29885
|
+
}
|
|
29886
|
+
/**
|
|
29887
|
+
* Fetch the server-generated workspace `.d.ts` + the wrapper envelope that
|
|
29888
|
+
* make a `src/workflows/<alias>.ts` body locally typecheckable (GAP-59).
|
|
29889
|
+
* The server is the single source of the type model — the CLI never
|
|
29890
|
+
* re-implements it. `envelope_prefix`/`envelope_suffix` are the exact
|
|
29891
|
+
* `async function __workflow(): …` wrapper the server compiles inside, so the
|
|
29892
|
+
* local typecheck mirrors the set-time verdict. Mirrors
|
|
29893
|
+
* POST /v1/apps/{app_id}/workflows/{alias}/dts.
|
|
29894
|
+
*/
|
|
29895
|
+
async getAppWorkflowDts(app_id, alias) {
|
|
29788
29896
|
return this.request(
|
|
29789
29897
|
"POST",
|
|
29790
|
-
`/v1/apps/${encodeURIComponent(app_id)}/workflows/${encodeURIComponent(alias)}/
|
|
29791
|
-
{ inputs }
|
|
29898
|
+
`/v1/apps/${encodeURIComponent(app_id)}/workflows/${encodeURIComponent(alias)}/dts`
|
|
29792
29899
|
);
|
|
29793
29900
|
}
|
|
29794
29901
|
/**
|
|
@@ -30339,6 +30446,45 @@ function buildStarterTemplate(args) {
|
|
|
30339
30446
|
// fall to `unknown`. The explicit glob makes the dot-dir the non-wildcard
|
|
30340
30447
|
// base, which IS read. (GAP-38.)
|
|
30341
30448
|
include: ["src", ".lotics/**/*"],
|
|
30449
|
+
// src/workflows/<alias>.ts bodies run on the server (workflow globals:
|
|
30450
|
+
// trigger / runtime / tool calls). They ARE locally typecheckable —
|
|
30451
|
+
// each is wrapped in the server's `__workflow` envelope and references
|
|
30452
|
+
// its per-alias `.lotics/workflows/<alias>.globals.d.ts` — but under a
|
|
30453
|
+
// DEDICATED config that mirrors the server's compile options (es2022
|
|
30454
|
+
// lib, NO DOM). The main `npm run typecheck` excludes them so it stays
|
|
30455
|
+
// green and DOM-lib-free for bodies; check a body with
|
|
30456
|
+
// `tsc -p tsconfig.workflows.json`. The server is the single verifier
|
|
30457
|
+
// on `lotics app workflow set`.
|
|
30458
|
+
exclude: ["node_modules", "src/workflows"]
|
|
30459
|
+
},
|
|
30460
|
+
null,
|
|
30461
|
+
2
|
|
30462
|
+
) + "\n"
|
|
30463
|
+
},
|
|
30464
|
+
{
|
|
30465
|
+
// Dedicated config for the editable workflow bodies (GAP-59). Mirrors the
|
|
30466
|
+
// SERVER's set-time typecheck options (strict, lib es2022 with NO DOM,
|
|
30467
|
+
// target ES2022, skipLibCheck) so a local `tsc -p tsconfig.workflows.json`
|
|
30468
|
+
// gives the same verdict the server would on `lotics app workflow set`.
|
|
30469
|
+
// Each body file is a module (the CLI writes a bookkeeping `export {};`),
|
|
30470
|
+
// so the per-file `__workflow` wrapper doesn't collide across bodies.
|
|
30471
|
+
path: "tsconfig.workflows.json",
|
|
30472
|
+
content: JSON.stringify(
|
|
30473
|
+
{
|
|
30474
|
+
compilerOptions: {
|
|
30475
|
+
target: "ES2022",
|
|
30476
|
+
lib: ["ES2022"],
|
|
30477
|
+
module: "ESNext",
|
|
30478
|
+
moduleResolution: "Bundler",
|
|
30479
|
+
strict: true,
|
|
30480
|
+
skipLibCheck: true,
|
|
30481
|
+
noEmit: true,
|
|
30482
|
+
types: []
|
|
30483
|
+
},
|
|
30484
|
+
// The bodies + their per-alias ambient globals. `.lotics/workflows`
|
|
30485
|
+
// uses the explicit `**/*` glob for the same dot-dir walk reason the
|
|
30486
|
+
// main config does (TS's include walk skips bare dot-dirs).
|
|
30487
|
+
include: ["src/workflows", ".lotics/workflows/**/*"],
|
|
30342
30488
|
exclude: ["node_modules"]
|
|
30343
30489
|
},
|
|
30344
30490
|
null,
|
|
@@ -30678,6 +30824,60 @@ const routes = [
|
|
|
30678
30824
|
export default function App() {
|
|
30679
30825
|
return <AppRouter routes={routes} />;
|
|
30680
30826
|
}
|
|
30827
|
+
`
|
|
30828
|
+
},
|
|
30829
|
+
{
|
|
30830
|
+
// The home for editable workflow bodies. `lotics app pull` writes one
|
|
30831
|
+
// `src/workflows/<alias>.ts` per bound workflow (faithful server source);
|
|
30832
|
+
// edit it, then `lotics app workflow set <alias>` pushes it back through
|
|
30833
|
+
// set_app_workflow (the server verifies). A new app has no bound workflows
|
|
30834
|
+
// yet, so this is just the docked directory + the loop reference. It's a
|
|
30835
|
+
// .md (not a .ts) so tsc's `include: ["src"]` never tries to compile it —
|
|
30836
|
+
// a workflow body is a JS-subset expression over server globals
|
|
30837
|
+
// (trigger / runtime / tool calls) that does NOT typecheck standalone.
|
|
30838
|
+
path: "src/workflows/README.md",
|
|
30839
|
+
content: `# Workflow bodies
|
|
30840
|
+
|
|
30841
|
+
Editable JS-subset bodies of this app's workflows live here, one file per alias:
|
|
30842
|
+
\`src/workflows/<alias>.ts\`.
|
|
30843
|
+
|
|
30844
|
+
## Loop
|
|
30845
|
+
|
|
30846
|
+
\`\`\`bash
|
|
30847
|
+
lotics app workflow pull # write/refresh every src/workflows/<alias>.ts from the server
|
|
30848
|
+
# edit src/workflows/<alias>.ts
|
|
30849
|
+
lotics app workflow set <alias> # push it back through set_app_workflow (the server verifies)
|
|
30850
|
+
\`\`\`
|
|
30851
|
+
|
|
30852
|
+
\`lotics app pull <app_id>\` also writes these files (alongside the rest of the project).
|
|
30853
|
+
|
|
30854
|
+
## What a body is
|
|
30855
|
+
|
|
30856
|
+
A workflow body is a **JS-subset expression** that runs server-side using workflow
|
|
30857
|
+
globals (\`trigger\`, \`runtime\`, tool calls) and ends with \`return({ data })\`. Each
|
|
30858
|
+
pulled file wraps the body in the server's \`__workflow\` envelope and references its
|
|
30859
|
+
per-alias ambient globals at \`.lotics/workflows/<alias>.globals.d.ts\`, so it **is**
|
|
30860
|
+
locally typecheckable \u2014 under the dedicated config that mirrors the server's compile
|
|
30861
|
+
options:
|
|
30862
|
+
|
|
30863
|
+
\`\`\`bash
|
|
30864
|
+
tsc -p tsconfig.workflows.json # same verdict the server gives on \`set\`
|
|
30865
|
+
\`\`\`
|
|
30866
|
+
|
|
30867
|
+
The main \`npm run typecheck\` excludes \`src/workflows\` (it would apply the app's
|
|
30868
|
+
DOM lib, which the server doesn't), so the bodies have their own config. The
|
|
30869
|
+
verification that matters still runs on the **server** when you \`set\` \u2014 the same
|
|
30870
|
+
guarantee as authoring via \`set_app_workflow\` directly. Edit only the body BETWEEN
|
|
30871
|
+
the wrapper lines; the wrapper, the \`/// <reference>\`, and the \`export {};\` marker
|
|
30872
|
+
are CLI bookkeeping (stripped on \`set\`). Do not rename a file (the filename is the
|
|
30873
|
+
alias the binding is keyed by).
|
|
30874
|
+
|
|
30875
|
+
## Authority
|
|
30876
|
+
|
|
30877
|
+
\`lotics app deploy\` never authors workflows \u2014 it carries code, queries, and
|
|
30878
|
+
capabilities only. \`apps.workflows\` has exactly one author: \`set_app_workflow\`
|
|
30879
|
+
(which \`lotics app workflow set\` calls). The typed \`inputs\`/\`outputs\` schema for
|
|
30880
|
+
each alias lives in \`package.json#lotics.workflows.<alias>\`.
|
|
30681
30881
|
`
|
|
30682
30882
|
},
|
|
30683
30883
|
{
|
|
@@ -30867,6 +31067,18 @@ import http from "node:http";
|
|
|
30867
31067
|
import net from "node:net";
|
|
30868
31068
|
import { spawn } from "node:child_process";
|
|
30869
31069
|
|
|
31070
|
+
// src/child_env.ts
|
|
31071
|
+
function ipv4ChildEnv(env) {
|
|
31072
|
+
return {
|
|
31073
|
+
...env,
|
|
31074
|
+
NODE_OPTIONS: [
|
|
31075
|
+
env.NODE_OPTIONS,
|
|
31076
|
+
"--dns-result-order=ipv4first",
|
|
31077
|
+
"--network-family-autoselection-attempt-timeout=2000"
|
|
31078
|
+
].filter(Boolean).join(" ")
|
|
31079
|
+
};
|
|
31080
|
+
}
|
|
31081
|
+
|
|
30870
31082
|
// src/dev/rpc_handler.ts
|
|
30871
31083
|
var SUPPORTED_OPS = /* @__PURE__ */ new Set([
|
|
30872
31084
|
"query",
|
|
@@ -31327,7 +31539,7 @@ async function startDevServer(args) {
|
|
|
31327
31539
|
{
|
|
31328
31540
|
cwd: args.projectDir,
|
|
31329
31541
|
stdio: [process.stdin.isTTY ? "inherit" : "ignore", "inherit", "inherit"],
|
|
31330
|
-
env: { ...process.env, FORCE_COLOR: "1" }
|
|
31542
|
+
env: ipv4ChildEnv({ ...process.env, FORCE_COLOR: "1" })
|
|
31331
31543
|
}
|
|
31332
31544
|
);
|
|
31333
31545
|
let stopped = false;
|
|
@@ -31751,6 +31963,162 @@ ${lines.join("\n")}
|
|
|
31751
31963
|
`;
|
|
31752
31964
|
}
|
|
31753
31965
|
|
|
31966
|
+
// ../shared/src/app_query_ast.ts
|
|
31967
|
+
function collectQueryTableIds(node) {
|
|
31968
|
+
const result = /* @__PURE__ */ new Set();
|
|
31969
|
+
walk(node, (n) => {
|
|
31970
|
+
if (n.kind === "from_table") result.add(n.table_id);
|
|
31971
|
+
});
|
|
31972
|
+
return result;
|
|
31973
|
+
}
|
|
31974
|
+
function walk(node, visit) {
|
|
31975
|
+
visit(node);
|
|
31976
|
+
switch (node.kind) {
|
|
31977
|
+
case "from_table":
|
|
31978
|
+
return;
|
|
31979
|
+
case "project":
|
|
31980
|
+
case "filter":
|
|
31981
|
+
case "group":
|
|
31982
|
+
case "window":
|
|
31983
|
+
case "sort":
|
|
31984
|
+
case "limit":
|
|
31985
|
+
case "unpivot":
|
|
31986
|
+
walk(node.from, visit);
|
|
31987
|
+
return;
|
|
31988
|
+
case "join":
|
|
31989
|
+
walk(node.left, visit);
|
|
31990
|
+
walk(node.right, visit);
|
|
31991
|
+
return;
|
|
31992
|
+
case "union":
|
|
31993
|
+
for (const child of node.sources) walk(child, visit);
|
|
31994
|
+
return;
|
|
31995
|
+
default: {
|
|
31996
|
+
const _exhaustive = node;
|
|
31997
|
+
void _exhaustive;
|
|
31998
|
+
return;
|
|
31999
|
+
}
|
|
32000
|
+
}
|
|
32001
|
+
}
|
|
32002
|
+
|
|
32003
|
+
// src/generate_app_fields.ts
|
|
32004
|
+
var HEADER4 = `// Auto-generated by 'lotics app codegen' (and app pull/dev/deploy).
|
|
32005
|
+
// DO NOT EDIT \u2014 regenerated from the workspace schema.
|
|
32006
|
+
//
|
|
32007
|
+
// Runtime field + option ids addressed by stable display-name aliases:
|
|
32008
|
+
// record.data[F.<TABLE>.<field>] \u2192 "fld_\u2026"
|
|
32009
|
+
// value === OPT.<TABLE>.<field>.<option> \u2192 "opt_\u2026"
|
|
32010
|
+
// A rename on the platform re-runs codegen and moves these in lockstep.
|
|
32011
|
+
`;
|
|
32012
|
+
function slugifyAlias(name, upper) {
|
|
32013
|
+
const stripped = name.normalize("NFD").replace(/[̀-ͯ]/g, "").replace(/đ/g, "d").replace(/Đ/g, "D");
|
|
32014
|
+
const cased = upper ? stripped.toUpperCase() : stripped.toLowerCase();
|
|
32015
|
+
const slug = cased.replace(/[^a-zA-Z0-9]+/g, "_").replace(/^_+|_+$/g, "");
|
|
32016
|
+
if (slug === "") return "_";
|
|
32017
|
+
return /^[0-9]/.test(slug) ? `_${slug}` : slug;
|
|
32018
|
+
}
|
|
32019
|
+
function dedupeAliases(names, upper) {
|
|
32020
|
+
const used = /* @__PURE__ */ new Map();
|
|
32021
|
+
return names.map((name) => {
|
|
32022
|
+
const base = slugifyAlias(name, upper);
|
|
32023
|
+
const seen = used.get(base);
|
|
32024
|
+
if (seen === void 0) {
|
|
32025
|
+
used.set(base, 1);
|
|
32026
|
+
return base;
|
|
32027
|
+
}
|
|
32028
|
+
let n = seen + 1;
|
|
32029
|
+
while (used.has(`${base}_${n}`)) n++;
|
|
32030
|
+
used.set(base, n);
|
|
32031
|
+
used.set(`${base}_${n}`, 1);
|
|
32032
|
+
return `${base}_${n}`;
|
|
32033
|
+
});
|
|
32034
|
+
}
|
|
32035
|
+
function propKey(alias) {
|
|
32036
|
+
return isValidIdentifier(alias) ? alias : JSON.stringify(alias);
|
|
32037
|
+
}
|
|
32038
|
+
function aliasTables(tables) {
|
|
32039
|
+
const tableAliases = dedupeAliases(
|
|
32040
|
+
tables.map((t) => t.name),
|
|
32041
|
+
true
|
|
32042
|
+
);
|
|
32043
|
+
return tables.map((table, i2) => {
|
|
32044
|
+
const fieldAliases = dedupeAliases(
|
|
32045
|
+
table.fields.map((f) => f.name),
|
|
32046
|
+
false
|
|
32047
|
+
);
|
|
32048
|
+
return {
|
|
32049
|
+
alias: tableAliases[i2],
|
|
32050
|
+
table,
|
|
32051
|
+
fields: table.fields.map((field, j) => ({ alias: fieldAliases[j], field }))
|
|
32052
|
+
};
|
|
32053
|
+
});
|
|
32054
|
+
}
|
|
32055
|
+
function emitFieldMap(aliased) {
|
|
32056
|
+
const tableBlocks = aliased.map(({ alias, fields }) => {
|
|
32057
|
+
const fieldLines = fields.map(
|
|
32058
|
+
({ alias: fieldAlias, field }) => ` ${propKey(fieldAlias)}: ${JSON.stringify(field.id)},`
|
|
32059
|
+
);
|
|
32060
|
+
return ` ${propKey(alias)}: {
|
|
32061
|
+
${fieldLines.join("\n")}
|
|
32062
|
+
},`;
|
|
32063
|
+
});
|
|
32064
|
+
return `export const F = {
|
|
32065
|
+
${tableBlocks.join("\n")}
|
|
32066
|
+
} as const;`;
|
|
32067
|
+
}
|
|
32068
|
+
function emitOptionMap(aliased) {
|
|
32069
|
+
const tableBlocks = [];
|
|
32070
|
+
for (const { alias, fields } of aliased) {
|
|
32071
|
+
const fieldBlocks = [];
|
|
32072
|
+
for (const { alias: fieldAlias, field } of fields) {
|
|
32073
|
+
const options = field.options ?? [];
|
|
32074
|
+
if (options.length === 0) continue;
|
|
32075
|
+
const optionAliases = dedupeAliases(
|
|
32076
|
+
options.map((o) => o.label),
|
|
32077
|
+
false
|
|
32078
|
+
);
|
|
32079
|
+
const optionLines = options.map(
|
|
32080
|
+
(option, i2) => ` ${propKey(optionAliases[i2])}: ${JSON.stringify(option.id)},`
|
|
32081
|
+
);
|
|
32082
|
+
fieldBlocks.push(` ${propKey(fieldAlias)}: {
|
|
32083
|
+
${optionLines.join("\n")}
|
|
32084
|
+
},`);
|
|
32085
|
+
}
|
|
32086
|
+
if (fieldBlocks.length === 0) continue;
|
|
32087
|
+
tableBlocks.push(` ${propKey(alias)}: {
|
|
32088
|
+
${fieldBlocks.join("\n")}
|
|
32089
|
+
},`);
|
|
32090
|
+
}
|
|
32091
|
+
if (tableBlocks.length === 0) return `export const OPT = {} as const;`;
|
|
32092
|
+
return `export const OPT = {
|
|
32093
|
+
${tableBlocks.join("\n")}
|
|
32094
|
+
} as const;`;
|
|
32095
|
+
}
|
|
32096
|
+
function generateAppFields(tables) {
|
|
32097
|
+
if (tables.length === 0) {
|
|
32098
|
+
return `${HEADER4}
|
|
32099
|
+
export const F = {} as const;
|
|
32100
|
+
|
|
32101
|
+
export const OPT = {} as const;
|
|
32102
|
+
|
|
32103
|
+
/** Field-id alias map (empty \u2014 no tables in scope). */
|
|
32104
|
+
export type AppFields = typeof F;
|
|
32105
|
+
/** Select-option alias map (empty \u2014 no tables in scope). */
|
|
32106
|
+
export type AppOptions = typeof OPT;
|
|
32107
|
+
`;
|
|
32108
|
+
}
|
|
32109
|
+
const aliased = aliasTables(tables);
|
|
32110
|
+
return `${HEADER4}
|
|
32111
|
+
${emitFieldMap(aliased)}
|
|
32112
|
+
|
|
32113
|
+
${emitOptionMap(aliased)}
|
|
32114
|
+
|
|
32115
|
+
/** Field-id alias map: \`F[<TABLE>][<field>]\` is the \`fld_\u2026\` id (literal-typed). */
|
|
32116
|
+
export type AppFields = typeof F;
|
|
32117
|
+
/** Select-option alias map: \`OPT[<TABLE>][<field>][<option>]\` is the \`opt_\u2026\` id. */
|
|
32118
|
+
export type AppOptions = typeof OPT;
|
|
32119
|
+
`;
|
|
32120
|
+
}
|
|
32121
|
+
|
|
31754
32122
|
// src/app_commands.ts
|
|
31755
32123
|
async function fetchLatestNpmVersion(packageName) {
|
|
31756
32124
|
try {
|
|
@@ -31768,6 +32136,98 @@ async function fetchLatestNpmVersion(packageName) {
|
|
|
31768
32136
|
return null;
|
|
31769
32137
|
}
|
|
31770
32138
|
}
|
|
32139
|
+
var WORKFLOWS_DIR = path4.join("src", "workflows");
|
|
32140
|
+
var WORKFLOW_GLOBALS_DIR = path4.join(".lotics", "workflows");
|
|
32141
|
+
var FALLBACK_ENVELOPE_PREFIX = "async function __workflow(): Promise<__WorkflowReturn | void> {\n";
|
|
32142
|
+
var FALLBACK_ENVELOPE_SUFFIX = "\n}";
|
|
32143
|
+
function workflowFileHeader(alias) {
|
|
32144
|
+
const refPath = path4.join("..", "..", WORKFLOW_GLOBALS_DIR, `${alias}.globals.d.ts`).split(path4.sep).join("/");
|
|
32145
|
+
return `/// <reference path="${refPath}" />
|
|
32146
|
+
// Auto-pulled workflow body for "${alias}". Edit the BODY between the wrapper
|
|
32147
|
+
// lines below, then push with:
|
|
32148
|
+
// lotics app workflow set ${alias}
|
|
32149
|
+
// The push goes through set_app_workflow, where the SERVER verifies the body.
|
|
32150
|
+
// The __workflow wrapper + the reference above are CLI bookkeeping (stripped on
|
|
32151
|
+
// set) \u2014 they only make the body typecheck locally against the workspace types.
|
|
32152
|
+
// Do NOT rename this file \u2014 the filename is the alias the binding is keyed by.
|
|
32153
|
+
export {};
|
|
32154
|
+
`;
|
|
32155
|
+
}
|
|
32156
|
+
function workflowFilePath(projectDir, alias) {
|
|
32157
|
+
return path4.join(projectDir, WORKFLOWS_DIR, `${alias}.ts`);
|
|
32158
|
+
}
|
|
32159
|
+
function workflowGlobalsPath(projectDir, alias) {
|
|
32160
|
+
return path4.join(projectDir, WORKFLOW_GLOBALS_DIR, `${alias}.globals.d.ts`);
|
|
32161
|
+
}
|
|
32162
|
+
function writeWorkflowGlobals(projectDir, alias, dts) {
|
|
32163
|
+
const dir = path4.join(projectDir, WORKFLOW_GLOBALS_DIR);
|
|
32164
|
+
fs3.mkdirSync(dir, { recursive: true });
|
|
32165
|
+
const file = workflowGlobalsPath(projectDir, alias);
|
|
32166
|
+
fs3.writeFileSync(file, `${dts.replace(/\s+$/, "")}
|
|
32167
|
+
`);
|
|
32168
|
+
return file;
|
|
32169
|
+
}
|
|
32170
|
+
function writeWorkflowFile(projectDir, alias, source, envelope = { prefix: FALLBACK_ENVELOPE_PREFIX, suffix: FALLBACK_ENVELOPE_SUFFIX }) {
|
|
32171
|
+
const dir = path4.join(projectDir, WORKFLOWS_DIR);
|
|
32172
|
+
fs3.mkdirSync(dir, { recursive: true });
|
|
32173
|
+
const file = workflowFilePath(projectDir, alias);
|
|
32174
|
+
const body = source.replace(/\s+$/, "");
|
|
32175
|
+
fs3.writeFileSync(file, `${workflowFileHeader(alias)}
|
|
32176
|
+
${envelope.prefix}${body}${envelope.suffix}
|
|
32177
|
+
`);
|
|
32178
|
+
return file;
|
|
32179
|
+
}
|
|
32180
|
+
var WORKFLOW_WRAPPER_OPENER = /^\s*async\s+function\s+__workflow\s*\(/;
|
|
32181
|
+
function stripWorkflowHeader(content) {
|
|
32182
|
+
const lines = content.split("\n");
|
|
32183
|
+
let headerEnd = 0;
|
|
32184
|
+
while (headerEnd < lines.length && /^\s*\/\//.test(lines[headerEnd])) headerEnd++;
|
|
32185
|
+
while (headerEnd < lines.length && /^\s*export\s*\{\s*\}\s*;?\s*$/.test(lines[headerEnd])) headerEnd++;
|
|
32186
|
+
while (headerEnd < lines.length && lines[headerEnd].trim() === "") headerEnd++;
|
|
32187
|
+
let start;
|
|
32188
|
+
if (headerEnd < lines.length && WORKFLOW_WRAPPER_OPENER.test(lines[headerEnd])) {
|
|
32189
|
+
start = headerEnd;
|
|
32190
|
+
} else if (lines.length > 0 && WORKFLOW_WRAPPER_OPENER.test(lines[0])) {
|
|
32191
|
+
start = 0;
|
|
32192
|
+
} else {
|
|
32193
|
+
return content.replace(/\s+$/, "");
|
|
32194
|
+
}
|
|
32195
|
+
let end = lines.length - 1;
|
|
32196
|
+
while (end > start && lines[end].trim() === "") end--;
|
|
32197
|
+
if (lines[end]?.trim() === "}") {
|
|
32198
|
+
return lines.slice(start + 1, end).join("\n").replace(/\s+$/, "");
|
|
32199
|
+
}
|
|
32200
|
+
return lines.slice(start + 1).join("\n").replace(/\s+$/, "");
|
|
32201
|
+
}
|
|
32202
|
+
async function writeWorkflowFiles(client, projectDir, app_id, aliases) {
|
|
32203
|
+
const written = [];
|
|
32204
|
+
for (const alias of aliases) {
|
|
32205
|
+
const res = await client.getAppWorkflow(app_id, alias);
|
|
32206
|
+
const source = res.error || res.result === null || typeof res.result !== "object" ? null : res.result.source;
|
|
32207
|
+
if (typeof source !== "string" || source.trim() === "") {
|
|
32208
|
+
console.error(
|
|
32209
|
+
`\u26A0 Skipped src/workflows/${alias}.ts \u2014 the server returned no readable source (${res.error ?? "legacy workflow with no rendered body"}).`
|
|
32210
|
+
);
|
|
32211
|
+
continue;
|
|
32212
|
+
}
|
|
32213
|
+
const envelope = await fetchWorkflowGlobals(client, projectDir, app_id, alias);
|
|
32214
|
+
writeWorkflowFile(projectDir, alias, source, envelope);
|
|
32215
|
+
written.push(alias);
|
|
32216
|
+
}
|
|
32217
|
+
return written;
|
|
32218
|
+
}
|
|
32219
|
+
async function fetchWorkflowGlobals(client, projectDir, app_id, alias) {
|
|
32220
|
+
try {
|
|
32221
|
+
const { dts, envelope_prefix, envelope_suffix } = await client.getAppWorkflowDts(app_id, alias);
|
|
32222
|
+
writeWorkflowGlobals(projectDir, alias, dts);
|
|
32223
|
+
return { prefix: envelope_prefix, suffix: envelope_suffix };
|
|
32224
|
+
} catch (err2) {
|
|
32225
|
+
console.error(
|
|
32226
|
+
`\u26A0 Could not fetch workflow types for "${alias}" (${err2 instanceof Error ? err2.message : String(err2)}). Wrote the body with the fallback wrapper; its local typecheck may be degraded.`
|
|
32227
|
+
);
|
|
32228
|
+
return { prefix: FALLBACK_ENVELOPE_PREFIX, suffix: FALLBACK_ENVELOPE_SUFFIX };
|
|
32229
|
+
}
|
|
32230
|
+
}
|
|
31771
32231
|
function runTar(args, cwd) {
|
|
31772
32232
|
return new Promise((resolve, reject2) => {
|
|
31773
32233
|
const proc = spawn2("tar", args, { cwd, stdio: ["ignore", "ignore", "pipe"] });
|
|
@@ -31784,7 +32244,7 @@ function runTar(args, cwd) {
|
|
|
31784
32244
|
}
|
|
31785
32245
|
function runNpm(args, cwd) {
|
|
31786
32246
|
return new Promise((resolve, reject2) => {
|
|
31787
|
-
const proc = spawn2("npm", args, { cwd, stdio: "inherit" });
|
|
32247
|
+
const proc = spawn2("npm", args, { cwd, stdio: "inherit", env: ipv4ChildEnv(process.env) });
|
|
31788
32248
|
proc.on("error", reject2);
|
|
31789
32249
|
proc.on("exit", (code) => {
|
|
31790
32250
|
if (code === 0) resolve();
|
|
@@ -31823,18 +32283,71 @@ function writeAppMeta(projectDir, meta) {
|
|
|
31823
32283
|
function writeAppDts(projectDir, manifest) {
|
|
31824
32284
|
const dotLotics = path4.join(projectDir, ".lotics");
|
|
31825
32285
|
fs3.mkdirSync(dotLotics, { recursive: true });
|
|
31826
|
-
|
|
31827
|
-
path4.join(dotLotics, "app_workflows.d.ts"),
|
|
31828
|
-
|
|
31829
|
-
|
|
31830
|
-
|
|
31831
|
-
|
|
31832
|
-
|
|
31833
|
-
|
|
31834
|
-
|
|
31835
|
-
|
|
31836
|
-
|
|
31837
|
-
);
|
|
32286
|
+
const written = [
|
|
32287
|
+
[path4.join(dotLotics, "app_workflows.d.ts"), generateAppWorkflowsDts(manifest.workflows)],
|
|
32288
|
+
[path4.join(dotLotics, "app_queries.d.ts"), generateAppQueriesDts(manifest.queries)],
|
|
32289
|
+
[path4.join(dotLotics, "app_agents.d.ts"), generateAppAgentsDts(manifest.agents)]
|
|
32290
|
+
];
|
|
32291
|
+
for (const [file, content] of written) fs3.writeFileSync(file, content);
|
|
32292
|
+
return written.map(([file]) => file);
|
|
32293
|
+
}
|
|
32294
|
+
function readCodegenTablesAllowlist(projectDir) {
|
|
32295
|
+
const pkg2 = JSON.parse(fs3.readFileSync(path4.join(projectDir, "package.json"), "utf-8"));
|
|
32296
|
+
const tables = pkg2.lotics?.codegen?.tables;
|
|
32297
|
+
return Array.isArray(tables) ? tables.filter((t) => typeof t === "string") : [];
|
|
32298
|
+
}
|
|
32299
|
+
function resolveCodegenTableIds(projectDir, queries) {
|
|
32300
|
+
const ids = /* @__PURE__ */ new Set();
|
|
32301
|
+
for (const decl of Object.values(queries)) {
|
|
32302
|
+
for (const id of collectQueryTableIds(decl.ast)) ids.add(id);
|
|
32303
|
+
}
|
|
32304
|
+
for (const id of readCodegenTablesAllowlist(projectDir)) ids.add(id);
|
|
32305
|
+
return [...ids];
|
|
32306
|
+
}
|
|
32307
|
+
function writeAppFields(projectDir, tables) {
|
|
32308
|
+
const dotLotics = path4.join(projectDir, ".lotics");
|
|
32309
|
+
fs3.mkdirSync(dotLotics, { recursive: true });
|
|
32310
|
+
const file = path4.join(dotLotics, "app_fields.ts");
|
|
32311
|
+
fs3.writeFileSync(file, generateAppFields(tables));
|
|
32312
|
+
return file;
|
|
32313
|
+
}
|
|
32314
|
+
async function appCodegen(args) {
|
|
32315
|
+
const projectDir = path4.resolve(args.projectDir ?? process.cwd());
|
|
32316
|
+
const meta = readAppMeta(projectDir);
|
|
32317
|
+
const dtsPaths = writeAppDts(projectDir, {
|
|
32318
|
+
workflows: meta.workflows,
|
|
32319
|
+
queries: meta.queries,
|
|
32320
|
+
agents: meta.agents
|
|
32321
|
+
});
|
|
32322
|
+
for (const p of dtsPaths) console.error(`Regenerated ${p}`);
|
|
32323
|
+
if (!args.client) {
|
|
32324
|
+
console.error(
|
|
32325
|
+
"Skipped .lotics/app_fields.ts \u2014 no workspace credentials resolved. Run authenticated (or set LOTICS_API_KEY) to regenerate field/option ids."
|
|
32326
|
+
);
|
|
32327
|
+
return;
|
|
32328
|
+
}
|
|
32329
|
+
const tableIds = resolveCodegenTableIds(projectDir, meta.queries ?? {});
|
|
32330
|
+
try {
|
|
32331
|
+
const tables = await args.client.getWorkspaceSchema(tableIds);
|
|
32332
|
+
const fieldsPath = writeAppFields(projectDir, tables);
|
|
32333
|
+
console.error(`Regenerated ${fieldsPath} (${tables.length} table${tables.length === 1 ? "" : "s"})`);
|
|
32334
|
+
} catch (err2) {
|
|
32335
|
+
console.error(
|
|
32336
|
+
`\u26A0 Could not fetch the workspace schema (${err2 instanceof Error ? err2.message : String(err2)}). Kept the existing .lotics/app_fields.ts.`
|
|
32337
|
+
);
|
|
32338
|
+
}
|
|
32339
|
+
await refreshWorkflowGlobals(args.client, projectDir, meta.app_id, Object.keys(meta.workflows ?? {}));
|
|
32340
|
+
}
|
|
32341
|
+
async function refreshWorkflowGlobals(client, projectDir, app_id, aliases) {
|
|
32342
|
+
for (const alias of aliases) {
|
|
32343
|
+
const file = workflowFilePath(projectDir, alias);
|
|
32344
|
+
if (!fs3.existsSync(file)) continue;
|
|
32345
|
+
const body = stripWorkflowHeader(fs3.readFileSync(file, "utf-8"));
|
|
32346
|
+
if (body.trim() === "") continue;
|
|
32347
|
+
const envelope = await fetchWorkflowGlobals(client, projectDir, app_id, alias);
|
|
32348
|
+
writeWorkflowFile(projectDir, alias, body, envelope);
|
|
32349
|
+
console.error(`Refreshed ${path4.relative(projectDir, file)} + its workflow types`);
|
|
32350
|
+
}
|
|
31838
32351
|
}
|
|
31839
32352
|
function stampPulledManifest(projectDir, args) {
|
|
31840
32353
|
writeAppMeta(projectDir, {
|
|
@@ -31942,6 +32455,15 @@ async function appPull(client, args) {
|
|
|
31942
32455
|
queries: app.queries ?? {},
|
|
31943
32456
|
agents: app.agents ?? {}
|
|
31944
32457
|
});
|
|
32458
|
+
const aliases = Object.keys(app.workflows ?? {});
|
|
32459
|
+
if (aliases.length > 0) {
|
|
32460
|
+
const written = await writeWorkflowFiles(client, targetPath, app.id, aliases);
|
|
32461
|
+
if (written.length > 0) {
|
|
32462
|
+
console.error(
|
|
32463
|
+
`Wrote ${written.length} workflow ${written.length === 1 ? "body" : "bodies"} to ${WORKFLOWS_DIR}/ (${written.join(", ")})`
|
|
32464
|
+
);
|
|
32465
|
+
}
|
|
32466
|
+
}
|
|
31945
32467
|
console.error(`Installing npm dependencies...`);
|
|
31946
32468
|
await runNpm(["install"], targetPath);
|
|
31947
32469
|
console.error(`
|
|
@@ -31965,14 +32487,14 @@ function readAppSourceText(projectDir) {
|
|
|
31965
32487
|
const srcDir = path4.join(projectDir, "src");
|
|
31966
32488
|
if (!fs3.existsSync(srcDir)) return "";
|
|
31967
32489
|
const parts = [];
|
|
31968
|
-
const
|
|
32490
|
+
const walk2 = (dir) => {
|
|
31969
32491
|
for (const entry of fs3.readdirSync(dir, { withFileTypes: true })) {
|
|
31970
32492
|
const full = path4.join(dir, entry.name);
|
|
31971
|
-
if (entry.isDirectory())
|
|
32493
|
+
if (entry.isDirectory()) walk2(full);
|
|
31972
32494
|
else if (/\.(ts|tsx|js|jsx)$/.test(entry.name)) parts.push(fs3.readFileSync(full, "utf8"));
|
|
31973
32495
|
}
|
|
31974
32496
|
};
|
|
31975
|
-
|
|
32497
|
+
walk2(srcDir);
|
|
31976
32498
|
return parts.join("\n");
|
|
31977
32499
|
}
|
|
31978
32500
|
async function appDeploy(client, args) {
|
|
@@ -32119,6 +32641,209 @@ async function appDev(client, args) {
|
|
|
32119
32641
|
console.error("\nStopping\u2026");
|
|
32120
32642
|
await handle.stop();
|
|
32121
32643
|
}
|
|
32644
|
+
function parseCreatedRecords(value) {
|
|
32645
|
+
if (!Array.isArray(value)) return [];
|
|
32646
|
+
const groups = [];
|
|
32647
|
+
for (const entry of value) {
|
|
32648
|
+
if (!entry || typeof entry !== "object") continue;
|
|
32649
|
+
const tableId = entry.table_id;
|
|
32650
|
+
const recordIds = entry.record_ids;
|
|
32651
|
+
if (typeof tableId !== "string" || !Array.isArray(recordIds)) continue;
|
|
32652
|
+
const ids = recordIds.filter((id) => typeof id === "string");
|
|
32653
|
+
if (ids.length > 0) groups.push({ table_id: tableId, record_ids: ids });
|
|
32654
|
+
}
|
|
32655
|
+
return groups;
|
|
32656
|
+
}
|
|
32657
|
+
function parseIrreversibleToolNames(value) {
|
|
32658
|
+
if (!Array.isArray(value)) return [];
|
|
32659
|
+
const names = [];
|
|
32660
|
+
for (const entry of value) {
|
|
32661
|
+
if (!entry || typeof entry !== "object") continue;
|
|
32662
|
+
const name = entry.tool_name;
|
|
32663
|
+
if (typeof name === "string" && !names.includes(name)) names.push(name);
|
|
32664
|
+
}
|
|
32665
|
+
return names;
|
|
32666
|
+
}
|
|
32667
|
+
function printSideEffects(summary) {
|
|
32668
|
+
const created = parseCreatedRecords(summary.created_records);
|
|
32669
|
+
const irreversibleTools = parseIrreversibleToolNames(summary.irreversible_tool_calls);
|
|
32670
|
+
const subWorkflows = summary.sub_workflows_possible === true;
|
|
32671
|
+
console.error("\nCreated records:");
|
|
32672
|
+
if (created.length === 0) {
|
|
32673
|
+
console.error(" (none with ids to clean up)");
|
|
32674
|
+
} else {
|
|
32675
|
+
for (const group of created) {
|
|
32676
|
+
console.error(` ${group.table_id}: ${group.record_ids.length} record(s)`);
|
|
32677
|
+
const payload = JSON.stringify({ table_id: group.table_id, record_ids: group.record_ids });
|
|
32678
|
+
console.error(` lotics run delete_records '${payload}'`);
|
|
32679
|
+
}
|
|
32680
|
+
}
|
|
32681
|
+
const irreversiblePart = irreversibleTools.length > 0 ? `Could NOT auto-undo (clean up manually): ${irreversibleTools.join(", ")}.` : "Could NOT auto-undo: none.";
|
|
32682
|
+
const subPart = subWorkflows ? " Sub-workflows may have run (after_* table workflows) \u2014 their effects are NOT in this list." : "";
|
|
32683
|
+
console.error(`
|
|
32684
|
+
${irreversiblePart}${subPart}`);
|
|
32685
|
+
}
|
|
32686
|
+
async function cleanupCreatedRecords(client, created) {
|
|
32687
|
+
if (created.length === 0) {
|
|
32688
|
+
console.error("\nNo created records to clean up.");
|
|
32689
|
+
return true;
|
|
32690
|
+
}
|
|
32691
|
+
console.error("\nCleaning up created records (delete_records \u2014 records only):");
|
|
32692
|
+
let allDeleted = true;
|
|
32693
|
+
for (const group of created) {
|
|
32694
|
+
const res = await client.execute("delete_records", {
|
|
32695
|
+
table_id: group.table_id,
|
|
32696
|
+
record_ids: group.record_ids
|
|
32697
|
+
});
|
|
32698
|
+
if (res.error) {
|
|
32699
|
+
console.error(` \u2717 ${group.table_id}: ${res.error}`);
|
|
32700
|
+
allDeleted = false;
|
|
32701
|
+
} else {
|
|
32702
|
+
console.error(` \u2713 ${group.table_id}: deleted ${group.record_ids.length} record(s)`);
|
|
32703
|
+
}
|
|
32704
|
+
}
|
|
32705
|
+
return allDeleted;
|
|
32706
|
+
}
|
|
32707
|
+
async function appExecuteWorkflow(client, args) {
|
|
32708
|
+
const meta = readAppMeta(process.cwd());
|
|
32709
|
+
const result = await client.appWorkflow(meta.app_id, args.alias, args.inputs);
|
|
32710
|
+
console.log(JSON.stringify(result, null, 2));
|
|
32711
|
+
const status = typeof result.status === "string" ? result.status : "unknown";
|
|
32712
|
+
const message = typeof result.message === "string" ? result.message : "";
|
|
32713
|
+
console.error(`Workflow "${args.alias}" \u2192 ${status}${message ? `: ${message}` : ""}`);
|
|
32714
|
+
let cleanupFailed = false;
|
|
32715
|
+
if ((args.printCreated || args.cleanup) && result.side_effects) {
|
|
32716
|
+
printSideEffects(result.side_effects);
|
|
32717
|
+
if (args.cleanup) {
|
|
32718
|
+
const allDeleted = await cleanupCreatedRecords(
|
|
32719
|
+
client,
|
|
32720
|
+
parseCreatedRecords(result.side_effects.created_records)
|
|
32721
|
+
);
|
|
32722
|
+
cleanupFailed = !allDeleted;
|
|
32723
|
+
}
|
|
32724
|
+
} else if (args.printCreated || args.cleanup) {
|
|
32725
|
+
console.error("\n(no side-effect summary returned by the server)");
|
|
32726
|
+
}
|
|
32727
|
+
if (status === "error" || cleanupFailed) process.exit(1);
|
|
32728
|
+
}
|
|
32729
|
+
async function appWorkflowSet(client, args) {
|
|
32730
|
+
const projectDir = process.cwd();
|
|
32731
|
+
const meta = readAppMeta(projectDir);
|
|
32732
|
+
const declaration = meta.workflows?.[args.alias];
|
|
32733
|
+
if (!declaration) {
|
|
32734
|
+
console.error(
|
|
32735
|
+
`No workflow "${args.alias}" in package.json#lotics.workflows. Bind it first (set_app_workflow), then 'lotics app pull' to write its body and manifest entry.`
|
|
32736
|
+
);
|
|
32737
|
+
process.exit(1);
|
|
32738
|
+
}
|
|
32739
|
+
const file = workflowFilePath(projectDir, args.alias);
|
|
32740
|
+
if (!fs3.existsSync(file)) {
|
|
32741
|
+
console.error(
|
|
32742
|
+
`No workflow body at ${path4.relative(projectDir, file)}. Run 'lotics app pull ${meta.app_id}' to write src/workflows/${args.alias}.ts, then edit it.`
|
|
32743
|
+
);
|
|
32744
|
+
process.exit(1);
|
|
32745
|
+
}
|
|
32746
|
+
const source = stripWorkflowHeader(fs3.readFileSync(file, "utf-8"));
|
|
32747
|
+
if (source.trim() === "") {
|
|
32748
|
+
console.error(`Workflow body ${path4.relative(projectDir, file)} is empty after stripping the header.`);
|
|
32749
|
+
process.exit(1);
|
|
32750
|
+
}
|
|
32751
|
+
const res = await client.setAppWorkflow(meta.app_id, args.alias, {
|
|
32752
|
+
source,
|
|
32753
|
+
inputs: declaration.inputs,
|
|
32754
|
+
outputs: declaration.outputs
|
|
32755
|
+
});
|
|
32756
|
+
if (res.error) {
|
|
32757
|
+
console.error(`Failed to set workflow "${args.alias}": ${res.error}`);
|
|
32758
|
+
process.exit(1);
|
|
32759
|
+
}
|
|
32760
|
+
const result = res.result ?? {};
|
|
32761
|
+
const workflowId = typeof result.workflow_id === "string" ? result.workflow_id : "(unknown)";
|
|
32762
|
+
console.error(`Set workflow "${args.alias}" \u2192 ${workflowId}`);
|
|
32763
|
+
if (result.outputs && typeof result.outputs === "object") {
|
|
32764
|
+
console.error(` result.data schema: ${JSON.stringify(result.outputs)}`);
|
|
32765
|
+
}
|
|
32766
|
+
}
|
|
32767
|
+
async function appWorkflowPull(client) {
|
|
32768
|
+
const projectDir = process.cwd();
|
|
32769
|
+
const meta = readAppMeta(projectDir);
|
|
32770
|
+
const app = await client.getApp(meta.app_id);
|
|
32771
|
+
const aliases = Object.keys(app.workflows ?? {});
|
|
32772
|
+
if (aliases.length === 0) {
|
|
32773
|
+
console.error(`App ${meta.app_id} has no bound workflows.`);
|
|
32774
|
+
return;
|
|
32775
|
+
}
|
|
32776
|
+
const written = await writeWorkflowFiles(client, projectDir, meta.app_id, aliases);
|
|
32777
|
+
console.error(
|
|
32778
|
+
`Wrote ${written.length} workflow ${written.length === 1 ? "body" : "bodies"} to ${WORKFLOWS_DIR}/` + (written.length > 0 ? ` (${written.join(", ")})` : "")
|
|
32779
|
+
);
|
|
32780
|
+
}
|
|
32781
|
+
function findUiSrcDir(start) {
|
|
32782
|
+
let dir = path4.resolve(start);
|
|
32783
|
+
for (; ; ) {
|
|
32784
|
+
const candidate = path4.join(dir, "packages", "ui", "src");
|
|
32785
|
+
if (fs3.existsSync(candidate) && fs3.statSync(candidate).isDirectory()) return candidate;
|
|
32786
|
+
const parent = path4.dirname(dir);
|
|
32787
|
+
if (parent === dir) return null;
|
|
32788
|
+
dir = parent;
|
|
32789
|
+
}
|
|
32790
|
+
}
|
|
32791
|
+
var UI_ALIAS_FIND_SOURCE = String.raw`/^@lotics\/ui\/(.+)$/`;
|
|
32792
|
+
function appUiLink(args) {
|
|
32793
|
+
const projectDir = path4.resolve(args.projectDir ?? process.cwd());
|
|
32794
|
+
const viteConfigPath = path4.join(projectDir, "vite.config.ts");
|
|
32795
|
+
if (!fs3.existsSync(viteConfigPath)) {
|
|
32796
|
+
throw new Error(
|
|
32797
|
+
`No vite.config.ts at ${projectDir}. Run inside a 'lotics app' project directory.`
|
|
32798
|
+
);
|
|
32799
|
+
}
|
|
32800
|
+
const uiSrc = findUiSrcDir(projectDir);
|
|
32801
|
+
if (!uiSrc) {
|
|
32802
|
+
throw new Error(
|
|
32803
|
+
"Cannot find packages/ui/src by walking up from this directory \u2014 `lotics ui link` requires a monorepo checkout. External apps consume @lotics/ui from npm; bump the package version and widen the app's dependency range instead."
|
|
32804
|
+
);
|
|
32805
|
+
}
|
|
32806
|
+
const hasComponent = fs3.existsSync(path4.join(uiSrc, `${args.component}.tsx`)) || fs3.existsSync(path4.join(uiSrc, `${args.component}.ts`)) || fs3.existsSync(path4.join(uiSrc, args.component));
|
|
32807
|
+
if (!hasComponent) {
|
|
32808
|
+
throw new Error(
|
|
32809
|
+
`No '@lotics/ui/${args.component}' under ${uiSrc} (expected ${args.component}.tsx/.ts). Check the component name.`
|
|
32810
|
+
);
|
|
32811
|
+
}
|
|
32812
|
+
const source = fs3.readFileSync(viteConfigPath, "utf-8");
|
|
32813
|
+
const aliasEntry = `{ find: ${UI_ALIAS_FIND_SOURCE}, replacement: ${JSON.stringify(`${uiSrc}/$1`)} },`;
|
|
32814
|
+
const alreadyLinked = source.includes(UI_ALIAS_FIND_SOURCE);
|
|
32815
|
+
if (args.remove) {
|
|
32816
|
+
if (!alreadyLinked) {
|
|
32817
|
+
console.error("No @lotics/ui dev-link alias present \u2014 nothing to remove.");
|
|
32818
|
+
return;
|
|
32819
|
+
}
|
|
32820
|
+
const stripped = source.replace(new RegExp(`^\\s*\\{ find: ${escapeRegExp(UI_ALIAS_FIND_SOURCE)}.*$\\n?`, "m"), "");
|
|
32821
|
+
fs3.writeFileSync(viteConfigPath, stripped);
|
|
32822
|
+
console.error(`Removed the @lotics/ui dev-link alias from ${viteConfigPath}.`);
|
|
32823
|
+
console.error("Restart `lotics app dev` and rm -rf node_modules/.vite to clear cached modules.");
|
|
32824
|
+
return;
|
|
32825
|
+
}
|
|
32826
|
+
if (alreadyLinked) {
|
|
32827
|
+
console.error(`@lotics/ui is already dev-linked in ${viteConfigPath}.`);
|
|
32828
|
+
return;
|
|
32829
|
+
}
|
|
32830
|
+
const aliasMatch = /resolve\s*:\s*\{[\s\S]*?alias\s*:\s*\[/.exec(source);
|
|
32831
|
+
if (!aliasMatch) {
|
|
32832
|
+
throw new Error(
|
|
32833
|
+
`Could not find a resolve.alias array literal in ${viteConfigPath}. Refresh vite.config.ts from the starter (packages/sdk/src/starter_template.ts) and retry.`
|
|
32834
|
+
);
|
|
32835
|
+
}
|
|
32836
|
+
const insertAt = aliasMatch.index + aliasMatch[0].length;
|
|
32837
|
+
const updated = `${source.slice(0, insertAt)}
|
|
32838
|
+
${aliasEntry}${source.slice(insertAt)}`;
|
|
32839
|
+
fs3.writeFileSync(viteConfigPath, updated);
|
|
32840
|
+
console.error(`Dev-linked @lotics/ui \u2192 ${uiSrc} in ${viteConfigPath}.`);
|
|
32841
|
+
console.error("Restart `lotics app dev` and rm -rf node_modules/.vite to clear cached modules.");
|
|
32842
|
+
console.error("Finalize: PR the packages/ui change \u2192 publish \u2192 `lotics ui link <component> --remove` + bump the app's dep.");
|
|
32843
|
+
}
|
|
32844
|
+
function escapeRegExp(s) {
|
|
32845
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
32846
|
+
}
|
|
32122
32847
|
|
|
32123
32848
|
// src/args.ts
|
|
32124
32849
|
function parseArgs(argv) {
|
|
@@ -32135,6 +32860,8 @@ function parseArgs(argv) {
|
|
|
32135
32860
|
message: void 0,
|
|
32136
32861
|
local: false,
|
|
32137
32862
|
all: false,
|
|
32863
|
+
printCreated: false,
|
|
32864
|
+
cleanup: false,
|
|
32138
32865
|
version: false,
|
|
32139
32866
|
help: false
|
|
32140
32867
|
};
|
|
@@ -32185,6 +32912,13 @@ function parseArgs(argv) {
|
|
|
32185
32912
|
case "--all":
|
|
32186
32913
|
flags.all = true;
|
|
32187
32914
|
break;
|
|
32915
|
+
case "--print-created":
|
|
32916
|
+
case "--report-effects":
|
|
32917
|
+
flags.printCreated = true;
|
|
32918
|
+
break;
|
|
32919
|
+
case "--cleanup":
|
|
32920
|
+
flags.cleanup = true;
|
|
32921
|
+
break;
|
|
32188
32922
|
case "--version":
|
|
32189
32923
|
case "-v":
|
|
32190
32924
|
flags.version = true;
|
|
@@ -32210,6 +32944,34 @@ function parseArgs(argv) {
|
|
|
32210
32944
|
return { command, subcommand, toolArgs, restArgs, flags };
|
|
32211
32945
|
}
|
|
32212
32946
|
|
|
32947
|
+
// src/inputs.ts
|
|
32948
|
+
async function ingestJsonArgs(opts) {
|
|
32949
|
+
let raw = opts.rawArg;
|
|
32950
|
+
if (raw && raw.startsWith("@")) {
|
|
32951
|
+
const argsPath = raw.slice(1);
|
|
32952
|
+
try {
|
|
32953
|
+
raw = opts.readFile(argsPath);
|
|
32954
|
+
} catch (err2) {
|
|
32955
|
+
return {
|
|
32956
|
+
kind: "error",
|
|
32957
|
+
message: `Cannot read args file "${argsPath}": ${err2 instanceof Error ? err2.message : String(err2)}`
|
|
32958
|
+
};
|
|
32959
|
+
}
|
|
32960
|
+
} else if (!raw && !opts.stdinIsTTY) {
|
|
32961
|
+
raw = await opts.readStdin();
|
|
32962
|
+
}
|
|
32963
|
+
if (!raw) return { kind: "ok", args: {} };
|
|
32964
|
+
try {
|
|
32965
|
+
const parsed = JSON.parse(raw);
|
|
32966
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
32967
|
+
return { kind: "error", message: `JSON args must be an object, got: ${raw}` };
|
|
32968
|
+
}
|
|
32969
|
+
return { kind: "ok", args: parsed };
|
|
32970
|
+
} catch {
|
|
32971
|
+
return { kind: "error", message: `Invalid JSON: ${raw}` };
|
|
32972
|
+
}
|
|
32973
|
+
}
|
|
32974
|
+
|
|
32213
32975
|
// src/xlsx.ts
|
|
32214
32976
|
import fs5 from "node:fs";
|
|
32215
32977
|
|
|
@@ -38666,8 +39428,8 @@ function parseWorkbook(workbookXml) {
|
|
|
38666
39428
|
}
|
|
38667
39429
|
return { sheets, activeSheetIndex, date1904, namedRanges, printTitlesBySheet, fullCalcOnLoad };
|
|
38668
39430
|
}
|
|
38669
|
-
function parseWorkbookRels(
|
|
38670
|
-
const doc = xmlParser3.parse(
|
|
39431
|
+
function parseWorkbookRels(relsXml2) {
|
|
39432
|
+
const doc = xmlParser3.parse(relsXml2);
|
|
38671
39433
|
const rels = doc?.["Relationships"];
|
|
38672
39434
|
if (!rels) return /* @__PURE__ */ new Map();
|
|
38673
39435
|
const relArr = rels["Relationship"];
|
|
@@ -39703,6 +40465,9 @@ function refToRowCol(ref) {
|
|
|
39703
40465
|
function rowColToRef(row, col) {
|
|
39704
40466
|
return colNumToLetters(col) + String(row);
|
|
39705
40467
|
}
|
|
40468
|
+
function escapeXml(s) {
|
|
40469
|
+
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
40470
|
+
}
|
|
39706
40471
|
var PACK_COL_BITS = 14;
|
|
39707
40472
|
var PACK_COL_MULT = 1 << PACK_COL_BITS;
|
|
39708
40473
|
function packRowCol(row, col) {
|
|
@@ -39874,8 +40639,8 @@ function parseHeaderFooterElement(worksheet) {
|
|
|
39874
40639
|
if (hf["@_differentFirst"] === "1") out.differentFirst = true;
|
|
39875
40640
|
return Object.keys(out).length > 0 ? out : void 0;
|
|
39876
40641
|
}
|
|
39877
|
-
function parseSheetRels(
|
|
39878
|
-
const doc = relsParser.parse(
|
|
40642
|
+
function parseSheetRels(relsXml2) {
|
|
40643
|
+
const doc = relsParser.parse(relsXml2);
|
|
39879
40644
|
const relationships = doc?.["Relationships"];
|
|
39880
40645
|
if (!relationships) return /* @__PURE__ */ new Map();
|
|
39881
40646
|
const relArr = relationships["Relationship"];
|
|
@@ -40179,8 +40944,8 @@ function parseImages(rels, zipEntries) {
|
|
|
40179
40944
|
}
|
|
40180
40945
|
return images;
|
|
40181
40946
|
}
|
|
40182
|
-
function parseDrawingRels(
|
|
40183
|
-
const doc = relsParser.parse(
|
|
40947
|
+
function parseDrawingRels(relsXml2) {
|
|
40948
|
+
const doc = relsParser.parse(relsXml2);
|
|
40184
40949
|
const relationships = doc?.["Relationships"];
|
|
40185
40950
|
if (!relationships) return /* @__PURE__ */ new Map();
|
|
40186
40951
|
const relArr = relationships["Relationship"];
|
|
@@ -41858,1505 +42623,1722 @@ function parsePrintTitlesRef(raw) {
|
|
|
41858
42623
|
return result.repeatRows || result.repeatCols ? result : void 0;
|
|
41859
42624
|
}
|
|
41860
42625
|
|
|
41861
|
-
// ../xlsx/src/
|
|
41862
|
-
|
|
41863
|
-
|
|
41864
|
-
|
|
41865
|
-
const
|
|
41866
|
-
const
|
|
41867
|
-
const
|
|
41868
|
-
|
|
41869
|
-
|
|
41870
|
-
|
|
41871
|
-
|
|
41872
|
-
|
|
41873
|
-
|
|
41874
|
-
|
|
41875
|
-
|
|
41876
|
-
|
|
41877
|
-
|
|
41878
|
-
const xml = decode(bytes);
|
|
41879
|
-
const re = /<Relationship\b([^/]*?)\/>/g;
|
|
41880
|
-
let m;
|
|
41881
|
-
while ((m = re.exec(xml)) !== null) {
|
|
41882
|
-
const attrs = m[1];
|
|
41883
|
-
const id = /\bId="([^"]+)"/.exec(attrs)?.[1];
|
|
41884
|
-
const type = /\bType="([^"]+)"/.exec(attrs)?.[1] ?? "";
|
|
41885
|
-
const target = /\bTarget="([^"]+)"/.exec(attrs)?.[1] ?? "";
|
|
41886
|
-
if (id) out.set(id, { type, target });
|
|
41887
|
-
}
|
|
41888
|
-
return out;
|
|
41889
|
-
}
|
|
41890
|
-
function readPivotCacheIdMap(originalZip) {
|
|
41891
|
-
const out = /* @__PURE__ */ new Map();
|
|
41892
|
-
const bytes = originalZip["xl/workbook.xml"];
|
|
41893
|
-
if (!bytes) return out;
|
|
41894
|
-
const xml = decode(bytes);
|
|
41895
|
-
const re = /<pivotCache\b([^/]*?)\/>/g;
|
|
41896
|
-
let m;
|
|
41897
|
-
while ((m = re.exec(xml)) !== null) {
|
|
41898
|
-
const attrs = m[1];
|
|
41899
|
-
const cacheIdMatch = /\bcacheId="(\d+)"/.exec(attrs);
|
|
41900
|
-
const ridMatch = /\br:id="([^"]+)"/.exec(attrs);
|
|
41901
|
-
if (cacheIdMatch && ridMatch) {
|
|
41902
|
-
out.set(parseInt(cacheIdMatch[1], 10), ridMatch[1]);
|
|
42626
|
+
// ../xlsx/src/pivot_recompute.ts
|
|
42627
|
+
var TOTAL_LABEL = "Grand Total";
|
|
42628
|
+
function recomputePivot(table, cache, source) {
|
|
42629
|
+
const records = filterByPageAxis(table, cache, source.records);
|
|
42630
|
+
const rowTuples = distinctTuples(records, table.rowFieldIndices);
|
|
42631
|
+
const colTuples = distinctTuples(records, table.colFieldIndices);
|
|
42632
|
+
const groupKey = (rec) => JSON.stringify([
|
|
42633
|
+
tupleOf(rec, table.rowFieldIndices),
|
|
42634
|
+
tupleOf(rec, table.colFieldIndices)
|
|
42635
|
+
]);
|
|
42636
|
+
const groups = /* @__PURE__ */ new Map();
|
|
42637
|
+
for (const rec of records) {
|
|
42638
|
+
const key = groupKey(rec);
|
|
42639
|
+
let bucket = groups.get(key);
|
|
42640
|
+
if (!bucket) {
|
|
42641
|
+
bucket = [];
|
|
42642
|
+
groups.set(key, bucket);
|
|
41903
42643
|
}
|
|
42644
|
+
bucket.push(rec);
|
|
41904
42645
|
}
|
|
41905
|
-
return
|
|
42646
|
+
return buildGrid(table, source, rowTuples, colTuples, groups, records);
|
|
41906
42647
|
}
|
|
41907
|
-
function
|
|
41908
|
-
const
|
|
41909
|
-
const
|
|
41910
|
-
|
|
41911
|
-
|
|
41912
|
-
|
|
41913
|
-
|
|
41914
|
-
|
|
41915
|
-
|
|
41916
|
-
while ((m = re.exec(xml)) !== null) {
|
|
41917
|
-
const attrs = m[1];
|
|
41918
|
-
const type = /\bType="([^"]+)"/.exec(attrs)?.[1] ?? "";
|
|
41919
|
-
if (!type.includes("/pivotTable")) continue;
|
|
41920
|
-
const target = /\bTarget="([^"]+)"/.exec(attrs)?.[1];
|
|
41921
|
-
if (target) out.push(target);
|
|
42648
|
+
function filterByPageAxis(table, cache, records) {
|
|
42649
|
+
const filters = [];
|
|
42650
|
+
for (const fi of table.pageFieldIndices) {
|
|
42651
|
+
const cfg = table.fields[fi];
|
|
42652
|
+
if (cfg?.selectedPageItem == null) continue;
|
|
42653
|
+
const cacheField = cache.fields[fi];
|
|
42654
|
+
if (!cacheField) continue;
|
|
42655
|
+
const allowed = cacheField.items[cfg.selectedPageItem];
|
|
42656
|
+
if (allowed) filters.push({ fieldIndex: fi, allowed });
|
|
41922
42657
|
}
|
|
41923
|
-
return
|
|
42658
|
+
if (filters.length === 0) return records;
|
|
42659
|
+
return records.filter(
|
|
42660
|
+
(rec) => filters.every(
|
|
42661
|
+
({ fieldIndex, allowed }) => cellMatchesItem(rec[fieldIndex], allowed)
|
|
42662
|
+
)
|
|
42663
|
+
);
|
|
41924
42664
|
}
|
|
41925
|
-
function
|
|
41926
|
-
|
|
41927
|
-
|
|
41928
|
-
|
|
41929
|
-
|
|
41930
|
-
|
|
41931
|
-
|
|
41932
|
-
|
|
41933
|
-
|
|
41934
|
-
|
|
41935
|
-
|
|
41936
|
-
|
|
41937
|
-
|
|
41938
|
-
|
|
41939
|
-
cachesByWorkbook.set(cacheId, rel.target);
|
|
41940
|
-
}
|
|
41941
|
-
const pivotTablesBySheetIndex = /* @__PURE__ */ new Map();
|
|
41942
|
-
for (let i2 = 0; i2 < sheetRIds.length; i2++) {
|
|
41943
|
-
const sheetTarget = wbRels.get(sheetRIds[i2])?.target;
|
|
41944
|
-
if (!sheetTarget) continue;
|
|
41945
|
-
const paths = readSheetPivotPaths(originalZip, sheetTarget);
|
|
41946
|
-
if (paths.length > 0) pivotTablesBySheetIndex.set(i2, paths);
|
|
41947
|
-
}
|
|
41948
|
-
const pivotXmlPaths = [];
|
|
41949
|
-
for (const path7 of Object.keys(originalZip)) {
|
|
41950
|
-
if (path7.startsWith("xl/pivotTables/") && path7.endsWith(".xml")) {
|
|
41951
|
-
pivotXmlPaths.push(path7);
|
|
41952
|
-
}
|
|
41953
|
-
if (path7.startsWith("xl/pivotCache/") && path7.endsWith(".xml")) {
|
|
41954
|
-
pivotXmlPaths.push(path7);
|
|
41955
|
-
}
|
|
42665
|
+
function cellMatchesItem(cell, item) {
|
|
42666
|
+
switch (item.kind) {
|
|
42667
|
+
case "string":
|
|
42668
|
+
return typeof cell === "string" && cell === item.value;
|
|
42669
|
+
case "number":
|
|
42670
|
+
return typeof cell === "number" && cell === item.value;
|
|
42671
|
+
case "boolean":
|
|
42672
|
+
return typeof cell === "boolean" && cell === item.value;
|
|
42673
|
+
case "date":
|
|
42674
|
+
return typeof cell === "string" && cell === item.value;
|
|
42675
|
+
case "missing":
|
|
42676
|
+
return cell === void 0 || cell === null || cell === "";
|
|
42677
|
+
case "error":
|
|
42678
|
+
return typeof cell === "string" && cell === item.value;
|
|
41956
42679
|
}
|
|
41957
|
-
return { cachesByWorkbook, pivotTablesBySheetIndex, pivotXmlPaths };
|
|
41958
42680
|
}
|
|
41959
|
-
function
|
|
41960
|
-
return
|
|
42681
|
+
function tupleOf(rec, indices) {
|
|
42682
|
+
return indices.map((i2) => rec[i2] ?? null);
|
|
41961
42683
|
}
|
|
41962
|
-
function
|
|
41963
|
-
|
|
41964
|
-
|
|
41965
|
-
|
|
41966
|
-
|
|
41967
|
-
|
|
42684
|
+
function distinctTuples(records, indices) {
|
|
42685
|
+
const seen = /* @__PURE__ */ new Set();
|
|
42686
|
+
const out = [];
|
|
42687
|
+
for (const rec of records) {
|
|
42688
|
+
const t = tupleOf(rec, indices);
|
|
42689
|
+
const key = JSON.stringify(t);
|
|
42690
|
+
if (seen.has(key)) continue;
|
|
42691
|
+
seen.add(key);
|
|
42692
|
+
out.push(t);
|
|
41968
42693
|
}
|
|
41969
|
-
|
|
41970
|
-
|
|
42694
|
+
out.sort((a, b) => {
|
|
42695
|
+
for (let i2 = 0; i2 < Math.max(a.length, b.length); i2++) {
|
|
42696
|
+
const av = a[i2];
|
|
42697
|
+
const bv = b[i2];
|
|
42698
|
+
if (av === bv) continue;
|
|
42699
|
+
const as = av === null || av === void 0 ? "" : String(av);
|
|
42700
|
+
const bs = bv === null || bv === void 0 ? "" : String(bv);
|
|
42701
|
+
if (as < bs) return -1;
|
|
42702
|
+
if (as > bs) return 1;
|
|
42703
|
+
}
|
|
42704
|
+
return 0;
|
|
42705
|
+
});
|
|
42706
|
+
return out;
|
|
42707
|
+
}
|
|
42708
|
+
function aggregate(values2, fn) {
|
|
42709
|
+
const numeric = values2.filter((v) => typeof v === "number");
|
|
42710
|
+
switch (fn) {
|
|
42711
|
+
case "count":
|
|
42712
|
+
return values2.filter((v) => v !== null && v !== void 0 && v !== "").length;
|
|
42713
|
+
case "countNums":
|
|
42714
|
+
return numeric.length;
|
|
42715
|
+
case "sum":
|
|
42716
|
+
return numeric.reduce((a, b) => a + b, 0);
|
|
42717
|
+
case "average":
|
|
42718
|
+
if (numeric.length === 0) return null;
|
|
42719
|
+
return numeric.reduce((a, b) => a + b, 0) / numeric.length;
|
|
42720
|
+
case "min":
|
|
42721
|
+
return numeric.length === 0 ? null : Math.min(...numeric);
|
|
42722
|
+
case "max":
|
|
42723
|
+
return numeric.length === 0 ? null : Math.max(...numeric);
|
|
42724
|
+
case "product":
|
|
42725
|
+
return numeric.length === 0 ? null : numeric.reduce((a, b) => a * b, 1);
|
|
41971
42726
|
}
|
|
41972
|
-
return void 0;
|
|
41973
42727
|
}
|
|
41974
|
-
function
|
|
41975
|
-
const
|
|
41976
|
-
const
|
|
41977
|
-
|
|
41978
|
-
|
|
41979
|
-
|
|
41980
|
-
|
|
41981
|
-
|
|
41982
|
-
|
|
41983
|
-
|
|
41984
|
-
|
|
41985
|
-
|
|
41986
|
-
|
|
41987
|
-
|
|
41988
|
-
|
|
41989
|
-
|
|
41990
|
-
|
|
41991
|
-
|
|
41992
|
-
|
|
41993
|
-
|
|
42728
|
+
function buildGrid(table, source, rowTuples, colTuples, groups, allRecords) {
|
|
42729
|
+
const numRowFields = table.rowFieldIndices.length;
|
|
42730
|
+
const numColFields = table.colFieldIndices.length;
|
|
42731
|
+
const numDataFields = Math.max(table.dataFields.length, 1);
|
|
42732
|
+
const showRowGrand = table.display.colGrandTotals;
|
|
42733
|
+
const showColGrand = table.display.rowGrandTotals;
|
|
42734
|
+
const rowLabelCols = Math.max(numRowFields, 1);
|
|
42735
|
+
const colHeaderRows = numColFields + (numDataFields > 0 ? 1 : 0);
|
|
42736
|
+
const headerRows = Math.max(colHeaderRows, 1);
|
|
42737
|
+
const dataCols = colTuples.length * numDataFields;
|
|
42738
|
+
const totalCols = rowLabelCols + dataCols + (showColGrand ? numDataFields : 0);
|
|
42739
|
+
const totalRows = headerRows + rowTuples.length + (showRowGrand ? 1 : 0);
|
|
42740
|
+
const cells = [];
|
|
42741
|
+
for (let r = 0; r < totalRows; r++) {
|
|
42742
|
+
cells.push(new Array(totalCols).fill({ kind: "blank" }));
|
|
42743
|
+
}
|
|
42744
|
+
for (let level = 0; level < numColFields; level++) {
|
|
42745
|
+
let col = rowLabelCols;
|
|
42746
|
+
for (const tuple of colTuples) {
|
|
42747
|
+
const text = formatCellLabel(tuple[level]);
|
|
42748
|
+
for (let i2 = 0; i2 < numDataFields; i2++) {
|
|
42749
|
+
cells[level][col + i2] = { kind: "colHeader", depth: level, text };
|
|
41994
42750
|
}
|
|
42751
|
+
col += numDataFields;
|
|
41995
42752
|
}
|
|
41996
|
-
for (const [path7, data] of Object.entries(originalZip)) {
|
|
41997
|
-
if (!regeneratedPaths.has(path7)) entries[path7] = data;
|
|
41998
|
-
}
|
|
41999
|
-
}
|
|
42000
|
-
const sharedStrings = buildSharedStrings(workbook);
|
|
42001
|
-
entries["xl/sharedStrings.xml"] = strToU8(sharedStrings.xml);
|
|
42002
|
-
const stylesResult = stylesPassthrough ? { xml: "", xfMap: /* @__PURE__ */ new Map(), numFmtMap: /* @__PURE__ */ new Map(), dxfMap: /* @__PURE__ */ new Map() } : buildStylesXml(workbook);
|
|
42003
|
-
if (!stylesPassthrough) entries["xl/styles.xml"] = strToU8(stylesResult.xml);
|
|
42004
|
-
const pivotInfo = extractPivotRoundTripInfo(originalZip);
|
|
42005
|
-
entries["xl/workbook.xml"] = strToU8(buildWorkbookXml(workbook, pivotInfo));
|
|
42006
|
-
entries["xl/_rels/workbook.xml.rels"] = strToU8(
|
|
42007
|
-
buildWorkbookRels(workbook, pivotInfo)
|
|
42008
|
-
);
|
|
42009
|
-
const extraContentTypes = [];
|
|
42010
|
-
for (const path7 of pivotInfo.pivotXmlPaths) {
|
|
42011
|
-
const ct = pivotContentTypeFor(path7);
|
|
42012
|
-
if (ct) extraContentTypes.push(ct);
|
|
42013
42753
|
}
|
|
42014
|
-
|
|
42015
|
-
|
|
42016
|
-
|
|
42017
|
-
|
|
42018
|
-
|
|
42019
|
-
|
|
42020
|
-
|
|
42021
|
-
|
|
42022
|
-
|
|
42023
|
-
const hasDrawings = sheet.drawings.length > 0;
|
|
42024
|
-
const hasTables = sheet.tables.length > 0;
|
|
42025
|
-
const hasHyperlinks = sheet.hyperlinks.size > 0;
|
|
42026
|
-
const needsDrawing = hasCharts || hasImages || hasDrawings;
|
|
42027
|
-
const hyperlinkRIds = /* @__PURE__ */ new Map();
|
|
42028
|
-
if (hasHyperlinks) {
|
|
42029
|
-
for (const [ref, url] of sheet.hyperlinks) {
|
|
42030
|
-
const rId = `rId${nextRId++}`;
|
|
42031
|
-
hyperlinkRIds.set(ref, rId);
|
|
42032
|
-
sheetRels.push(`<Relationship Id="${rId}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink" Target="${escapeXml(url)}" TargetMode="External"/>`);
|
|
42754
|
+
if (numDataFields > 0) {
|
|
42755
|
+
const labelRow = colHeaderRows - 1;
|
|
42756
|
+
let col = rowLabelCols;
|
|
42757
|
+
for (let _t = 0; _t < colTuples.length; _t++) {
|
|
42758
|
+
for (let d = 0; d < table.dataFields.length; d++) {
|
|
42759
|
+
cells[labelRow][col + d] = {
|
|
42760
|
+
kind: "valueLabel",
|
|
42761
|
+
text: table.dataFields[d].name
|
|
42762
|
+
};
|
|
42033
42763
|
}
|
|
42764
|
+
col += numDataFields;
|
|
42034
42765
|
}
|
|
42035
|
-
|
|
42036
|
-
|
|
42037
|
-
|
|
42038
|
-
|
|
42039
|
-
|
|
42040
|
-
|
|
42041
|
-
const drawingAnchors = [];
|
|
42042
|
-
for (const chart of sheet.charts) {
|
|
42043
|
-
const chartRId = `rId${drawingRelId++}`;
|
|
42044
|
-
const chartPath = `xl/charts/chart${globalChartIndex}.xml`;
|
|
42045
|
-
entries[chartPath] = strToU8(buildChartXml(chart));
|
|
42046
|
-
extraContentTypes.push(`<Override PartName="/${chartPath}" ContentType="application/vnd.openxmlformats-officedocument.drawingml.chart+xml"/>`);
|
|
42047
|
-
drawingRels.push(`<Relationship Id="${chartRId}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart" Target="../charts/chart${globalChartIndex}.xml"/>`);
|
|
42048
|
-
drawingAnchors.push(buildChartAnchorXml(chart, chartRId));
|
|
42049
|
-
globalChartIndex++;
|
|
42050
|
-
}
|
|
42051
|
-
for (const image of sheet.images) {
|
|
42052
|
-
const imgRId = `rId${drawingRelId++}`;
|
|
42053
|
-
const ext = getImageExtension(image.dataUrl);
|
|
42054
|
-
const imgPath = `xl/media/image${globalImageIndex}.${ext}`;
|
|
42055
|
-
const imgBytes = dataUrlToBytes(image.dataUrl);
|
|
42056
|
-
if (imgBytes) {
|
|
42057
|
-
entries[imgPath] = imgBytes;
|
|
42058
|
-
drawingRels.push(`<Relationship Id="${imgRId}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/image" Target="../media/image${globalImageIndex}.${ext}"/>`);
|
|
42059
|
-
drawingAnchors.push(buildImageAnchorXml(image, imgRId));
|
|
42060
|
-
globalImageIndex++;
|
|
42061
|
-
}
|
|
42062
|
-
}
|
|
42063
|
-
for (const drawing of sheet.drawings) {
|
|
42064
|
-
drawingAnchors.push(buildShapeAnchorXml(drawing));
|
|
42065
|
-
}
|
|
42066
|
-
entries[`xl/drawings/drawing${i2 + 1}.xml`] = strToU8(
|
|
42067
|
-
`<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
42068
|
-
<xdr:wsDr xmlns:xdr="http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing" xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:c="http://schemas.openxmlformats.org/drawingml/2006/chart">
|
|
42069
|
-
` + drawingAnchors.join("\n") + `
|
|
42070
|
-
</xdr:wsDr>`
|
|
42071
|
-
);
|
|
42072
|
-
extraContentTypes.push(`<Override PartName="/xl/drawings/drawing${i2 + 1}.xml" ContentType="application/vnd.openxmlformats-officedocument.drawing+xml"/>`);
|
|
42073
|
-
if (drawingRels.length > 0) {
|
|
42074
|
-
entries[`xl/drawings/_rels/drawing${i2 + 1}.xml.rels`] = strToU8(
|
|
42075
|
-
`<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
42076
|
-
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
|
|
42077
|
-
${drawingRels.join("\n")}
|
|
42078
|
-
</Relationships>`
|
|
42079
|
-
);
|
|
42766
|
+
if (showColGrand) {
|
|
42767
|
+
for (let d = 0; d < table.dataFields.length; d++) {
|
|
42768
|
+
cells[labelRow][rowLabelCols + dataCols + d] = {
|
|
42769
|
+
kind: "valueLabel",
|
|
42770
|
+
text: table.dataFields[d].name
|
|
42771
|
+
};
|
|
42080
42772
|
}
|
|
42081
42773
|
}
|
|
42082
|
-
|
|
42083
|
-
|
|
42084
|
-
|
|
42085
|
-
|
|
42086
|
-
|
|
42087
|
-
|
|
42088
|
-
|
|
42089
|
-
|
|
42090
|
-
|
|
42091
|
-
|
|
42092
|
-
}
|
|
42774
|
+
}
|
|
42775
|
+
for (let r = 0; r < rowTuples.length; r++) {
|
|
42776
|
+
const rowTuple = rowTuples[r];
|
|
42777
|
+
const gridRow = headerRows + r;
|
|
42778
|
+
for (let level = 0; level < numRowFields; level++) {
|
|
42779
|
+
cells[gridRow][level] = {
|
|
42780
|
+
kind: "rowHeader",
|
|
42781
|
+
depth: level,
|
|
42782
|
+
text: formatCellLabel(rowTuple[level])
|
|
42783
|
+
};
|
|
42093
42784
|
}
|
|
42094
|
-
|
|
42095
|
-
|
|
42096
|
-
|
|
42097
|
-
|
|
42098
|
-
|
|
42099
|
-
|
|
42100
|
-
|
|
42785
|
+
for (let c = 0; c < colTuples.length; c++) {
|
|
42786
|
+
const colTuple = colTuples[c];
|
|
42787
|
+
const groupRecords = groups.get(JSON.stringify([rowTuple, colTuple])) ?? [];
|
|
42788
|
+
for (let d = 0; d < table.dataFields.length; d++) {
|
|
42789
|
+
const df = table.dataFields[d];
|
|
42790
|
+
const values2 = groupRecords.map((rec) => rec[df.fieldIndex]);
|
|
42791
|
+
cells[gridRow][rowLabelCols + c * numDataFields + d] = {
|
|
42792
|
+
kind: "value",
|
|
42793
|
+
value: aggregate(values2, df.subtotal),
|
|
42794
|
+
numFmt: df.numFmt
|
|
42795
|
+
};
|
|
42101
42796
|
}
|
|
42102
42797
|
}
|
|
42103
|
-
if (
|
|
42104
|
-
|
|
42105
|
-
|
|
42106
|
-
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
|
|
42107
|
-
${sheetRels.join("\n")}
|
|
42108
|
-
</Relationships>`
|
|
42798
|
+
if (showColGrand) {
|
|
42799
|
+
const rowOnly = allRecords.filter(
|
|
42800
|
+
(rec) => sameTuple(tupleOf(rec, table.rowFieldIndices), rowTuple)
|
|
42109
42801
|
);
|
|
42802
|
+
for (let d = 0; d < table.dataFields.length; d++) {
|
|
42803
|
+
const df = table.dataFields[d];
|
|
42804
|
+
cells[gridRow][rowLabelCols + dataCols + d] = {
|
|
42805
|
+
kind: "rowTotal",
|
|
42806
|
+
value: aggregate(
|
|
42807
|
+
rowOnly.map((rec) => rec[df.fieldIndex]),
|
|
42808
|
+
df.subtotal
|
|
42809
|
+
)
|
|
42810
|
+
};
|
|
42811
|
+
}
|
|
42110
42812
|
}
|
|
42111
|
-
entries[`xl/worksheets/sheet${i2 + 1}.xml`] = strToU8(
|
|
42112
|
-
buildSheetXml(sheet, workbook.styles, sharedStrings.index, i2 === workbook.activeSheetIndex, stylesResult.xfMap, stylesResult.numFmtMap, stylesResult.dxfMap, drawingRId, tableRIds, hyperlinkRIds)
|
|
42113
|
-
);
|
|
42114
42813
|
}
|
|
42115
|
-
|
|
42116
|
-
|
|
42117
|
-
|
|
42118
|
-
|
|
42119
|
-
|
|
42120
|
-
|
|
42121
|
-
|
|
42122
|
-
|
|
42123
|
-
|
|
42124
|
-
|
|
42125
|
-
|
|
42126
|
-
|
|
42127
|
-
|
|
42128
|
-
|
|
42129
|
-
|
|
42130
|
-
|
|
42131
|
-
|
|
42132
|
-
if (!index.has(cell.value)) {
|
|
42133
|
-
index.set(cell.value, strings.length);
|
|
42134
|
-
strings.push(cell.value);
|
|
42135
|
-
if (cell.richText && cell.richText.length > 0) {
|
|
42136
|
-
richTextMap.set(cell.value, cell.richText);
|
|
42137
|
-
}
|
|
42138
|
-
}
|
|
42814
|
+
if (showRowGrand) {
|
|
42815
|
+
const gridRow = headerRows + rowTuples.length;
|
|
42816
|
+
cells[gridRow][0] = { kind: "totalLabel", text: TOTAL_LABEL };
|
|
42817
|
+
for (let c = 0; c < colTuples.length; c++) {
|
|
42818
|
+
const colTuple = colTuples[c];
|
|
42819
|
+
const colOnly = allRecords.filter(
|
|
42820
|
+
(rec) => sameTuple(tupleOf(rec, table.colFieldIndices), colTuple)
|
|
42821
|
+
);
|
|
42822
|
+
for (let d = 0; d < table.dataFields.length; d++) {
|
|
42823
|
+
const df = table.dataFields[d];
|
|
42824
|
+
cells[gridRow][rowLabelCols + c * numDataFields + d] = {
|
|
42825
|
+
kind: "colTotal",
|
|
42826
|
+
value: aggregate(
|
|
42827
|
+
colOnly.map((rec) => rec[df.fieldIndex]),
|
|
42828
|
+
df.subtotal
|
|
42829
|
+
)
|
|
42830
|
+
};
|
|
42139
42831
|
}
|
|
42140
42832
|
}
|
|
42141
|
-
|
|
42142
|
-
|
|
42143
|
-
|
|
42144
|
-
|
|
42145
|
-
|
|
42833
|
+
if (showColGrand) {
|
|
42834
|
+
for (let d = 0; d < table.dataFields.length; d++) {
|
|
42835
|
+
const df = table.dataFields[d];
|
|
42836
|
+
cells[gridRow][rowLabelCols + dataCols + d] = {
|
|
42837
|
+
kind: "grandTotal",
|
|
42838
|
+
value: aggregate(
|
|
42839
|
+
allRecords.map((rec) => rec[df.fieldIndex]),
|
|
42840
|
+
df.subtotal
|
|
42841
|
+
)
|
|
42842
|
+
};
|
|
42843
|
+
}
|
|
42146
42844
|
}
|
|
42147
|
-
|
|
42148
|
-
|
|
42149
|
-
|
|
42150
|
-
|
|
42151
|
-
|
|
42152
|
-
|
|
42153
|
-
|
|
42154
|
-
|
|
42155
|
-
|
|
42845
|
+
}
|
|
42846
|
+
void source;
|
|
42847
|
+
return {
|
|
42848
|
+
cells,
|
|
42849
|
+
headerRows,
|
|
42850
|
+
rowLabelCols,
|
|
42851
|
+
rows: totalRows,
|
|
42852
|
+
cols: totalCols
|
|
42853
|
+
};
|
|
42156
42854
|
}
|
|
42157
|
-
function
|
|
42158
|
-
|
|
42159
|
-
|
|
42160
|
-
|
|
42161
|
-
|
|
42855
|
+
function sameTuple(a, b) {
|
|
42856
|
+
if (a.length !== b.length) return false;
|
|
42857
|
+
for (let i2 = 0; i2 < a.length; i2++) {
|
|
42858
|
+
if (a[i2] !== b[i2]) {
|
|
42859
|
+
const an = a[i2] === void 0 || a[i2] === null || a[i2] === "";
|
|
42860
|
+
const bn = b[i2] === void 0 || b[i2] === null || b[i2] === "";
|
|
42861
|
+
if (!(an && bn)) return false;
|
|
42862
|
+
}
|
|
42162
42863
|
}
|
|
42163
|
-
return
|
|
42864
|
+
return true;
|
|
42164
42865
|
}
|
|
42165
|
-
function
|
|
42166
|
-
|
|
42167
|
-
if (
|
|
42168
|
-
|
|
42169
|
-
if (font.strike) parts += "<strike/>";
|
|
42170
|
-
if (font.underline) parts += `<u val="${font.underline}"/>`;
|
|
42171
|
-
if (font.vertAlign) parts += `<vertAlign val="${font.vertAlign}"/>`;
|
|
42172
|
-
if (font.size) parts += `<sz val="${font.size}"/>`;
|
|
42173
|
-
if (font.color) parts += `<color rgb="${hexToArgb(font.color)}"/>`;
|
|
42174
|
-
if (font.name) parts += `<rFont val="${escapeXml(font.name)}"/>`;
|
|
42175
|
-
return `<rPr>${parts}</rPr>`;
|
|
42866
|
+
function formatCellLabel(v) {
|
|
42867
|
+
if (v === void 0 || v === null || v === "") return "(blank)";
|
|
42868
|
+
if (typeof v === "boolean") return v ? "TRUE" : "FALSE";
|
|
42869
|
+
return String(v);
|
|
42176
42870
|
}
|
|
42177
|
-
|
|
42178
|
-
|
|
42179
|
-
|
|
42180
|
-
|
|
42181
|
-
|
|
42182
|
-
|
|
42183
|
-
|
|
42184
|
-
for (const sheet of workbook.sheets) {
|
|
42185
|
-
for (const cell of sheet.cells.values()) {
|
|
42186
|
-
if (cell.numFmtCode && cell.numFmtCode !== "General" && cell.numFmtCode !== "") {
|
|
42187
|
-
if (!numFmtMap.has(cell.numFmtCode)) {
|
|
42188
|
-
numFmtMap.set(cell.numFmtCode, nextNumFmtId++);
|
|
42189
|
-
}
|
|
42190
|
-
}
|
|
42191
|
-
}
|
|
42871
|
+
|
|
42872
|
+
// ../xlsx/src/pivot_model.ts
|
|
42873
|
+
var PivotTableModel = class {
|
|
42874
|
+
constructor(config, cache, authored = false) {
|
|
42875
|
+
this.config = config;
|
|
42876
|
+
this.cache = cache;
|
|
42877
|
+
this.authored = authored;
|
|
42192
42878
|
}
|
|
42193
|
-
|
|
42194
|
-
|
|
42195
|
-
|
|
42196
|
-
|
|
42197
|
-
|
|
42198
|
-
|
|
42199
|
-
|
|
42879
|
+
/**
|
|
42880
|
+
* Recompute the pivot result from the workbook's current source data.
|
|
42881
|
+
* Callers are responsible for triggering recomputation; the model does
|
|
42882
|
+
* not subscribe to workbook changes itself.
|
|
42883
|
+
*/
|
|
42884
|
+
recompute(workbook) {
|
|
42885
|
+
const source = readSourceData(workbook, this.cache);
|
|
42886
|
+
if (!source) {
|
|
42887
|
+
this.result = void 0;
|
|
42888
|
+
return;
|
|
42200
42889
|
}
|
|
42890
|
+
this.result = recomputePivot(this.config, this.cache, source);
|
|
42201
42891
|
}
|
|
42202
|
-
|
|
42203
|
-
|
|
42204
|
-
|
|
42205
|
-
|
|
42206
|
-
|
|
42207
|
-
|
|
42208
|
-
|
|
42209
|
-
|
|
42210
|
-
|
|
42211
|
-
|
|
42212
|
-
|
|
42213
|
-
|
|
42214
|
-
const fillMap = /* @__PURE__ */ new Map();
|
|
42215
|
-
fillEntries.push('<fill><patternFill patternType="none"/></fill>');
|
|
42216
|
-
fillEntries.push('<fill><patternFill patternType="gray125"/></fill>');
|
|
42217
|
-
fillMap.set("", 0);
|
|
42218
|
-
for (const s of styles) {
|
|
42219
|
-
const fk = fillKey(s);
|
|
42220
|
-
if (fk === "" || fillMap.has(fk)) continue;
|
|
42221
|
-
fillMap.set(fk, fillEntries.length);
|
|
42222
|
-
fillEntries.push(buildFillXml(s));
|
|
42223
|
-
}
|
|
42224
|
-
const borderEntries = [];
|
|
42225
|
-
const borderMap = /* @__PURE__ */ new Map();
|
|
42226
|
-
borderEntries.push("<border><left/><right/><top/><bottom/><diagonal/></border>");
|
|
42227
|
-
borderMap.set("", 0);
|
|
42228
|
-
for (const s of styles) {
|
|
42229
|
-
const bk = borderKey(s);
|
|
42230
|
-
if (bk === "" || borderMap.has(bk)) continue;
|
|
42231
|
-
borderMap.set(bk, borderEntries.length);
|
|
42232
|
-
borderEntries.push(buildBorderXml(s));
|
|
42892
|
+
};
|
|
42893
|
+
function readSourceData(workbook, cache) {
|
|
42894
|
+
if (cache.source.type !== "worksheet") return void 0;
|
|
42895
|
+
const source = cache.source;
|
|
42896
|
+
const sheet = workbook.sheets.find((s) => s.name === source.sheetName);
|
|
42897
|
+
if (!sheet) return void 0;
|
|
42898
|
+
const range = parseRange(source.ref);
|
|
42899
|
+
if (!range) return void 0;
|
|
42900
|
+
const header = [];
|
|
42901
|
+
for (let col = range.startCol; col <= range.endCol; col++) {
|
|
42902
|
+
const cell = sheet.getCell(rowColToRef(range.startRow, col));
|
|
42903
|
+
header.push(formatHeader(cell?.value));
|
|
42233
42904
|
}
|
|
42234
|
-
const
|
|
42235
|
-
|
|
42236
|
-
|
|
42237
|
-
|
|
42238
|
-
|
|
42239
|
-
|
|
42240
|
-
|
|
42241
|
-
|
|
42242
|
-
</numFmts>
|
|
42243
|
-
`;
|
|
42905
|
+
const records = [];
|
|
42906
|
+
for (let row = range.startRow + 1; row <= range.endRow; row++) {
|
|
42907
|
+
const rec = [];
|
|
42908
|
+
for (let col = range.startCol; col <= range.endCol; col++) {
|
|
42909
|
+
const cell = sheet.getCell(rowColToRef(row, col));
|
|
42910
|
+
rec.push(coerceValue(cell?.value));
|
|
42911
|
+
}
|
|
42912
|
+
records.push(rec);
|
|
42244
42913
|
}
|
|
42245
|
-
|
|
42246
|
-
|
|
42247
|
-
|
|
42248
|
-
|
|
42249
|
-
|
|
42250
|
-
|
|
42251
|
-
|
|
42252
|
-
|
|
42253
|
-
|
|
42254
|
-
|
|
42914
|
+
return { header, records };
|
|
42915
|
+
}
|
|
42916
|
+
function formatHeader(v) {
|
|
42917
|
+
if (v === void 0 || v === null) return "";
|
|
42918
|
+
return String(v);
|
|
42919
|
+
}
|
|
42920
|
+
function coerceValue(v) {
|
|
42921
|
+
if (v === void 0 || v === null) return void 0;
|
|
42922
|
+
if (typeof v === "string" || typeof v === "number" || typeof v === "boolean") {
|
|
42923
|
+
return v;
|
|
42255
42924
|
}
|
|
42256
|
-
|
|
42257
|
-
|
|
42258
|
-
|
|
42259
|
-
|
|
42260
|
-
|
|
42261
|
-
|
|
42262
|
-
|
|
42263
|
-
|
|
42264
|
-
|
|
42265
|
-
|
|
42266
|
-
|
|
42267
|
-
|
|
42925
|
+
return String(v);
|
|
42926
|
+
}
|
|
42927
|
+
function parseRange(ref) {
|
|
42928
|
+
const range = ref.includes("!") ? ref.split("!")[1] : ref;
|
|
42929
|
+
const cleaned = range.replace(/\$/g, "");
|
|
42930
|
+
const m = cleaned.match(/^([A-Z]+\d+)(?::([A-Z]+\d+))?$/);
|
|
42931
|
+
if (!m) return void 0;
|
|
42932
|
+
const start = refToRowCol(m[1]);
|
|
42933
|
+
if (!start) return void 0;
|
|
42934
|
+
const endRef = m[2] ?? m[1];
|
|
42935
|
+
const end = refToRowCol(endRef);
|
|
42936
|
+
if (!end) return void 0;
|
|
42937
|
+
return {
|
|
42938
|
+
startRow: start.row,
|
|
42939
|
+
startCol: start.col,
|
|
42940
|
+
endRow: end.row,
|
|
42941
|
+
endCol: end.col
|
|
42942
|
+
};
|
|
42943
|
+
}
|
|
42944
|
+
|
|
42945
|
+
// ../xlsx/src/pivot_writer.ts
|
|
42946
|
+
var MAIN_NS = "http://schemas.openxmlformats.org/spreadsheetml/2006/main";
|
|
42947
|
+
var REL_NS = "http://schemas.openxmlformats.org/officeDocument/2006/relationships";
|
|
42948
|
+
function sourceValueToItem(v) {
|
|
42949
|
+
if (v === void 0 || v === null || v === "") return { kind: "missing" };
|
|
42950
|
+
if (typeof v === "number") return { kind: "number", value: v };
|
|
42951
|
+
if (typeof v === "boolean") return { kind: "boolean", value: v };
|
|
42952
|
+
return { kind: "string", value: v };
|
|
42953
|
+
}
|
|
42954
|
+
function cacheItemKey(item) {
|
|
42955
|
+
switch (item.kind) {
|
|
42956
|
+
case "missing":
|
|
42957
|
+
return "m:";
|
|
42958
|
+
case "number":
|
|
42959
|
+
return `n:${item.value}`;
|
|
42960
|
+
case "boolean":
|
|
42961
|
+
return `b:${item.value}`;
|
|
42962
|
+
case "string":
|
|
42963
|
+
return `s:${item.value}`;
|
|
42964
|
+
case "date":
|
|
42965
|
+
return `d:${item.value}`;
|
|
42966
|
+
case "error":
|
|
42967
|
+
return `e:${item.value}`;
|
|
42268
42968
|
}
|
|
42269
|
-
|
|
42270
|
-
|
|
42271
|
-
|
|
42272
|
-
|
|
42273
|
-
|
|
42274
|
-
|
|
42275
|
-
|
|
42276
|
-
|
|
42277
|
-
|
|
42278
|
-
|
|
42279
|
-
|
|
42969
|
+
}
|
|
42970
|
+
function enumerateFlags(table, fieldCount) {
|
|
42971
|
+
const axis = /* @__PURE__ */ new Set([...table.rowFieldIndices, ...table.colFieldIndices, ...table.pageFieldIndices]);
|
|
42972
|
+
return Array.from({ length: fieldCount }, (_, i2) => axis.has(i2));
|
|
42973
|
+
}
|
|
42974
|
+
function buildPivotCacheRecordsXml(records, cache, enumerate) {
|
|
42975
|
+
const indexMaps = cache.fields.map((f, i2) => {
|
|
42976
|
+
if (!enumerate[i2]) return void 0;
|
|
42977
|
+
const m = /* @__PURE__ */ new Map();
|
|
42978
|
+
f.items.forEach((item, idx) => m.set(cacheItemKey(item), idx));
|
|
42979
|
+
return m;
|
|
42980
|
+
});
|
|
42981
|
+
const rows = records.map((rec) => {
|
|
42982
|
+
const cells = cache.fields.map((_f, i2) => {
|
|
42983
|
+
const item = sourceValueToItem(rec[i2]);
|
|
42984
|
+
const map2 = indexMaps[i2];
|
|
42985
|
+
if (map2) {
|
|
42986
|
+
const idx = map2.get(cacheItemKey(item));
|
|
42987
|
+
if (idx === void 0) {
|
|
42988
|
+
throw new Error(
|
|
42989
|
+
`buildPivotCacheRecordsXml: value ${JSON.stringify(rec[i2])} for field "${cache.fields[i2].name}" is missing from its cached shared items`
|
|
42990
|
+
);
|
|
42280
42991
|
}
|
|
42992
|
+
return `<x v="${idx}"/>`;
|
|
42281
42993
|
}
|
|
42282
|
-
|
|
42283
|
-
|
|
42284
|
-
|
|
42285
|
-
|
|
42286
|
-
|
|
42287
|
-
${
|
|
42288
|
-
|
|
42994
|
+
return inlineRecordCell(item);
|
|
42995
|
+
});
|
|
42996
|
+
return `<r>${cells.join("")}</r>`;
|
|
42997
|
+
});
|
|
42998
|
+
return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
42999
|
+
<pivotCacheRecords xmlns="${MAIN_NS}" xmlns:r="${REL_NS}" count="${records.length}">` + rows.join("") + `</pivotCacheRecords>`;
|
|
43000
|
+
}
|
|
43001
|
+
function inlineRecordCell(item) {
|
|
43002
|
+
switch (item.kind) {
|
|
43003
|
+
case "missing":
|
|
43004
|
+
return "<m/>";
|
|
43005
|
+
case "number":
|
|
43006
|
+
return `<n v="${item.value}"/>`;
|
|
43007
|
+
case "boolean":
|
|
43008
|
+
return `<b v="${item.value ? 1 : 0}"/>`;
|
|
43009
|
+
case "date":
|
|
43010
|
+
return `<d v="${escapeXml(item.value)}"/>`;
|
|
43011
|
+
case "error":
|
|
43012
|
+
return `<e v="${escapeXml(item.value)}"/>`;
|
|
43013
|
+
case "string":
|
|
43014
|
+
return `<s v="${escapeXml(item.value)}"/>`;
|
|
42289
43015
|
}
|
|
42290
|
-
const xml = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
42291
|
-
<styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
|
|
42292
|
-
${numFmtsXml}<fonts count="${fontList.length}">
|
|
42293
|
-
${fontsXml}
|
|
42294
|
-
</fonts>
|
|
42295
|
-
<fills count="${fillEntries.length}">
|
|
42296
|
-
${fillsXml}
|
|
42297
|
-
</fills>
|
|
42298
|
-
<borders count="${borderEntries.length}">
|
|
42299
|
-
${bordersXml}
|
|
42300
|
-
</borders>
|
|
42301
|
-
<cellStyleXfs count="1">
|
|
42302
|
-
<xf numFmtId="0" fontId="0" fillId="0" borderId="0"/>
|
|
42303
|
-
</cellStyleXfs>
|
|
42304
|
-
<cellXfs count="${xfEntries.length}">
|
|
42305
|
-
${xfEntries.join("\n")}
|
|
42306
|
-
</cellXfs>
|
|
42307
|
-
<cellStyles count="1">
|
|
42308
|
-
<cellStyle name="Normal" xfId="0" builtinId="0"/>
|
|
42309
|
-
</cellStyles>
|
|
42310
|
-
${dxfsXml}
|
|
42311
|
-
</styleSheet>`;
|
|
42312
|
-
return { xml, xfMap, numFmtMap, dxfMap };
|
|
42313
43016
|
}
|
|
42314
|
-
function
|
|
42315
|
-
|
|
42316
|
-
|
|
42317
|
-
|
|
42318
|
-
|
|
42319
|
-
|
|
42320
|
-
|
|
42321
|
-
|
|
42322
|
-
|
|
42323
|
-
|
|
42324
|
-
|
|
42325
|
-
|
|
42326
|
-
const
|
|
42327
|
-
return `<
|
|
43017
|
+
function buildPivotCacheDefinitionXml(cache, enumerate, recordCount, recordsRelId) {
|
|
43018
|
+
if (cache.source.type !== "worksheet") {
|
|
43019
|
+
throw new Error("buildPivotCacheDefinitionXml: only worksheet sources are supported");
|
|
43020
|
+
}
|
|
43021
|
+
const src = cache.source;
|
|
43022
|
+
const fields = cache.fields.map((f, i2) => cacheFieldXml(f, enumerate[i2])).join("");
|
|
43023
|
+
return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
43024
|
+
<pivotCacheDefinition xmlns="${MAIN_NS}" xmlns:r="${REL_NS}" r:id="${recordsRelId}" refreshOnLoad="1" refreshedBy="Lotics" createdVersion="6" refreshedVersion="6" minRefreshableVersion="3" recordCount="${recordCount}"><cacheSource type="worksheet"><worksheetSource ref="${escapeXml(src.ref)}" sheet="${escapeXml(src.sheetName)}"/></cacheSource><cacheFields count="${cache.fields.length}">${fields}</cacheFields></pivotCacheDefinition>`;
|
|
43025
|
+
}
|
|
43026
|
+
function cacheFieldXml(field, enumerate) {
|
|
43027
|
+
const name = `name="${escapeXml(field.name)}" numFmtId="0"`;
|
|
43028
|
+
if (!enumerate) {
|
|
43029
|
+
const flags = `containsBlank="${field.items.length === 0 ? 0 : 1}"` + (field.containsNumber ? ` containsString="0" containsNumber="1"` : "");
|
|
43030
|
+
return `<cacheField ${name}><sharedItems ${flags}/></cacheField>`;
|
|
43031
|
+
}
|
|
43032
|
+
const items = field.items.map(sharedItemXml).join("");
|
|
43033
|
+
const hasString = field.items.some((i2) => i2.kind === "string");
|
|
43034
|
+
const hasNumber = field.items.some((i2) => i2.kind === "number");
|
|
43035
|
+
const hasBlank = field.items.some((i2) => i2.kind === "missing");
|
|
43036
|
+
const attrs = `count="${field.items.length}"` + (hasBlank ? ` containsBlank="1"` : "") + (hasNumber && !hasString ? ` containsString="0" containsNumber="1"` : "");
|
|
43037
|
+
return `<cacheField ${name}><sharedItems ${attrs}>${items}</sharedItems></cacheField>`;
|
|
43038
|
+
}
|
|
43039
|
+
function sharedItemXml(item) {
|
|
43040
|
+
switch (item.kind) {
|
|
43041
|
+
case "missing":
|
|
43042
|
+
return `<m/>`;
|
|
43043
|
+
case "number":
|
|
43044
|
+
return `<n v="${item.value}"/>`;
|
|
43045
|
+
case "boolean":
|
|
43046
|
+
return `<b v="${item.value ? 1 : 0}"/>`;
|
|
43047
|
+
case "date":
|
|
43048
|
+
return `<d v="${escapeXml(item.value)}"/>`;
|
|
43049
|
+
case "error":
|
|
43050
|
+
return `<e v="${escapeXml(item.value)}"/>`;
|
|
43051
|
+
case "string":
|
|
43052
|
+
return `<s v="${escapeXml(item.value)}"/>`;
|
|
42328
43053
|
}
|
|
42329
|
-
return `<xf ${attrs}/>`;
|
|
42330
43054
|
}
|
|
42331
|
-
|
|
42332
|
-
|
|
43055
|
+
var SUBTOTAL_FN_TO_ENUM = {
|
|
43056
|
+
sum: "sum",
|
|
43057
|
+
count: "count",
|
|
43058
|
+
countNums: "countNums",
|
|
43059
|
+
average: "average",
|
|
43060
|
+
min: "min",
|
|
43061
|
+
max: "max",
|
|
43062
|
+
product: "product"
|
|
43063
|
+
};
|
|
43064
|
+
function buildPivotTableXml(table, cache) {
|
|
43065
|
+
const rowField = table.rowFieldIndices[0];
|
|
43066
|
+
const colField = table.colFieldIndices[0];
|
|
43067
|
+
if (rowField === void 0 || colField === void 0) {
|
|
43068
|
+
throw new Error("buildPivotTableXml: a row field and a column field are required");
|
|
43069
|
+
}
|
|
43070
|
+
const pageSet = new Set(table.pageFieldIndices);
|
|
43071
|
+
const pivotFields = cache.fields.map((f, i2) => {
|
|
43072
|
+
const onAxis = i2 === rowField ? "axisRow" : i2 === colField ? "axisCol" : pageSet.has(i2) ? "axisPage" : void 0;
|
|
43073
|
+
if (onAxis) return axisPivotFieldXml(onAxis, f.items.length);
|
|
43074
|
+
if (table.dataFields.some((d) => d.fieldIndex === i2)) {
|
|
43075
|
+
return `<pivotField dataField="1" showAll="0"/>`;
|
|
43076
|
+
}
|
|
43077
|
+
return `<pivotField showAll="0"/>`;
|
|
43078
|
+
}).join("");
|
|
43079
|
+
const rowCount = cache.fields[rowField].items.length;
|
|
43080
|
+
const colCount = cache.fields[colField].items.length;
|
|
43081
|
+
const rowItems = axisItemsXml("rowItems", rowCount, table.display.colGrandTotals);
|
|
43082
|
+
const colItems = axisItemsXml("colItems", colCount, table.display.rowGrandTotals);
|
|
43083
|
+
const pageFieldsXml = table.pageFieldIndices.length ? `<pageFields count="${table.pageFieldIndices.length}">` + table.pageFieldIndices.map((fld) => {
|
|
43084
|
+
const sel = table.fields[fld]?.selectedPageItem;
|
|
43085
|
+
const item = sel === null || sel === void 0 ? "" : ` item="${sel}"`;
|
|
43086
|
+
return `<pageField fld="${fld}"${item} hier="-1"/>`;
|
|
43087
|
+
}).join("") + `</pageFields>` : "";
|
|
43088
|
+
const dataFieldsXml = `<dataFields count="${table.dataFields.length}">` + table.dataFields.map((d) => {
|
|
43089
|
+
const fn = SUBTOTAL_FN_TO_ENUM[d.subtotal] ?? "sum";
|
|
43090
|
+
const sub = fn === "sum" ? "" : ` subtotal="${fn}"`;
|
|
43091
|
+
const numFmt = d.numFmt ? ` numFmtId="${escapeXml(d.numFmt)}"` : "";
|
|
43092
|
+
return `<dataField name="${escapeXml(d.name)}" fld="${d.fieldIndex}"${sub} baseField="0" baseItem="0"${numFmt}/>`;
|
|
43093
|
+
}).join("") + `</dataFields>`;
|
|
43094
|
+
const style = `<pivotTableStyleInfo name="${escapeXml(table.styleName ?? "PivotStyleLight16")}" showRowHeaders="1" showColHeaders="1" showRowStripes="${table.display.showRowStripes ? 1 : 0}" showColStripes="${table.display.showColStripes ? 1 : 0}" showLastColumn="1"/>`;
|
|
43095
|
+
return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
43096
|
+
<pivotTableDefinition xmlns="${MAIN_NS}" xmlns:r="${REL_NS}" name="${escapeXml(table.name)}" cacheId="${table.cacheId}" applyNumberFormats="0" applyBorderFormats="0" applyFontFormats="0" applyPatternFormats="0" applyAlignmentFormats="0" applyWidthHeightFormats="1" dataCaption="Values" updatedVersion="6" minRefreshableVersion="3" useAutoFormatting="1" itemPrintTitles="1" createdVersion="6" indent="0" outline="1" outlineData="1" multipleFieldFilters="0" rowGrandTotals="${table.display.rowGrandTotals ? 1 : 0}" colGrandTotals="${table.display.colGrandTotals ? 1 : 0}"><location ref="${escapeXml(table.ref)}" firstHeaderRow="${table.firstHeaderRow}" firstDataRow="${table.firstDataRow}" firstDataCol="${table.firstDataCol}"/><pivotFields count="${cache.fields.length}">${pivotFields}</pivotFields><rowFields count="1"><field x="${rowField}"/></rowFields>` + rowItems + `<colFields count="1"><field x="${colField}"/></colFields>` + colItems + pageFieldsXml + dataFieldsXml + style + `</pivotTableDefinition>`;
|
|
42333
43097
|
}
|
|
42334
|
-
function
|
|
42335
|
-
|
|
42336
|
-
|
|
42337
|
-
|
|
42338
|
-
|
|
42339
|
-
if (s.fontUnderline) parts += `<u val="${s.fontUnderline}"/>`;
|
|
42340
|
-
parts += `<sz val="${s.fontSize ?? 11}"/>`;
|
|
42341
|
-
if (s.fontColor) {
|
|
42342
|
-
parts += `<color rgb="${hexToArgb(s.fontColor)}"/>`;
|
|
42343
|
-
} else {
|
|
42344
|
-
parts += '<color theme="1"/>';
|
|
42345
|
-
}
|
|
42346
|
-
parts += `<name val="${escapeXml(s.fontName ?? "Calibri")}"/>`;
|
|
42347
|
-
return `<font>${parts}</font>`;
|
|
43098
|
+
function axisPivotFieldXml(axis, itemCount) {
|
|
43099
|
+
const items = [];
|
|
43100
|
+
for (let i2 = 0; i2 < itemCount; i2++) items.push(`<item x="${i2}"/>`);
|
|
43101
|
+
items.push(`<item t="default"/>`);
|
|
43102
|
+
return `<pivotField axis="${axis}" showAll="0"><items count="${items.length}">${items.join("")}</items></pivotField>`;
|
|
42348
43103
|
}
|
|
42349
|
-
function
|
|
42350
|
-
const
|
|
42351
|
-
|
|
42352
|
-
if (
|
|
42353
|
-
|
|
42354
|
-
if (s.borderLeft) parts.push(`l:${s.borderLeft.style}:${s.borderLeft.width}:${s.borderLeft.color ?? ""}`);
|
|
42355
|
-
if (s.borderDiagonal) parts.push(`d:${s.borderDiagonal.style}:${s.borderDiagonal.width}:${s.borderDiagonal.color ?? ""}`);
|
|
42356
|
-
if (s.diagonalUp) parts.push("du");
|
|
42357
|
-
if (s.diagonalDown) parts.push("dd");
|
|
42358
|
-
return parts.join("|");
|
|
43104
|
+
function axisItemsXml(element, itemCount, grandTotal) {
|
|
43105
|
+
const items = [];
|
|
43106
|
+
for (let i2 = 0; i2 < itemCount; i2++) items.push(`<i><x v="${i2}"/></i>`);
|
|
43107
|
+
if (grandTotal) items.push(`<i t="grand"><x/></i>`);
|
|
43108
|
+
return `<${element} count="${items.length}">${items.join("")}</${element}>`;
|
|
42359
43109
|
}
|
|
42360
|
-
|
|
42361
|
-
|
|
42362
|
-
|
|
42363
|
-
|
|
42364
|
-
|
|
42365
|
-
|
|
42366
|
-
|
|
42367
|
-
|
|
42368
|
-
|
|
42369
|
-
|
|
42370
|
-
|
|
42371
|
-
|
|
42372
|
-
|
|
42373
|
-
"mediumDashDotDot",
|
|
42374
|
-
"slantDashDot"
|
|
42375
|
-
];
|
|
42376
|
-
if (ooxmlStyles.includes(border2.style)) return border2.style;
|
|
42377
|
-
if (border2.style === "solid") {
|
|
42378
|
-
if (border2.width <= 1) return "thin";
|
|
42379
|
-
if (border2.width <= 2) return "medium";
|
|
42380
|
-
return "thick";
|
|
42381
|
-
}
|
|
42382
|
-
if (border2.style === "dashed") return "dashed";
|
|
42383
|
-
if (border2.style === "dotted") return "dotted";
|
|
42384
|
-
if (border2.style === "double") return "double";
|
|
42385
|
-
return "thin";
|
|
42386
|
-
}
|
|
42387
|
-
function buildBorderXml(s) {
|
|
42388
|
-
let attrs = "";
|
|
42389
|
-
if (s.diagonalUp) attrs += ' diagonalUp="1"';
|
|
42390
|
-
if (s.diagonalDown) attrs += ' diagonalDown="1"';
|
|
42391
|
-
const sides = [
|
|
42392
|
-
{ tag: "left", border: s.borderLeft },
|
|
42393
|
-
{ tag: "right", border: s.borderRight },
|
|
42394
|
-
{ tag: "top", border: s.borderTop },
|
|
42395
|
-
{ tag: "bottom", border: s.borderBottom },
|
|
42396
|
-
{ tag: "diagonal", border: s.borderDiagonal }
|
|
42397
|
-
];
|
|
42398
|
-
const inner = sides.map(({ tag, border: border2 }) => {
|
|
42399
|
-
if (!border2) return `<${tag}/>`;
|
|
42400
|
-
const ooxmlStyle = toOoxmlBorderStyle(border2);
|
|
42401
|
-
let colorXml = "";
|
|
42402
|
-
if (border2.color) {
|
|
42403
|
-
colorXml = `<color rgb="${hexToArgb(border2.color)}"/>`;
|
|
42404
|
-
}
|
|
42405
|
-
return `<${tag} style="${ooxmlStyle}">${colorXml}</${tag}>`;
|
|
42406
|
-
}).join("");
|
|
42407
|
-
return `<border${attrs}>${inner}</border>`;
|
|
43110
|
+
|
|
43111
|
+
// ../xlsx/src/xlsx_writer.ts
|
|
43112
|
+
function readWorkbookSheetOrder(originalZip) {
|
|
43113
|
+
const wbBytes = originalZip["xl/workbook.xml"];
|
|
43114
|
+
if (!wbBytes) return [];
|
|
43115
|
+
const xml = decode(wbBytes);
|
|
43116
|
+
const out = [];
|
|
43117
|
+
const re = /<sheet\b[^>]*?r:id="([^"]+)"/g;
|
|
43118
|
+
let m;
|
|
43119
|
+
while ((m = re.exec(xml)) !== null) {
|
|
43120
|
+
out.push(m[1]);
|
|
43121
|
+
}
|
|
43122
|
+
return out;
|
|
42408
43123
|
}
|
|
42409
|
-
function
|
|
42410
|
-
|
|
42411
|
-
|
|
42412
|
-
if (
|
|
42413
|
-
|
|
43124
|
+
function readWorkbookRels(originalZip) {
|
|
43125
|
+
const out = /* @__PURE__ */ new Map();
|
|
43126
|
+
const bytes = originalZip["xl/_rels/workbook.xml.rels"];
|
|
43127
|
+
if (!bytes) return out;
|
|
43128
|
+
const xml = decode(bytes);
|
|
43129
|
+
const re = /<Relationship\b([^/]*?)\/>/g;
|
|
43130
|
+
let m;
|
|
43131
|
+
while ((m = re.exec(xml)) !== null) {
|
|
43132
|
+
const attrs = m[1];
|
|
43133
|
+
const id = /\bId="([^"]+)"/.exec(attrs)?.[1];
|
|
43134
|
+
const type = /\bType="([^"]+)"/.exec(attrs)?.[1] ?? "";
|
|
43135
|
+
const target = /\bTarget="([^"]+)"/.exec(attrs)?.[1] ?? "";
|
|
43136
|
+
if (id) out.set(id, { type, target });
|
|
43137
|
+
}
|
|
43138
|
+
return out;
|
|
42414
43139
|
}
|
|
42415
|
-
function
|
|
42416
|
-
|
|
42417
|
-
|
|
42418
|
-
|
|
42419
|
-
|
|
42420
|
-
|
|
42421
|
-
|
|
42422
|
-
|
|
42423
|
-
|
|
43140
|
+
function readPivotCacheIdMap(originalZip) {
|
|
43141
|
+
const out = /* @__PURE__ */ new Map();
|
|
43142
|
+
const bytes = originalZip["xl/workbook.xml"];
|
|
43143
|
+
if (!bytes) return out;
|
|
43144
|
+
const xml = decode(bytes);
|
|
43145
|
+
const re = /<pivotCache\b([^/]*?)\/>/g;
|
|
43146
|
+
let m;
|
|
43147
|
+
while ((m = re.exec(xml)) !== null) {
|
|
43148
|
+
const attrs = m[1];
|
|
43149
|
+
const cacheIdMatch = /\bcacheId="(\d+)"/.exec(attrs);
|
|
43150
|
+
const ridMatch = /\br:id="([^"]+)"/.exec(attrs);
|
|
43151
|
+
if (cacheIdMatch && ridMatch) {
|
|
43152
|
+
out.set(parseInt(cacheIdMatch[1], 10), ridMatch[1]);
|
|
42424
43153
|
}
|
|
42425
|
-
return `<fill><gradientFill degree="${g.degree}">${stops}</gradientFill></fill>`;
|
|
42426
43154
|
}
|
|
42427
|
-
|
|
42428
|
-
|
|
42429
|
-
|
|
42430
|
-
|
|
42431
|
-
|
|
42432
|
-
|
|
43155
|
+
return out;
|
|
43156
|
+
}
|
|
43157
|
+
function readSheetPivotPaths(originalZip, sheetTarget) {
|
|
43158
|
+
const sheetPath = `xl/${sheetTarget}`;
|
|
43159
|
+
const relsPath = sheetPath.replace(/([^/]+)$/, "_rels/$1.rels");
|
|
43160
|
+
const bytes = originalZip[relsPath];
|
|
43161
|
+
if (!bytes) return [];
|
|
43162
|
+
const xml = decode(bytes);
|
|
43163
|
+
const re = /<Relationship\b([^/]*?)\/>/g;
|
|
43164
|
+
const out = [];
|
|
43165
|
+
let m;
|
|
43166
|
+
while ((m = re.exec(xml)) !== null) {
|
|
43167
|
+
const attrs = m[1];
|
|
43168
|
+
const type = /\bType="([^"]+)"/.exec(attrs)?.[1] ?? "";
|
|
43169
|
+
if (!type.includes("/pivotTable")) continue;
|
|
43170
|
+
const target = /\bTarget="([^"]+)"/.exec(attrs)?.[1];
|
|
43171
|
+
if (target) out.push(target);
|
|
42433
43172
|
}
|
|
42434
|
-
return
|
|
43173
|
+
return out;
|
|
42435
43174
|
}
|
|
42436
|
-
function
|
|
42437
|
-
const
|
|
42438
|
-
|
|
42439
|
-
|
|
43175
|
+
function extractPivotRoundTripInfo(originalZip) {
|
|
43176
|
+
const empty = {
|
|
43177
|
+
cachesByWorkbook: /* @__PURE__ */ new Map(),
|
|
43178
|
+
pivotTablesBySheetIndex: /* @__PURE__ */ new Map(),
|
|
43179
|
+
pivotXmlPaths: []
|
|
43180
|
+
};
|
|
43181
|
+
if (!originalZip) return empty;
|
|
43182
|
+
const sheetRIds = readWorkbookSheetOrder(originalZip);
|
|
43183
|
+
const wbRels = readWorkbookRels(originalZip);
|
|
43184
|
+
const cacheRIds = readPivotCacheIdMap(originalZip);
|
|
43185
|
+
const cachesByWorkbook = /* @__PURE__ */ new Map();
|
|
43186
|
+
for (const [cacheId, rid] of cacheRIds) {
|
|
43187
|
+
const rel = wbRels.get(rid);
|
|
43188
|
+
if (!rel) continue;
|
|
43189
|
+
cachesByWorkbook.set(cacheId, rel.target);
|
|
42440
43190
|
}
|
|
42441
|
-
const
|
|
42442
|
-
|
|
42443
|
-
|
|
43191
|
+
const pivotTablesBySheetIndex = /* @__PURE__ */ new Map();
|
|
43192
|
+
for (let i2 = 0; i2 < sheetRIds.length; i2++) {
|
|
43193
|
+
const sheetTarget = wbRels.get(sheetRIds[i2])?.target;
|
|
43194
|
+
if (!sheetTarget) continue;
|
|
43195
|
+
const paths = readSheetPivotPaths(originalZip, sheetTarget);
|
|
43196
|
+
if (paths.length > 0) pivotTablesBySheetIndex.set(i2, paths);
|
|
42444
43197
|
}
|
|
42445
|
-
|
|
42446
|
-
|
|
42447
|
-
|
|
42448
|
-
|
|
42449
|
-
|
|
42450
|
-
|
|
42451
|
-
|
|
42452
|
-
if (!rc) continue;
|
|
42453
|
-
let arr = rowMap.get(rc.row);
|
|
42454
|
-
if (!arr) {
|
|
42455
|
-
arr = [];
|
|
42456
|
-
rowMap.set(rc.row, arr);
|
|
43198
|
+
const pivotXmlPaths = [];
|
|
43199
|
+
for (const path7 of Object.keys(originalZip)) {
|
|
43200
|
+
if (path7.startsWith("xl/pivotTables/") && path7.endsWith(".xml")) {
|
|
43201
|
+
pivotXmlPaths.push(path7);
|
|
43202
|
+
}
|
|
43203
|
+
if (path7.startsWith("xl/pivotCache/") && path7.endsWith(".xml")) {
|
|
43204
|
+
pivotXmlPaths.push(path7);
|
|
42457
43205
|
}
|
|
42458
|
-
arr.push({ col: rc.col, cell });
|
|
42459
|
-
}
|
|
42460
|
-
const sortedRows = Array.from(rowMap.keys()).sort((a, b) => a - b);
|
|
42461
|
-
for (const rowNum of sortedRows) {
|
|
42462
|
-
const cells = rowMap.get(rowNum);
|
|
42463
|
-
cells.sort((a, b) => a.col - b.col);
|
|
42464
|
-
const h = sheet.rowHeights.get(rowNum);
|
|
42465
|
-
const rowAttrs = h ? ` ht="${h}" customHeight="1"` : "";
|
|
42466
|
-
const hidden = sheet.hiddenRows.has(rowNum) ? ' hidden="1"' : "";
|
|
42467
|
-
const cellsXml = cells.map(({ col, cell }) => {
|
|
42468
|
-
const ref = rowColToRef(rowNum, col);
|
|
42469
|
-
const type = getCellType(cell, ssIndex);
|
|
42470
|
-
const value = getCellValue(cell, ssIndex);
|
|
42471
|
-
let attrs = `r="${ref}"`;
|
|
42472
|
-
let xfIndex = 0;
|
|
42473
|
-
if (xfMap.size === 0 && cell.originalXfIndex !== void 0) {
|
|
42474
|
-
xfIndex = cell.originalXfIndex;
|
|
42475
|
-
} else {
|
|
42476
|
-
const numFmtId = cell.numFmtCode && cell.numFmtCode !== "General" && cell.numFmtCode !== "" ? numFmtMap.get(cell.numFmtCode) ?? 0 : 0;
|
|
42477
|
-
const xfKey = `${cell.styleIndex}:${numFmtId}`;
|
|
42478
|
-
xfIndex = xfMap.get(xfKey) ?? 0;
|
|
42479
|
-
}
|
|
42480
|
-
if (xfIndex > 0) attrs += ` s="${xfIndex}"`;
|
|
42481
|
-
if (type) attrs += ` t="${type}"`;
|
|
42482
|
-
let inner = "";
|
|
42483
|
-
if (cell.formula) {
|
|
42484
|
-
if (cell.isArrayFormula && cell.arrayRange) {
|
|
42485
|
-
inner += `<f t="array" ref="${cell.arrayRange}">${escapeXml(cell.formula)}</f>`;
|
|
42486
|
-
} else {
|
|
42487
|
-
inner += `<f>${escapeXml(cell.formula)}</f>`;
|
|
42488
|
-
}
|
|
42489
|
-
}
|
|
42490
|
-
if (value !== void 0) inner += `<v>${escapeXml(String(value))}</v>`;
|
|
42491
|
-
return `<c ${attrs}>${inner}</c>`;
|
|
42492
|
-
}).join("");
|
|
42493
|
-
rows.push(`<row r="${rowNum}"${rowAttrs}${hidden}>${cellsXml}</row>`);
|
|
42494
43206
|
}
|
|
42495
|
-
|
|
42496
|
-
|
|
42497
|
-
|
|
42498
|
-
|
|
42499
|
-
|
|
42500
|
-
|
|
43207
|
+
return { cachesByWorkbook, pivotTablesBySheetIndex, pivotXmlPaths };
|
|
43208
|
+
}
|
|
43209
|
+
function decode(bytes) {
|
|
43210
|
+
return new TextDecoder().decode(bytes);
|
|
43211
|
+
}
|
|
43212
|
+
function pivotContentTypeFor(path7) {
|
|
43213
|
+
if (path7.startsWith("xl/pivotTables/") && path7.endsWith(".xml")) {
|
|
43214
|
+
return `<Override PartName="/${path7}" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.pivotTable+xml"/>`;
|
|
42501
43215
|
}
|
|
42502
|
-
|
|
42503
|
-
|
|
42504
|
-
const merges = sheet.mergedCells.map((r) => `<mergeCell ref="${r}"/>`).join("");
|
|
42505
|
-
mergeXml = `<mergeCells count="${sheet.mergedCells.length}">${merges}</mergeCells>`;
|
|
43216
|
+
if (path7.includes("/pivotCacheDefinition") && path7.endsWith(".xml")) {
|
|
43217
|
+
return `<Override PartName="/${path7}" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheDefinition+xml"/>`;
|
|
42506
43218
|
}
|
|
42507
|
-
|
|
42508
|
-
|
|
42509
|
-
if (sheet.freeze) {
|
|
42510
|
-
const activePane = sheet.freeze.col > 0 && sheet.freeze.row > 0 ? "bottomRight" : sheet.freeze.row > 0 ? "bottomLeft" : "topRight";
|
|
42511
|
-
const topLeft = rowColToRef(sheet.freeze.row + 1, sheet.freeze.col + 1);
|
|
42512
|
-
paneXml = `<pane xSplit="${sheet.freeze.col}" ySplit="${sheet.freeze.row}" topLeftCell="${topLeft}" activePane="${activePane}" state="frozen"/>`;
|
|
42513
|
-
selectionXml = `<selection pane="${activePane}" activeCell="${topLeft}" sqref="${topLeft}"/>`;
|
|
43219
|
+
if (path7.includes("/pivotCacheRecords") && path7.endsWith(".xml")) {
|
|
43220
|
+
return `<Override PartName="/${path7}" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheRecords+xml"/>`;
|
|
42514
43221
|
}
|
|
42515
|
-
|
|
42516
|
-
|
|
42517
|
-
|
|
42518
|
-
|
|
42519
|
-
|
|
42520
|
-
|
|
42521
|
-
|
|
42522
|
-
|
|
42523
|
-
|
|
42524
|
-
|
|
43222
|
+
return void 0;
|
|
43223
|
+
}
|
|
43224
|
+
var REL_BASE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships";
|
|
43225
|
+
function relsXml(rels) {
|
|
43226
|
+
return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
43227
|
+
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
|
|
43228
|
+
` + rels.map((r) => `<Relationship Id="${r.id}" Type="${r.type}" Target="${escapeXml(r.target)}"/>`).join("\n") + `
|
|
43229
|
+
</Relationships>`;
|
|
43230
|
+
}
|
|
43231
|
+
function emitAuthoredPivots(workbook, entries, startFileIndex) {
|
|
43232
|
+
const info = {
|
|
43233
|
+
cachesByWorkbook: /* @__PURE__ */ new Map(),
|
|
43234
|
+
pivotTablesBySheetIndex: /* @__PURE__ */ new Map(),
|
|
43235
|
+
pivotXmlPaths: []
|
|
43236
|
+
};
|
|
43237
|
+
let n = startFileIndex;
|
|
43238
|
+
for (let i2 = 0; i2 < workbook.sheets.length; i2++) {
|
|
43239
|
+
for (const model of workbook.sheets[i2].pivotTables) {
|
|
43240
|
+
if (!model.authored) continue;
|
|
43241
|
+
const idx = n++;
|
|
43242
|
+
const enumerate = enumerateFlags(model.config, model.cache.fields.length);
|
|
43243
|
+
const records = readSourceData(workbook, model.cache)?.records ?? [];
|
|
43244
|
+
const cacheDefPath = `xl/pivotCache/pivotCacheDefinition${idx}.xml`;
|
|
43245
|
+
const recordsPath = `xl/pivotCache/pivotCacheRecords${idx}.xml`;
|
|
43246
|
+
const tablePath = `xl/pivotTables/pivotTable${idx}.xml`;
|
|
43247
|
+
entries[cacheDefPath] = strToU8(buildPivotCacheDefinitionXml(model.cache, enumerate, records.length, "rId1"));
|
|
43248
|
+
entries[`xl/pivotCache/_rels/pivotCacheDefinition${idx}.xml.rels`] = strToU8(
|
|
43249
|
+
relsXml([{ id: "rId1", type: `${REL_BASE}/pivotCacheRecords`, target: `pivotCacheRecords${idx}.xml` }])
|
|
43250
|
+
);
|
|
43251
|
+
entries[recordsPath] = strToU8(buildPivotCacheRecordsXml(records, model.cache, enumerate));
|
|
43252
|
+
entries[tablePath] = strToU8(buildPivotTableXml(model.config, model.cache));
|
|
43253
|
+
entries[`xl/pivotTables/_rels/pivotTable${idx}.xml.rels`] = strToU8(
|
|
43254
|
+
relsXml([{ id: "rId1", type: `${REL_BASE}/pivotCacheDefinition`, target: `../pivotCache/pivotCacheDefinition${idx}.xml` }])
|
|
43255
|
+
);
|
|
43256
|
+
info.cachesByWorkbook.set(model.cache.id, `pivotCache/pivotCacheDefinition${idx}.xml`);
|
|
43257
|
+
const list = info.pivotTablesBySheetIndex.get(i2) ?? [];
|
|
43258
|
+
list.push(`../pivotTables/pivotTable${idx}.xml`);
|
|
43259
|
+
info.pivotTablesBySheetIndex.set(i2, list);
|
|
43260
|
+
info.pivotXmlPaths.push(tablePath, cacheDefPath, recordsPath);
|
|
42525
43261
|
}
|
|
42526
|
-
autoFilterXml = `<autoFilter ref="${sheet.autoFilter.ref}">${filterCols}</autoFilter>`;
|
|
42527
43262
|
}
|
|
42528
|
-
|
|
42529
|
-
|
|
42530
|
-
|
|
42531
|
-
|
|
42532
|
-
|
|
42533
|
-
|
|
42534
|
-
|
|
42535
|
-
|
|
42536
|
-
|
|
42537
|
-
if (dv.promptTitle) attrs += ` promptTitle="${escapeXml(dv.promptTitle)}"`;
|
|
42538
|
-
if (dv.promptMessage) attrs += ` prompt="${escapeXml(dv.promptMessage)}"`;
|
|
42539
|
-
let inner = "";
|
|
42540
|
-
if (dv.formula1) inner += `<formula1>${escapeXml(dv.formula1)}</formula1>`;
|
|
42541
|
-
if (dv.formula2) inner += `<formula2>${escapeXml(dv.formula2)}</formula2>`;
|
|
42542
|
-
return `<dataValidation ${attrs}>${inner}</dataValidation>`;
|
|
42543
|
-
}).join("");
|
|
42544
|
-
dvXml = `<dataValidations count="${sheet.dataValidations.length}">${dvEntries}</dataValidations>`;
|
|
42545
|
-
}
|
|
42546
|
-
let cfXml = "";
|
|
42547
|
-
if (sheet.conditionalFormats.length > 0) {
|
|
42548
|
-
cfXml = sheet.conditionalFormats.map((cf) => buildConditionalFormattingXml(cf, dxfMap)).join("");
|
|
42549
|
-
}
|
|
42550
|
-
let hyperlinksXml = "";
|
|
42551
|
-
if (hyperlinkRIds && hyperlinkRIds.size > 0) {
|
|
42552
|
-
const hlEntries = Array.from(hyperlinkRIds.entries()).map(([ref, rId]) => `<hyperlink ref="${ref}" r:id="${rId}"/>`).join("");
|
|
42553
|
-
hyperlinksXml = `<hyperlinks>${hlEntries}</hyperlinks>`;
|
|
43263
|
+
return info;
|
|
43264
|
+
}
|
|
43265
|
+
function mergePivotInfo(a, b) {
|
|
43266
|
+
const cachesByWorkbook = new Map(a.cachesByWorkbook);
|
|
43267
|
+
for (const [k, v] of b.cachesByWorkbook) cachesByWorkbook.set(k, v);
|
|
43268
|
+
const pivotTablesBySheetIndex = /* @__PURE__ */ new Map();
|
|
43269
|
+
for (const [k, v] of a.pivotTablesBySheetIndex) pivotTablesBySheetIndex.set(k, [...v]);
|
|
43270
|
+
for (const [k, v] of b.pivotTablesBySheetIndex) {
|
|
43271
|
+
pivotTablesBySheetIndex.set(k, [...pivotTablesBySheetIndex.get(k) ?? [], ...v]);
|
|
42554
43272
|
}
|
|
42555
|
-
|
|
42556
|
-
|
|
42557
|
-
|
|
42558
|
-
|
|
42559
|
-
|
|
43273
|
+
return { cachesByWorkbook, pivotTablesBySheetIndex, pivotXmlPaths: [...a.pivotXmlPaths, ...b.pivotXmlPaths] };
|
|
43274
|
+
}
|
|
43275
|
+
function exportWorkbook(workbook, originalZip) {
|
|
43276
|
+
const entries = {};
|
|
43277
|
+
const stylesPassthrough = !!originalZip && !workbook.styles.dirty && !!originalZip["xl/styles.xml"];
|
|
43278
|
+
if (originalZip) {
|
|
43279
|
+
const regeneratedPaths = /* @__PURE__ */ new Set();
|
|
43280
|
+
regeneratedPaths.add("xl/sharedStrings.xml");
|
|
43281
|
+
if (!stylesPassthrough) regeneratedPaths.add("xl/styles.xml");
|
|
43282
|
+
regeneratedPaths.add("xl/workbook.xml");
|
|
43283
|
+
regeneratedPaths.add("xl/_rels/workbook.xml.rels");
|
|
43284
|
+
regeneratedPaths.add("[Content_Types].xml");
|
|
43285
|
+
regeneratedPaths.add("_rels/.rels");
|
|
43286
|
+
regeneratedPaths.add("docProps/core.xml");
|
|
43287
|
+
regeneratedPaths.add("docProps/app.xml");
|
|
43288
|
+
for (let i2 = 0; i2 < workbook.sheets.length + 10; i2++) {
|
|
43289
|
+
regeneratedPaths.add(`xl/worksheets/sheet${i2 + 1}.xml`);
|
|
43290
|
+
regeneratedPaths.add(`xl/worksheets/_rels/sheet${i2 + 1}.xml.rels`);
|
|
43291
|
+
}
|
|
43292
|
+
for (const path7 of Object.keys(originalZip)) {
|
|
43293
|
+
if (path7.startsWith("xl/drawings/") || path7.startsWith("xl/charts/") || path7.startsWith("xl/tables/") || path7.startsWith("xl/media/")) {
|
|
43294
|
+
regeneratedPaths.add(path7);
|
|
43295
|
+
}
|
|
43296
|
+
}
|
|
43297
|
+
for (const [path7, data] of Object.entries(originalZip)) {
|
|
43298
|
+
if (!regeneratedPaths.has(path7)) entries[path7] = data;
|
|
43299
|
+
}
|
|
42560
43300
|
}
|
|
42561
|
-
const
|
|
42562
|
-
|
|
42563
|
-
const
|
|
42564
|
-
|
|
42565
|
-
const
|
|
42566
|
-
|
|
42567
|
-
|
|
42568
|
-
|
|
42569
|
-
|
|
42570
|
-
|
|
42571
|
-
|
|
42572
|
-
|
|
42573
|
-
|
|
42574
|
-
|
|
42575
|
-
|
|
42576
|
-
if (ps) {
|
|
42577
|
-
const attrs = [];
|
|
42578
|
-
if (ps.paperSize !== void 0) attrs.push(`paperSize="${ps.paperSize}"`);
|
|
42579
|
-
if (ps.scale !== void 0) attrs.push(`scale="${ps.scale}"`);
|
|
42580
|
-
if (ps.fitToWidth !== void 0) attrs.push(`fitToWidth="${ps.fitToWidth}"`);
|
|
42581
|
-
if (ps.fitToHeight !== void 0) attrs.push(`fitToHeight="${ps.fitToHeight}"`);
|
|
42582
|
-
if (ps.orientation) attrs.push(`orientation="${ps.orientation}"`);
|
|
42583
|
-
if (attrs.length > 0) pageSetupXml = `<pageSetup ${attrs.join(" ")}/>`;
|
|
43301
|
+
const sharedStrings = buildSharedStrings(workbook);
|
|
43302
|
+
entries["xl/sharedStrings.xml"] = strToU8(sharedStrings.xml);
|
|
43303
|
+
const stylesResult = stylesPassthrough ? { xml: "", xfMap: /* @__PURE__ */ new Map(), numFmtMap: /* @__PURE__ */ new Map(), dxfMap: /* @__PURE__ */ new Map() } : buildStylesXml(workbook);
|
|
43304
|
+
if (!stylesPassthrough) entries["xl/styles.xml"] = strToU8(stylesResult.xml);
|
|
43305
|
+
const roundTripInfo = extractPivotRoundTripInfo(originalZip);
|
|
43306
|
+
const authoredStartIndex = roundTripInfo.pivotXmlPaths.filter((p) => p.startsWith("xl/pivotTables/")).length + 1;
|
|
43307
|
+
const pivotInfo = mergePivotInfo(roundTripInfo, emitAuthoredPivots(workbook, entries, authoredStartIndex));
|
|
43308
|
+
entries["xl/workbook.xml"] = strToU8(buildWorkbookXml(workbook, pivotInfo));
|
|
43309
|
+
entries["xl/_rels/workbook.xml.rels"] = strToU8(
|
|
43310
|
+
buildWorkbookRels(workbook, pivotInfo)
|
|
43311
|
+
);
|
|
43312
|
+
const extraContentTypes = [];
|
|
43313
|
+
for (const path7 of pivotInfo.pivotXmlPaths) {
|
|
43314
|
+
const ct = pivotContentTypeFor(path7);
|
|
43315
|
+
if (ct) extraContentTypes.push(ct);
|
|
42584
43316
|
}
|
|
42585
|
-
let
|
|
42586
|
-
|
|
42587
|
-
|
|
42588
|
-
|
|
42589
|
-
|
|
42590
|
-
const
|
|
42591
|
-
|
|
42592
|
-
|
|
42593
|
-
|
|
42594
|
-
|
|
42595
|
-
|
|
42596
|
-
|
|
42597
|
-
|
|
42598
|
-
|
|
42599
|
-
|
|
43317
|
+
let globalChartIndex = 1;
|
|
43318
|
+
let globalImageIndex = 1;
|
|
43319
|
+
let globalTableIndex = 1;
|
|
43320
|
+
for (let i2 = 0; i2 < workbook.sheets.length; i2++) {
|
|
43321
|
+
const sheet = workbook.sheets[i2];
|
|
43322
|
+
const sheetRels = [];
|
|
43323
|
+
let nextRId = 1;
|
|
43324
|
+
const hasCharts = sheet.charts.length > 0;
|
|
43325
|
+
const hasImages = sheet.images.length > 0;
|
|
43326
|
+
const hasDrawings = sheet.drawings.length > 0;
|
|
43327
|
+
const hasTables = sheet.tables.length > 0;
|
|
43328
|
+
const hasHyperlinks = sheet.hyperlinks.size > 0;
|
|
43329
|
+
const needsDrawing = hasCharts || hasImages || hasDrawings;
|
|
43330
|
+
const hyperlinkRIds = /* @__PURE__ */ new Map();
|
|
43331
|
+
if (hasHyperlinks) {
|
|
43332
|
+
for (const [ref, url] of sheet.hyperlinks) {
|
|
43333
|
+
const rId = `rId${nextRId++}`;
|
|
43334
|
+
hyperlinkRIds.set(ref, rId);
|
|
43335
|
+
sheetRels.push(`<Relationship Id="${rId}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink" Target="${escapeXml(url)}" TargetMode="External"/>`);
|
|
43336
|
+
}
|
|
42600
43337
|
}
|
|
42601
|
-
|
|
42602
|
-
|
|
42603
|
-
|
|
42604
|
-
|
|
42605
|
-
|
|
42606
|
-
|
|
42607
|
-
|
|
42608
|
-
const
|
|
42609
|
-
|
|
42610
|
-
|
|
42611
|
-
|
|
43338
|
+
let drawingRId = "";
|
|
43339
|
+
if (needsDrawing) {
|
|
43340
|
+
drawingRId = `rId${nextRId++}`;
|
|
43341
|
+
sheetRels.push(`<Relationship Id="${drawingRId}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing" Target="../drawings/drawing${i2 + 1}.xml"/>`);
|
|
43342
|
+
const drawingRels = [];
|
|
43343
|
+
let drawingRelId = 1;
|
|
43344
|
+
const drawingAnchors = [];
|
|
43345
|
+
for (const chart of sheet.charts) {
|
|
43346
|
+
const chartRId = `rId${drawingRelId++}`;
|
|
43347
|
+
const chartPath = `xl/charts/chart${globalChartIndex}.xml`;
|
|
43348
|
+
entries[chartPath] = strToU8(buildChartXml(chart));
|
|
43349
|
+
extraContentTypes.push(`<Override PartName="/${chartPath}" ContentType="application/vnd.openxmlformats-officedocument.drawingml.chart+xml"/>`);
|
|
43350
|
+
drawingRels.push(`<Relationship Id="${chartRId}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart" Target="../charts/chart${globalChartIndex}.xml"/>`);
|
|
43351
|
+
drawingAnchors.push(buildChartAnchorXml(chart, chartRId));
|
|
43352
|
+
globalChartIndex++;
|
|
43353
|
+
}
|
|
43354
|
+
for (const image of sheet.images) {
|
|
43355
|
+
const imgRId = `rId${drawingRelId++}`;
|
|
43356
|
+
const ext = getImageExtension(image.dataUrl);
|
|
43357
|
+
const imgPath = `xl/media/image${globalImageIndex}.${ext}`;
|
|
43358
|
+
const imgBytes = dataUrlToBytes(image.dataUrl);
|
|
43359
|
+
if (imgBytes) {
|
|
43360
|
+
entries[imgPath] = imgBytes;
|
|
43361
|
+
drawingRels.push(`<Relationship Id="${imgRId}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/image" Target="../media/image${globalImageIndex}.${ext}"/>`);
|
|
43362
|
+
drawingAnchors.push(buildImageAnchorXml(image, imgRId));
|
|
43363
|
+
globalImageIndex++;
|
|
43364
|
+
}
|
|
43365
|
+
}
|
|
43366
|
+
for (const drawing of sheet.drawings) {
|
|
43367
|
+
drawingAnchors.push(buildShapeAnchorXml(drawing));
|
|
43368
|
+
}
|
|
43369
|
+
entries[`xl/drawings/drawing${i2 + 1}.xml`] = strToU8(
|
|
43370
|
+
`<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
43371
|
+
<xdr:wsDr xmlns:xdr="http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing" xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:c="http://schemas.openxmlformats.org/drawingml/2006/chart">
|
|
43372
|
+
` + drawingAnchors.join("\n") + `
|
|
43373
|
+
</xdr:wsDr>`
|
|
43374
|
+
);
|
|
43375
|
+
extraContentTypes.push(`<Override PartName="/xl/drawings/drawing${i2 + 1}.xml" ContentType="application/vnd.openxmlformats-officedocument.drawing+xml"/>`);
|
|
43376
|
+
if (drawingRels.length > 0) {
|
|
43377
|
+
entries[`xl/drawings/_rels/drawing${i2 + 1}.xml.rels`] = strToU8(
|
|
43378
|
+
`<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
43379
|
+
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
|
|
43380
|
+
${drawingRels.join("\n")}
|
|
43381
|
+
</Relationships>`
|
|
43382
|
+
);
|
|
42612
43383
|
}
|
|
42613
43384
|
}
|
|
42614
|
-
|
|
43385
|
+
const tableRIds = [];
|
|
43386
|
+
if (hasTables) {
|
|
43387
|
+
for (const table of sheet.tables) {
|
|
43388
|
+
const tableRId = `rId${nextRId++}`;
|
|
43389
|
+
tableRIds.push(tableRId);
|
|
43390
|
+
const tablePath = `xl/tables/table${globalTableIndex}.xml`;
|
|
43391
|
+
entries[tablePath] = strToU8(buildTableXml(table, globalTableIndex));
|
|
43392
|
+
extraContentTypes.push(`<Override PartName="/${tablePath}" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.table+xml"/>`);
|
|
43393
|
+
sheetRels.push(`<Relationship Id="${tableRId}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/table" Target="../tables/table${globalTableIndex}.xml"/>`);
|
|
43394
|
+
globalTableIndex++;
|
|
43395
|
+
}
|
|
43396
|
+
}
|
|
43397
|
+
const pivotTargets = pivotInfo.pivotTablesBySheetIndex.get(i2);
|
|
43398
|
+
if (pivotTargets && pivotTargets.length > 0) {
|
|
43399
|
+
for (const target of pivotTargets) {
|
|
43400
|
+
const rId = `rId${nextRId++}`;
|
|
43401
|
+
sheetRels.push(
|
|
43402
|
+
`<Relationship Id="${rId}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/pivotTable" Target="${escapeXml(target)}"/>`
|
|
43403
|
+
);
|
|
43404
|
+
}
|
|
43405
|
+
}
|
|
43406
|
+
if (sheetRels.length > 0) {
|
|
43407
|
+
entries[`xl/worksheets/_rels/sheet${i2 + 1}.xml.rels`] = strToU8(
|
|
43408
|
+
`<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
43409
|
+
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
|
|
43410
|
+
${sheetRels.join("\n")}
|
|
43411
|
+
</Relationships>`
|
|
43412
|
+
);
|
|
43413
|
+
}
|
|
43414
|
+
entries[`xl/worksheets/sheet${i2 + 1}.xml`] = strToU8(
|
|
43415
|
+
buildSheetXml(sheet, workbook.styles, sharedStrings.index, i2 === workbook.activeSheetIndex, stylesResult.xfMap, stylesResult.numFmtMap, stylesResult.dxfMap, drawingRId, tableRIds, hyperlinkRIds)
|
|
43416
|
+
);
|
|
42615
43417
|
}
|
|
42616
|
-
|
|
42617
|
-
|
|
42618
|
-
|
|
42619
|
-
|
|
42620
|
-
|
|
42621
|
-
<sheetFormatPr defaultRowHeight="${sheet.defaultRowHeight}" defaultColWidth="${sheet.defaultColWidth}"/>
|
|
42622
|
-
${cols.length > 0 ? `<cols>${cols.join("")}</cols>` : ""}
|
|
42623
|
-
<sheetData>
|
|
42624
|
-
${rows.join("\n")}
|
|
42625
|
-
</sheetData>
|
|
42626
|
-
${autoFilterXml}${mergeXml}${cfXml}${dvXml}${hyperlinksXml}${marginsXml}${pageSetupXml}${headerFooterXml}${drawingXml}${tablePartsXml}
|
|
42627
|
-
</worksheet>`;
|
|
42628
|
-
}
|
|
42629
|
-
function getCellType(cell, ssIndex) {
|
|
42630
|
-
if (cell.error) return "e";
|
|
42631
|
-
if (cell.formula && typeof cell.value === "string") return "str";
|
|
42632
|
-
if (typeof cell.value === "string" && ssIndex.has(cell.value)) return "s";
|
|
42633
|
-
if (typeof cell.value === "boolean") return "b";
|
|
42634
|
-
return void 0;
|
|
43418
|
+
entries["docProps/core.xml"] = strToU8(buildCoreProps());
|
|
43419
|
+
entries["docProps/app.xml"] = strToU8(buildAppProps());
|
|
43420
|
+
entries["[Content_Types].xml"] = strToU8(buildContentTypes(workbook.sheets.length, extraContentTypes));
|
|
43421
|
+
entries["_rels/.rels"] = strToU8(buildRootRels());
|
|
43422
|
+
return zipSync(entries, { level: 6 });
|
|
42635
43423
|
}
|
|
42636
|
-
function
|
|
42637
|
-
|
|
42638
|
-
|
|
42639
|
-
|
|
42640
|
-
|
|
42641
|
-
|
|
42642
|
-
|
|
43424
|
+
function buildSharedStrings(workbook) {
|
|
43425
|
+
const strings = [];
|
|
43426
|
+
const index = /* @__PURE__ */ new Map();
|
|
43427
|
+
const richTextMap = /* @__PURE__ */ new Map();
|
|
43428
|
+
let totalCount = 0;
|
|
43429
|
+
for (const sheet of workbook.sheets) {
|
|
43430
|
+
for (const cell of sheet.cells.values()) {
|
|
43431
|
+
if (cell.error) continue;
|
|
43432
|
+
if (cell.formula && typeof cell.value === "string") continue;
|
|
43433
|
+
if (typeof cell.value === "string") {
|
|
43434
|
+
totalCount++;
|
|
43435
|
+
if (!index.has(cell.value)) {
|
|
43436
|
+
index.set(cell.value, strings.length);
|
|
43437
|
+
strings.push(cell.value);
|
|
43438
|
+
if (cell.richText && cell.richText.length > 0) {
|
|
43439
|
+
richTextMap.set(cell.value, cell.richText);
|
|
43440
|
+
}
|
|
43441
|
+
}
|
|
43442
|
+
}
|
|
43443
|
+
}
|
|
42643
43444
|
}
|
|
42644
|
-
|
|
42645
|
-
|
|
42646
|
-
|
|
42647
|
-
|
|
42648
|
-
return /^[A-Za-z_][A-Za-z0-9_]*$/.test(name) ? name : `'${name.replace(/'/g, "''")}'`;
|
|
42649
|
-
}
|
|
42650
|
-
function buildWorkbookXml(workbook, pivotInfo) {
|
|
42651
|
-
const sheets = workbook.sheets.map(
|
|
42652
|
-
(s, i2) => `<sheet name="${escapeXml(s.name)}" sheetId="${i2 + 1}" r:id="rId${i2 + 1}"/>`
|
|
42653
|
-
).join("\n");
|
|
42654
|
-
const nameEntries = [];
|
|
42655
|
-
for (const [name, value] of workbook.namedRanges) {
|
|
42656
|
-
nameEntries.push(`<definedName name="${escapeXml(name)}">${escapeXml(value)}</definedName>`);
|
|
42657
|
-
}
|
|
42658
|
-
workbook.sheets.forEach((s, i2) => {
|
|
42659
|
-
const pt = s.printTitles;
|
|
42660
|
-
if (!pt || !pt.repeatRows && !pt.repeatCols) return;
|
|
42661
|
-
const parts = [];
|
|
42662
|
-
const sheetName = quoteSheetName(s.name);
|
|
42663
|
-
if (pt.repeatCols) {
|
|
42664
|
-
const [start, end] = pt.repeatCols;
|
|
42665
|
-
parts.push(`${sheetName}!$${colNumToLetters(start)}:$${colNumToLetters(end)}`);
|
|
42666
|
-
}
|
|
42667
|
-
if (pt.repeatRows) {
|
|
42668
|
-
const [start, end] = pt.repeatRows;
|
|
42669
|
-
parts.push(`${sheetName}!$${start}:$${end}`);
|
|
43445
|
+
const siEntries = strings.map((s) => {
|
|
43446
|
+
const richText = richTextMap.get(s);
|
|
43447
|
+
if (richText) {
|
|
43448
|
+
return `<si>${richText.map((part) => buildRichTextRun(part)).join("")}</si>`;
|
|
42670
43449
|
}
|
|
42671
|
-
|
|
42672
|
-
|
|
42673
|
-
)
|
|
43450
|
+
const needsPreserve = s.length === 0 || s !== s.trim();
|
|
43451
|
+
const spaceAttr = needsPreserve ? ' xml:space="preserve"' : "";
|
|
43452
|
+
return `<si><t${spaceAttr}>${escapeXml(s)}</t></si>`;
|
|
42674
43453
|
});
|
|
42675
|
-
const
|
|
42676
|
-
<
|
|
42677
|
-
${
|
|
42678
|
-
</
|
|
42679
|
-
|
|
42680
|
-
if (pivotInfo && pivotInfo.cachesByWorkbook.size > 0) {
|
|
42681
|
-
const baseRId = workbook.sheets.length + 3;
|
|
42682
|
-
const cacheIds = [...pivotInfo.cachesByWorkbook.keys()].sort((a, b) => a - b);
|
|
42683
|
-
const items = cacheIds.map((cacheId, i2) => `<pivotCache cacheId="${cacheId}" r:id="rId${baseRId + i2}"/>`).join("\n");
|
|
42684
|
-
pivotCachesBlock = `
|
|
42685
|
-
<pivotCaches>
|
|
42686
|
-
${items}
|
|
42687
|
-
</pivotCaches>`;
|
|
42688
|
-
}
|
|
42689
|
-
return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
42690
|
-
<workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"
|
|
42691
|
-
xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
|
|
42692
|
-
<bookViews>
|
|
42693
|
-
<workbookView activeTab="${workbook.activeSheetIndex}"/>
|
|
42694
|
-
</bookViews>
|
|
42695
|
-
<sheets>
|
|
42696
|
-
${sheets}
|
|
42697
|
-
</sheets>${definedNames}${pivotCachesBlock}
|
|
42698
|
-
<calcPr fullCalcOnLoad="1"/>
|
|
42699
|
-
</workbook>`;
|
|
43454
|
+
const xml = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
43455
|
+
<sst xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" count="${totalCount}" uniqueCount="${strings.length}">
|
|
43456
|
+
${siEntries.join("\n")}
|
|
43457
|
+
</sst>`;
|
|
43458
|
+
return { xml, index };
|
|
42700
43459
|
}
|
|
42701
|
-
function
|
|
42702
|
-
const
|
|
42703
|
-
|
|
42704
|
-
)
|
|
42705
|
-
|
|
42706
|
-
rels.push(`<Relationship Id="rId${workbook.sheets.length + 2}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings" Target="sharedStrings.xml"/>`);
|
|
42707
|
-
if (pivotInfo && pivotInfo.cachesByWorkbook.size > 0) {
|
|
42708
|
-
const baseRId = workbook.sheets.length + 3;
|
|
42709
|
-
const cacheIds = [...pivotInfo.cachesByWorkbook.keys()].sort((a, b) => a - b);
|
|
42710
|
-
cacheIds.forEach((cacheId, i2) => {
|
|
42711
|
-
const target = pivotInfo.cachesByWorkbook.get(cacheId);
|
|
42712
|
-
if (!target) return;
|
|
42713
|
-
rels.push(
|
|
42714
|
-
`<Relationship Id="rId${baseRId + i2}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/pivotCacheDefinition" Target="${escapeXml(target)}"/>`
|
|
42715
|
-
);
|
|
42716
|
-
});
|
|
43460
|
+
function buildRichTextRun(part) {
|
|
43461
|
+
const needsPreserve = part.text.length === 0 || part.text !== part.text.trim();
|
|
43462
|
+
const spaceAttr = needsPreserve ? ' xml:space="preserve"' : "";
|
|
43463
|
+
if (!part.font) {
|
|
43464
|
+
return `<r><t${spaceAttr}>${escapeXml(part.text)}</t></r>`;
|
|
42717
43465
|
}
|
|
42718
|
-
return
|
|
42719
|
-
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
|
|
42720
|
-
${rels.join("\n")}
|
|
42721
|
-
</Relationships>`;
|
|
42722
|
-
}
|
|
42723
|
-
function buildContentTypes(sheetCount, extraTypes = []) {
|
|
42724
|
-
const sheetTypes = Array.from(
|
|
42725
|
-
{ length: sheetCount },
|
|
42726
|
-
(_, i2) => `<Override PartName="/xl/worksheets/sheet${i2 + 1}.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"/>`
|
|
42727
|
-
).join("\n");
|
|
42728
|
-
return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
42729
|
-
<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
|
|
42730
|
-
<Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>
|
|
42731
|
-
<Default Extension="xml" ContentType="application/xml"/>
|
|
42732
|
-
<Default Extension="png" ContentType="image/png"/>
|
|
42733
|
-
<Default Extension="jpeg" ContentType="image/jpeg"/>
|
|
42734
|
-
<Default Extension="jpg" ContentType="image/jpeg"/>
|
|
42735
|
-
<Default Extension="gif" ContentType="image/gif"/>
|
|
42736
|
-
<Override PartName="/xl/workbook.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"/>
|
|
42737
|
-
${sheetTypes}
|
|
42738
|
-
<Override PartName="/xl/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml"/>
|
|
42739
|
-
<Override PartName="/xl/sharedStrings.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml"/>
|
|
42740
|
-
<Override PartName="/docProps/core.xml" ContentType="application/vnd.openxmlformats-package.core-properties+xml"/>
|
|
42741
|
-
<Override PartName="/docProps/app.xml" ContentType="application/vnd.openxmlformats-officedocument.extended-properties+xml"/>
|
|
42742
|
-
${extraTypes.join("\n")}
|
|
42743
|
-
</Types>`;
|
|
42744
|
-
}
|
|
42745
|
-
function buildRootRels() {
|
|
42746
|
-
return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
42747
|
-
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
|
|
42748
|
-
<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="xl/workbook.xml"/>
|
|
42749
|
-
<Relationship Id="rId2" Type="http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties" Target="docProps/core.xml"/>
|
|
42750
|
-
<Relationship Id="rId3" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties" Target="docProps/app.xml"/>
|
|
42751
|
-
</Relationships>`;
|
|
42752
|
-
}
|
|
42753
|
-
function buildCoreProps() {
|
|
42754
|
-
const now = (/* @__PURE__ */ new Date()).toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
42755
|
-
return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
42756
|
-
<cp:coreProperties xmlns:cp="http://schemas.openxmlformats.org/package/2006/metadata/core-properties"
|
|
42757
|
-
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
|
42758
|
-
xmlns:dcterms="http://purl.org/dc/terms/"
|
|
42759
|
-
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
|
42760
|
-
<dcterms:created xsi:type="dcterms:W3CDTF">${now}</dcterms:created>
|
|
42761
|
-
<dcterms:modified xsi:type="dcterms:W3CDTF">${now}</dcterms:modified>
|
|
42762
|
-
</cp:coreProperties>`;
|
|
42763
|
-
}
|
|
42764
|
-
function buildAppProps() {
|
|
42765
|
-
return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
42766
|
-
<Properties xmlns="http://schemas.openxmlformats.org/officeDocument/2006/extended-properties">
|
|
42767
|
-
<Application>Microsoft Excel</Application>
|
|
42768
|
-
</Properties>`;
|
|
43466
|
+
return `<r>${buildRichTextRunProps(part.font)}<t${spaceAttr}>${escapeXml(part.text)}</t></r>`;
|
|
42769
43467
|
}
|
|
42770
|
-
|
|
42771
|
-
|
|
42772
|
-
|
|
42773
|
-
|
|
42774
|
-
|
|
42775
|
-
|
|
42776
|
-
|
|
42777
|
-
|
|
42778
|
-
|
|
42779
|
-
|
|
42780
|
-
|
|
42781
|
-
surface: "c:surfaceChart"
|
|
42782
|
-
};
|
|
42783
|
-
function buildSeriesXml(s, idx, chartType, categories) {
|
|
42784
|
-
let nameXml = "";
|
|
42785
|
-
if (s.name) nameXml = `<c:tx><c:strRef><c:strCache><c:ptCount val="1"/><c:pt idx="0"><c:v>${escapeXml(s.name)}</c:v></c:pt></c:strCache></c:strRef></c:tx>`;
|
|
42786
|
-
let colorXml = "";
|
|
42787
|
-
if (s.color) colorXml = `<c:spPr><a:solidFill><a:srgbClr val="${hexToOoxmlRgb(s.color)}"/></a:solidFill></c:spPr>`;
|
|
42788
|
-
const valTag = chartType === "scatter" || chartType === "bubble" ? "c:yVal" : "c:val";
|
|
42789
|
-
const valPts = s.values.map((v, i2) => `<c:pt idx="${i2}"><c:v>${v}</c:v></c:pt>`).join("");
|
|
42790
|
-
const valXml = `<${valTag}><c:numRef><c:numCache><c:ptCount val="${s.values.length}"/>${valPts}</c:numCache></c:numRef></${valTag}>`;
|
|
42791
|
-
let catXml = "";
|
|
42792
|
-
if (categories && categories.length > 0) {
|
|
42793
|
-
const catTag = chartType === "scatter" || chartType === "bubble" ? "c:xVal" : "c:cat";
|
|
42794
|
-
const catPts = categories.map((c, i2) => `<c:pt idx="${i2}"><c:v>${escapeXml(c)}</c:v></c:pt>`).join("");
|
|
42795
|
-
catXml = `<${catTag}><c:strRef><c:strCache><c:ptCount val="${categories.length}"/>${catPts}</c:strCache></c:strRef></${catTag}>`;
|
|
42796
|
-
}
|
|
42797
|
-
let bubbleXml = "";
|
|
42798
|
-
if (s.bubbleSizes) {
|
|
42799
|
-
const bPts = s.bubbleSizes.map((v, i2) => `<c:pt idx="${i2}"><c:v>${v}</c:v></c:pt>`).join("");
|
|
42800
|
-
bubbleXml = `<c:bubbleSize><c:numRef><c:numCache><c:ptCount val="${s.bubbleSizes.length}"/>${bPts}</c:numCache></c:numRef></c:bubbleSize>`;
|
|
42801
|
-
}
|
|
42802
|
-
return `<c:ser><c:idx val="${idx}"/><c:order val="${idx}"/>${nameXml}${colorXml}${catXml}${valXml}${bubbleXml}</c:ser>`;
|
|
43468
|
+
function buildRichTextRunProps(font) {
|
|
43469
|
+
let parts = "";
|
|
43470
|
+
if (font.bold) parts += "<b/>";
|
|
43471
|
+
if (font.italic) parts += "<i/>";
|
|
43472
|
+
if (font.strike) parts += "<strike/>";
|
|
43473
|
+
if (font.underline) parts += `<u val="${font.underline}"/>`;
|
|
43474
|
+
if (font.vertAlign) parts += `<vertAlign val="${font.vertAlign}"/>`;
|
|
43475
|
+
if (font.size) parts += `<sz val="${font.size}"/>`;
|
|
43476
|
+
if (font.color) parts += `<color rgb="${hexToArgb(font.color)}"/>`;
|
|
43477
|
+
if (font.name) parts += `<rFont val="${escapeXml(font.name)}"/>`;
|
|
43478
|
+
return `<rPr>${parts}</rPr>`;
|
|
42803
43479
|
}
|
|
42804
|
-
function
|
|
42805
|
-
const
|
|
42806
|
-
|
|
42807
|
-
|
|
42808
|
-
if (chartTag === "c:barChart") {
|
|
42809
|
-
barDir = isBar ? '<c:barDir val="bar"/>' : '<c:barDir val="col"/>';
|
|
43480
|
+
function buildStylesXml(workbook) {
|
|
43481
|
+
const styles = [];
|
|
43482
|
+
for (let i2 = 0; i2 < workbook.styles.size; i2++) {
|
|
43483
|
+
styles.push(workbook.styles.get(i2));
|
|
42810
43484
|
}
|
|
42811
|
-
|
|
42812
|
-
|
|
42813
|
-
|
|
42814
|
-
|
|
42815
|
-
|
|
43485
|
+
const numFmtMap = /* @__PURE__ */ new Map();
|
|
43486
|
+
let nextNumFmtId = 164;
|
|
43487
|
+
for (const sheet of workbook.sheets) {
|
|
43488
|
+
for (const cell of sheet.cells.values()) {
|
|
43489
|
+
if (cell.numFmtCode && cell.numFmtCode !== "General" && cell.numFmtCode !== "") {
|
|
43490
|
+
if (!numFmtMap.has(cell.numFmtCode)) {
|
|
43491
|
+
numFmtMap.set(cell.numFmtCode, nextNumFmtId++);
|
|
43492
|
+
}
|
|
43493
|
+
}
|
|
43494
|
+
}
|
|
42816
43495
|
}
|
|
42817
|
-
const
|
|
42818
|
-
|
|
42819
|
-
|
|
42820
|
-
|
|
42821
|
-
|
|
42822
|
-
|
|
42823
|
-
if (chart.chartType === "combo") {
|
|
42824
|
-
const groups = /* @__PURE__ */ new Map();
|
|
42825
|
-
chart.series.forEach((s, idx) => {
|
|
42826
|
-
const sType = s.seriesChartType ?? "col";
|
|
42827
|
-
let group = groups.get(sType);
|
|
42828
|
-
if (!group) {
|
|
42829
|
-
group = [];
|
|
42830
|
-
groups.set(sType, group);
|
|
43496
|
+
const cellNumFmtIds = /* @__PURE__ */ new Map();
|
|
43497
|
+
for (let si = 0; si < workbook.sheets.length; si++) {
|
|
43498
|
+
for (const [ref, cell] of workbook.sheets[si].cells) {
|
|
43499
|
+
if (cell.numFmtCode && cell.numFmtCode !== "General" && cell.numFmtCode !== "") {
|
|
43500
|
+
const id = numFmtMap.get(cell.numFmtCode);
|
|
43501
|
+
if (id !== void 0) cellNumFmtIds.set(`${si}:${ref}`, id);
|
|
42831
43502
|
}
|
|
42832
|
-
group.push({ series: s, idx });
|
|
42833
|
-
});
|
|
42834
|
-
let chartElements = "";
|
|
42835
|
-
for (const [groupType, groupSeries] of groups) {
|
|
42836
|
-
const groupSeriesXml = groupSeries.map(
|
|
42837
|
-
({ series, idx }) => buildSeriesXml(series, idx, groupType, chart.categories)
|
|
42838
|
-
).join("");
|
|
42839
|
-
chartElements += buildChartTypeElement(groupType, groupSeriesXml, true);
|
|
42840
43503
|
}
|
|
42841
|
-
plotArea = `<c:plotArea><c:layout/>${chartElements}`;
|
|
42842
|
-
} else {
|
|
42843
|
-
const seriesXml = chart.series.map(
|
|
42844
|
-
(s, idx) => buildSeriesXml(s, idx, chart.chartType, chart.categories)
|
|
42845
|
-
).join("");
|
|
42846
|
-
plotArea = `<c:plotArea><c:layout/>${buildChartTypeElement(chart.chartType, seriesXml, needsAxIds)}`;
|
|
42847
43504
|
}
|
|
42848
|
-
|
|
42849
|
-
|
|
42850
|
-
|
|
42851
|
-
|
|
42852
|
-
|
|
42853
|
-
|
|
42854
|
-
|
|
42855
|
-
|
|
42856
|
-
|
|
42857
|
-
|
|
42858
|
-
|
|
42859
|
-
|
|
42860
|
-
|
|
42861
|
-
|
|
42862
|
-
|
|
42863
|
-
|
|
42864
|
-
|
|
42865
|
-
|
|
42866
|
-
|
|
42867
|
-
|
|
43505
|
+
const fonts = /* @__PURE__ */ new Map();
|
|
43506
|
+
const fontList = [];
|
|
43507
|
+
fonts.set("default", 0);
|
|
43508
|
+
fontList.push({});
|
|
43509
|
+
for (const s of styles) {
|
|
43510
|
+
const key = fontKey(s);
|
|
43511
|
+
if (!fonts.has(key)) {
|
|
43512
|
+
fonts.set(key, fontList.length);
|
|
43513
|
+
fontList.push(s);
|
|
43514
|
+
}
|
|
43515
|
+
}
|
|
43516
|
+
const fillEntries = [];
|
|
43517
|
+
const fillMap = /* @__PURE__ */ new Map();
|
|
43518
|
+
fillEntries.push('<fill><patternFill patternType="none"/></fill>');
|
|
43519
|
+
fillEntries.push('<fill><patternFill patternType="gray125"/></fill>');
|
|
43520
|
+
fillMap.set("", 0);
|
|
43521
|
+
for (const s of styles) {
|
|
43522
|
+
const fk = fillKey(s);
|
|
43523
|
+
if (fk === "" || fillMap.has(fk)) continue;
|
|
43524
|
+
fillMap.set(fk, fillEntries.length);
|
|
43525
|
+
fillEntries.push(buildFillXml(s));
|
|
43526
|
+
}
|
|
43527
|
+
const borderEntries = [];
|
|
43528
|
+
const borderMap = /* @__PURE__ */ new Map();
|
|
43529
|
+
borderEntries.push("<border><left/><right/><top/><bottom/><diagonal/></border>");
|
|
43530
|
+
borderMap.set("", 0);
|
|
43531
|
+
for (const s of styles) {
|
|
43532
|
+
const bk = borderKey(s);
|
|
43533
|
+
if (bk === "" || borderMap.has(bk)) continue;
|
|
43534
|
+
borderMap.set(bk, borderEntries.length);
|
|
43535
|
+
borderEntries.push(buildBorderXml(s));
|
|
43536
|
+
}
|
|
43537
|
+
const fontsXml = fontList.map((f) => buildFontXml(f)).join("\n");
|
|
43538
|
+
const fillsXml = fillEntries.join("\n");
|
|
43539
|
+
const bordersXml = borderEntries.join("\n");
|
|
43540
|
+
let numFmtsXml = "";
|
|
43541
|
+
if (numFmtMap.size > 0) {
|
|
43542
|
+
const entries = Array.from(numFmtMap.entries()).map(([code, id]) => `<numFmt numFmtId="${id}" formatCode="${escapeXml(code)}"/>`).join("\n");
|
|
43543
|
+
numFmtsXml = `<numFmts count="${numFmtMap.size}">
|
|
43544
|
+
${entries}
|
|
43545
|
+
</numFmts>
|
|
43546
|
+
`;
|
|
43547
|
+
}
|
|
43548
|
+
const xfEntries = [];
|
|
43549
|
+
const xfMap = /* @__PURE__ */ new Map();
|
|
43550
|
+
for (let styleIdx = 0; styleIdx < styles.length; styleIdx++) {
|
|
43551
|
+
const s = styles[styleIdx];
|
|
43552
|
+
const fontId = fonts.get(fontKey(s)) ?? 0;
|
|
43553
|
+
const fillId = fillMap.get(fillKey(s)) ?? 0;
|
|
43554
|
+
const borderId = borderMap.get(borderKey(s)) ?? 0;
|
|
43555
|
+
const xfKey = `${styleIdx}:0`;
|
|
43556
|
+
xfMap.set(xfKey, xfEntries.length);
|
|
43557
|
+
xfEntries.push(buildXfXml(s, fontId, fillId, borderId, 0));
|
|
43558
|
+
}
|
|
43559
|
+
for (const [cellKey2, numFmtId] of cellNumFmtIds) {
|
|
43560
|
+
const [siStr, ref] = cellKey2.split(":");
|
|
43561
|
+
const cell = workbook.sheets[parseInt(siStr)].cells.get(ref);
|
|
43562
|
+
if (!cell) continue;
|
|
43563
|
+
const xfKey = `${cell.styleIndex}:${numFmtId}`;
|
|
43564
|
+
if (xfMap.has(xfKey)) continue;
|
|
43565
|
+
const s = styles[cell.styleIndex] ?? {};
|
|
43566
|
+
const fontId = fonts.get(fontKey(s)) ?? 0;
|
|
43567
|
+
const fillId = fillMap.get(fillKey(s)) ?? 0;
|
|
43568
|
+
const borderId = borderMap.get(borderKey(s)) ?? 0;
|
|
43569
|
+
xfMap.set(xfKey, xfEntries.length);
|
|
43570
|
+
xfEntries.push(buildXfXml(s, fontId, fillId, borderId, numFmtId));
|
|
43571
|
+
}
|
|
43572
|
+
const dxfEntries = [];
|
|
43573
|
+
const dxfMap = /* @__PURE__ */ new Map();
|
|
43574
|
+
for (const sheet of workbook.sheets) {
|
|
43575
|
+
for (const cf of sheet.conditionalFormats) {
|
|
43576
|
+
for (const rule of cf.rules) {
|
|
43577
|
+
if (rule.ruleType === "style" && rule.style) {
|
|
43578
|
+
const key = JSON.stringify(rule.style);
|
|
43579
|
+
if (!dxfMap.has(key)) {
|
|
43580
|
+
dxfMap.set(key, dxfEntries.length);
|
|
43581
|
+
dxfEntries.push(buildDxfXml(rule.style));
|
|
43582
|
+
}
|
|
43583
|
+
}
|
|
42868
43584
|
}
|
|
42869
|
-
let titleXml2 = "";
|
|
42870
|
-
if (ax.title) titleXml2 = `<c:title><c:tx><c:rich><a:bodyPr/><a:lstStyle/><a:p><a:r><a:t>${escapeXml(ax.title)}</a:t></a:r></a:p></c:rich></c:tx></c:title>`;
|
|
42871
|
-
let scalingXml = '<c:scaling><c:orientation val="minMax"/>';
|
|
42872
|
-
if (ax.min !== void 0) scalingXml += `<c:min val="${ax.min}"/>`;
|
|
42873
|
-
if (ax.max !== void 0) scalingXml += `<c:max val="${ax.max}"/>`;
|
|
42874
|
-
scalingXml += "</c:scaling>";
|
|
42875
|
-
const numFmt = ax.numFmt ? `<c:numFmt formatCode="${escapeXml(ax.numFmt)}" sourceLinked="0"/>` : "";
|
|
42876
|
-
plotArea += `<${axTag}><c:axId val="${axId}"/>${scalingXml}${titleXml2}${numFmt}<c:crossAx val="${crossId}"/></${axTag}>`;
|
|
42877
43585
|
}
|
|
42878
43586
|
}
|
|
42879
|
-
|
|
42880
|
-
|
|
42881
|
-
|
|
42882
|
-
|
|
43587
|
+
let dxfsXml = '<dxfs count="0"/>';
|
|
43588
|
+
if (dxfEntries.length > 0) {
|
|
43589
|
+
dxfsXml = `<dxfs count="${dxfEntries.length}">
|
|
43590
|
+
${dxfEntries.join("\n")}
|
|
43591
|
+
</dxfs>`;
|
|
42883
43592
|
}
|
|
42884
|
-
|
|
42885
|
-
|
|
42886
|
-
|
|
42887
|
-
|
|
43593
|
+
const xml = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
43594
|
+
<styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
|
|
43595
|
+
${numFmtsXml}<fonts count="${fontList.length}">
|
|
43596
|
+
${fontsXml}
|
|
43597
|
+
</fonts>
|
|
43598
|
+
<fills count="${fillEntries.length}">
|
|
43599
|
+
${fillsXml}
|
|
43600
|
+
</fills>
|
|
43601
|
+
<borders count="${borderEntries.length}">
|
|
43602
|
+
${bordersXml}
|
|
43603
|
+
</borders>
|
|
43604
|
+
<cellStyleXfs count="1">
|
|
43605
|
+
<xf numFmtId="0" fontId="0" fillId="0" borderId="0"/>
|
|
43606
|
+
</cellStyleXfs>
|
|
43607
|
+
<cellXfs count="${xfEntries.length}">
|
|
43608
|
+
${xfEntries.join("\n")}
|
|
43609
|
+
</cellXfs>
|
|
43610
|
+
<cellStyles count="1">
|
|
43611
|
+
<cellStyle name="Normal" xfId="0" builtinId="0"/>
|
|
43612
|
+
</cellStyles>
|
|
43613
|
+
${dxfsXml}
|
|
43614
|
+
</styleSheet>`;
|
|
43615
|
+
return { xml, xfMap, numFmtMap, dxfMap };
|
|
43616
|
+
}
|
|
43617
|
+
function buildXfXml(s, fontId, fillId, borderId, numFmtId) {
|
|
43618
|
+
let attrs = `numFmtId="${numFmtId}" fontId="${fontId}" fillId="${fillId}" borderId="${borderId}" xfId="0"`;
|
|
43619
|
+
if (numFmtId > 0) attrs += ' applyNumberFormat="1"';
|
|
43620
|
+
if (fontId > 0) attrs += ' applyFont="1"';
|
|
43621
|
+
if (fillId > 0) attrs += ' applyFill="1"';
|
|
43622
|
+
if (borderId > 0) attrs += ' applyBorder="1"';
|
|
43623
|
+
if (s.horizontalAlign || s.verticalAlign || s.wrapText || s.indent || s.textRotation || s.shrinkToFit) {
|
|
43624
|
+
const hAlign = s.horizontalAlign ? ` horizontal="${s.horizontalAlign}"` : "";
|
|
43625
|
+
const vAlign = s.verticalAlign ? ` vertical="${s.verticalAlign}"` : "";
|
|
43626
|
+
const wrap = s.wrapText ? ' wrapText="1"' : "";
|
|
43627
|
+
const indent = s.indent ? ` indent="${s.indent}"` : "";
|
|
43628
|
+
const rotation = s.textRotation !== void 0 ? ` textRotation="${s.textRotation === "vertical" ? 255 : s.textRotation}"` : "";
|
|
43629
|
+
const shrink = s.shrinkToFit ? ' shrinkToFit="1"' : "";
|
|
43630
|
+
return `<xf ${attrs} applyAlignment="1"><alignment${hAlign}${vAlign}${wrap}${indent}${rotation}${shrink}/></xf>`;
|
|
42888
43631
|
}
|
|
42889
|
-
return
|
|
42890
|
-
<c:chartSpace xmlns:c="http://schemas.openxmlformats.org/drawingml/2006/chart" xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
|
|
42891
|
-
<c:chart>${titleXml}${plotArea}${legendXml}</c:chart>
|
|
42892
|
-
</c:chartSpace>`;
|
|
43632
|
+
return `<xf ${attrs}/>`;
|
|
42893
43633
|
}
|
|
42894
|
-
function
|
|
42895
|
-
return
|
|
43634
|
+
function fontKey(s) {
|
|
43635
|
+
return `${s.fontName ?? ""}|${s.fontSize ?? 0}|${s.fontBold ? 1 : 0}|${s.fontItalic ? 1 : 0}|${s.fontColor ?? ""}|${s.fontUnderline ?? ""}|${s.fontStrike ? 1 : 0}`;
|
|
42896
43636
|
}
|
|
42897
|
-
function
|
|
42898
|
-
|
|
42899
|
-
|
|
42900
|
-
|
|
42901
|
-
|
|
42902
|
-
|
|
42903
|
-
|
|
42904
|
-
|
|
42905
|
-
|
|
42906
|
-
|
|
42907
|
-
|
|
43637
|
+
function buildFontXml(s) {
|
|
43638
|
+
let parts = "";
|
|
43639
|
+
if (s.fontBold) parts += "<b/>";
|
|
43640
|
+
if (s.fontItalic) parts += "<i/>";
|
|
43641
|
+
if (s.fontStrike) parts += "<strike/>";
|
|
43642
|
+
if (s.fontUnderline) parts += `<u val="${s.fontUnderline}"/>`;
|
|
43643
|
+
parts += `<sz val="${s.fontSize ?? 11}"/>`;
|
|
43644
|
+
if (s.fontColor) {
|
|
43645
|
+
parts += `<color rgb="${hexToArgb(s.fontColor)}"/>`;
|
|
43646
|
+
} else {
|
|
43647
|
+
parts += '<color theme="1"/>';
|
|
43648
|
+
}
|
|
43649
|
+
parts += `<name val="${escapeXml(s.fontName ?? "Calibri")}"/>`;
|
|
43650
|
+
return `<font>${parts}</font>`;
|
|
42908
43651
|
}
|
|
42909
|
-
function
|
|
42910
|
-
|
|
42911
|
-
|
|
42912
|
-
|
|
42913
|
-
|
|
42914
|
-
|
|
42915
|
-
|
|
42916
|
-
|
|
42917
|
-
|
|
42918
|
-
|
|
42919
|
-
</xdr:twoCellAnchor>`;
|
|
43652
|
+
function borderKey(s) {
|
|
43653
|
+
const parts = [];
|
|
43654
|
+
if (s.borderTop) parts.push(`t:${s.borderTop.style}:${s.borderTop.width}:${s.borderTop.color ?? ""}`);
|
|
43655
|
+
if (s.borderRight) parts.push(`r:${s.borderRight.style}:${s.borderRight.width}:${s.borderRight.color ?? ""}`);
|
|
43656
|
+
if (s.borderBottom) parts.push(`b:${s.borderBottom.style}:${s.borderBottom.width}:${s.borderBottom.color ?? ""}`);
|
|
43657
|
+
if (s.borderLeft) parts.push(`l:${s.borderLeft.style}:${s.borderLeft.width}:${s.borderLeft.color ?? ""}`);
|
|
43658
|
+
if (s.borderDiagonal) parts.push(`d:${s.borderDiagonal.style}:${s.borderDiagonal.width}:${s.borderDiagonal.color ?? ""}`);
|
|
43659
|
+
if (s.diagonalUp) parts.push("du");
|
|
43660
|
+
if (s.diagonalDown) parts.push("dd");
|
|
43661
|
+
return parts.join("|");
|
|
42920
43662
|
}
|
|
42921
|
-
function
|
|
42922
|
-
|
|
42923
|
-
|
|
42924
|
-
|
|
42925
|
-
|
|
42926
|
-
|
|
42927
|
-
|
|
43663
|
+
function toOoxmlBorderStyle(border2) {
|
|
43664
|
+
const ooxmlStyles = [
|
|
43665
|
+
"thin",
|
|
43666
|
+
"medium",
|
|
43667
|
+
"thick",
|
|
43668
|
+
"dotted",
|
|
43669
|
+
"dashed",
|
|
43670
|
+
"double",
|
|
43671
|
+
"hair",
|
|
43672
|
+
"mediumDashed",
|
|
43673
|
+
"dashDot",
|
|
43674
|
+
"mediumDashDot",
|
|
43675
|
+
"dashDotDot",
|
|
43676
|
+
"mediumDashDotDot",
|
|
43677
|
+
"slantDashDot"
|
|
43678
|
+
];
|
|
43679
|
+
if (ooxmlStyles.includes(border2.style)) return border2.style;
|
|
43680
|
+
if (border2.style === "solid") {
|
|
43681
|
+
if (border2.width <= 1) return "thin";
|
|
43682
|
+
if (border2.width <= 2) return "medium";
|
|
43683
|
+
return "thick";
|
|
42928
43684
|
}
|
|
42929
|
-
|
|
42930
|
-
|
|
42931
|
-
if (
|
|
42932
|
-
return
|
|
42933
|
-
<xdr:from>${buildAnchorPosition(drawing.anchor.from)}</xdr:from>
|
|
42934
|
-
<xdr:to>${buildAnchorPosition(drawing.anchor.to)}</xdr:to>
|
|
42935
|
-
<xdr:sp><xdr:nvSpPr><xdr:cNvPr id="0" name="Shape"/><xdr:cNvSpPr/></xdr:nvSpPr>
|
|
42936
|
-
<xdr:spPr><a:xfrm><a:off x="0" y="0"/><a:ext cx="0" cy="0"/></a:xfrm><a:prstGeom prst="${geom}"><a:avLst/></a:prstGeom>${fillXml}${outlineXml}</xdr:spPr>
|
|
42937
|
-
${textXml}</xdr:sp>
|
|
42938
|
-
<xdr:clientData/>
|
|
42939
|
-
</xdr:twoCellAnchor>`;
|
|
43685
|
+
if (border2.style === "dashed") return "dashed";
|
|
43686
|
+
if (border2.style === "dotted") return "dotted";
|
|
43687
|
+
if (border2.style === "double") return "double";
|
|
43688
|
+
return "thin";
|
|
42940
43689
|
}
|
|
42941
|
-
function
|
|
42942
|
-
|
|
42943
|
-
|
|
42944
|
-
|
|
42945
|
-
|
|
42946
|
-
|
|
43690
|
+
function buildBorderXml(s) {
|
|
43691
|
+
let attrs = "";
|
|
43692
|
+
if (s.diagonalUp) attrs += ' diagonalUp="1"';
|
|
43693
|
+
if (s.diagonalDown) attrs += ' diagonalDown="1"';
|
|
43694
|
+
const sides = [
|
|
43695
|
+
{ tag: "left", border: s.borderLeft },
|
|
43696
|
+
{ tag: "right", border: s.borderRight },
|
|
43697
|
+
{ tag: "top", border: s.borderTop },
|
|
43698
|
+
{ tag: "bottom", border: s.borderBottom },
|
|
43699
|
+
{ tag: "diagonal", border: s.borderDiagonal }
|
|
43700
|
+
];
|
|
43701
|
+
const inner = sides.map(({ tag, border: border2 }) => {
|
|
43702
|
+
if (!border2) return `<${tag}/>`;
|
|
43703
|
+
const ooxmlStyle = toOoxmlBorderStyle(border2);
|
|
43704
|
+
let colorXml = "";
|
|
43705
|
+
if (border2.color) {
|
|
43706
|
+
colorXml = `<color rgb="${hexToArgb(border2.color)}"/>`;
|
|
43707
|
+
}
|
|
43708
|
+
return `<${tag} style="${ooxmlStyle}">${colorXml}</${tag}>`;
|
|
42947
43709
|
}).join("");
|
|
42948
|
-
|
|
42949
|
-
const styleName = table.styleName ?? "TableStyleMedium2";
|
|
42950
|
-
return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
42951
|
-
<table xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" id="${tableId}" name="${escapeXml(table.name)}" displayName="${escapeXml(table.displayName)}" ref="${escapeXml(table.ref)}" totalsRowCount="${table.totalsRow ? 1 : 0}">
|
|
42952
|
-
${autoFilterXml}
|
|
42953
|
-
<tableColumns count="${table.columns.length}">${colsXml}</tableColumns>
|
|
42954
|
-
<tableStyleInfo name="${escapeXml(styleName)}" showFirstColumn="0" showLastColumn="0" showRowStripes="1" showColumnStripes="0"/>
|
|
42955
|
-
</table>`;
|
|
43710
|
+
return `<border${attrs}>${inner}</border>`;
|
|
42956
43711
|
}
|
|
42957
|
-
function
|
|
42958
|
-
|
|
42959
|
-
|
|
42960
|
-
|
|
42961
|
-
|
|
42962
|
-
|
|
42963
|
-
|
|
42964
|
-
|
|
42965
|
-
|
|
42966
|
-
|
|
42967
|
-
|
|
42968
|
-
|
|
42969
|
-
|
|
42970
|
-
|
|
42971
|
-
|
|
42972
|
-
|
|
42973
|
-
|
|
42974
|
-
|
|
42975
|
-
|
|
42976
|
-
|
|
42977
|
-
|
|
42978
|
-
|
|
43712
|
+
function fillKey(s) {
|
|
43713
|
+
if (s.gradientData) return `gradient:${JSON.stringify(s.gradientData)}`;
|
|
43714
|
+
if (s.patternType && s.backgroundPattern) return `pattern:${s.patternType}|${s.backgroundPattern}`;
|
|
43715
|
+
if (s.backgroundColor) return `solid:${s.backgroundColor}`;
|
|
43716
|
+
return "";
|
|
43717
|
+
}
|
|
43718
|
+
function buildFillXml(s) {
|
|
43719
|
+
if (s.gradientData) {
|
|
43720
|
+
const g = s.gradientData;
|
|
43721
|
+
const stops = g.stops.map((stop) => {
|
|
43722
|
+
const hex = hexToArgb(stop.color);
|
|
43723
|
+
return `<stop position="${stop.position}"><color rgb="${hex}"/></stop>`;
|
|
43724
|
+
}).join("");
|
|
43725
|
+
if (g.type === "radial") {
|
|
43726
|
+
return `<fill><gradientFill type="path" left="0.5" right="0.5" top="0.5" bottom="0.5">${stops}</gradientFill></fill>`;
|
|
43727
|
+
}
|
|
43728
|
+
return `<fill><gradientFill degree="${g.degree}">${stops}</gradientFill></fill>`;
|
|
43729
|
+
}
|
|
43730
|
+
if (s.patternType && s.backgroundPattern) {
|
|
43731
|
+
const colors = extractFillColors(s.backgroundPattern);
|
|
43732
|
+
let colorAttrs = "";
|
|
43733
|
+
if (colors.fg) colorAttrs += `<fgColor rgb="${hexToArgb(colors.fg)}"/>`;
|
|
43734
|
+
if (colors.bg) colorAttrs += `<bgColor rgb="${hexToArgb(colors.bg)}"/>`;
|
|
43735
|
+
return `<fill><patternFill patternType="${escapeXml(s.patternType)}">${colorAttrs}</patternFill></fill>`;
|
|
43736
|
+
}
|
|
43737
|
+
return `<fill><patternFill patternType="solid"><fgColor rgb="${hexToArgb(s.backgroundColor)}"/></patternFill></fill>`;
|
|
43738
|
+
}
|
|
43739
|
+
function extractFillColors(css) {
|
|
43740
|
+
const colorMatches = css.match(/rgba?\([^)]+\)/g);
|
|
43741
|
+
if (colorMatches) {
|
|
43742
|
+
return { fg: colorMatches[0], bg: colorMatches[1] };
|
|
43743
|
+
}
|
|
43744
|
+
const hexMatches = css.match(/#[0-9a-fA-F]{6}/g);
|
|
43745
|
+
if (hexMatches) {
|
|
43746
|
+
return { fg: hexMatches[0], bg: hexMatches[1] };
|
|
43747
|
+
}
|
|
43748
|
+
return { fg: void 0, bg: void 0 };
|
|
43749
|
+
}
|
|
43750
|
+
function buildSheetXml(sheet, styles, ssIndex, isActive, xfMap, numFmtMap, dxfMap, drawingRId, tableRIds, hyperlinkRIds) {
|
|
43751
|
+
const rows = [];
|
|
43752
|
+
const rowMap = /* @__PURE__ */ new Map();
|
|
43753
|
+
for (const [ref, cell] of sheet.cells) {
|
|
43754
|
+
const rc = refToRowCol(ref);
|
|
43755
|
+
if (!rc) continue;
|
|
43756
|
+
let arr = rowMap.get(rc.row);
|
|
43757
|
+
if (!arr) {
|
|
43758
|
+
arr = [];
|
|
43759
|
+
rowMap.set(rc.row, arr);
|
|
43760
|
+
}
|
|
43761
|
+
arr.push({ col: rc.col, cell });
|
|
43762
|
+
}
|
|
43763
|
+
const sortedRows = Array.from(rowMap.keys()).sort((a, b) => a - b);
|
|
43764
|
+
for (const rowNum of sortedRows) {
|
|
43765
|
+
const cells = rowMap.get(rowNum);
|
|
43766
|
+
cells.sort((a, b) => a.col - b.col);
|
|
43767
|
+
const h = sheet.rowHeights.get(rowNum);
|
|
43768
|
+
const rowAttrs = h ? ` ht="${h}" customHeight="1"` : "";
|
|
43769
|
+
const hidden = sheet.hiddenRows.has(rowNum) ? ' hidden="1"' : "";
|
|
43770
|
+
const cellsXml = cells.map(({ col, cell }) => {
|
|
43771
|
+
const ref = rowColToRef(rowNum, col);
|
|
43772
|
+
const type = getCellType(cell, ssIndex);
|
|
43773
|
+
const value = getCellValue(cell, ssIndex);
|
|
43774
|
+
let attrs = `r="${ref}"`;
|
|
43775
|
+
let xfIndex = 0;
|
|
43776
|
+
if (xfMap.size === 0 && cell.originalXfIndex !== void 0) {
|
|
43777
|
+
xfIndex = cell.originalXfIndex;
|
|
43778
|
+
} else {
|
|
43779
|
+
const numFmtId = cell.numFmtCode && cell.numFmtCode !== "General" && cell.numFmtCode !== "" ? numFmtMap.get(cell.numFmtCode) ?? 0 : 0;
|
|
43780
|
+
const xfKey = `${cell.styleIndex}:${numFmtId}`;
|
|
43781
|
+
xfIndex = xfMap.get(xfKey) ?? 0;
|
|
42979
43782
|
}
|
|
42980
|
-
|
|
42981
|
-
|
|
42982
|
-
|
|
42983
|
-
|
|
42984
|
-
|
|
42985
|
-
|
|
42986
|
-
|
|
42987
|
-
|
|
42988
|
-
if (rule.rank !== void 0) attrs += ` rank="${rule.rank}"`;
|
|
42989
|
-
if (rule.percent) attrs += ' percent="1"';
|
|
42990
|
-
if (rule.bottom) attrs += ' bottom="1"';
|
|
42991
|
-
if (rule.aboveAverage === false) attrs += ' aboveAverage="0"';
|
|
42992
|
-
if (rule.timePeriod) attrs += ` timePeriod="${rule.timePeriod}"`;
|
|
42993
|
-
let inner = "";
|
|
42994
|
-
if (rule.formulae) {
|
|
42995
|
-
inner = rule.formulae.map((f) => `<formula>${escapeXml(String(f))}</formula>`).join("");
|
|
43783
|
+
if (xfIndex > 0) attrs += ` s="${xfIndex}"`;
|
|
43784
|
+
if (type) attrs += ` t="${type}"`;
|
|
43785
|
+
let inner = "";
|
|
43786
|
+
if (cell.formula) {
|
|
43787
|
+
if (cell.isArrayFormula && cell.arrayRange) {
|
|
43788
|
+
inner += `<f t="array" ref="${cell.arrayRange}">${escapeXml(cell.formula)}</f>`;
|
|
43789
|
+
} else {
|
|
43790
|
+
inner += `<f>${escapeXml(cell.formula)}</f>`;
|
|
42996
43791
|
}
|
|
42997
|
-
return `<cfRule ${attrs}>${inner}</cfRule>`;
|
|
42998
43792
|
}
|
|
43793
|
+
if (value !== void 0) inner += `<v>${escapeXml(String(value))}</v>`;
|
|
43794
|
+
return `<c ${attrs}>${inner}</c>`;
|
|
43795
|
+
}).join("");
|
|
43796
|
+
rows.push(`<row r="${rowNum}"${rowAttrs}${hidden}>${cellsXml}</row>`);
|
|
43797
|
+
}
|
|
43798
|
+
const cols = [];
|
|
43799
|
+
const allCols = /* @__PURE__ */ new Set([...sheet.colWidths.keys(), ...sheet.hiddenCols]);
|
|
43800
|
+
for (const c of Array.from(allCols).sort((a, b) => a - b)) {
|
|
43801
|
+
const w = sheet.colWidths.get(c) ?? sheet.defaultColWidth;
|
|
43802
|
+
const hidden = sheet.hiddenCols.has(c) ? ' hidden="1"' : "";
|
|
43803
|
+
cols.push(`<col min="${c}" max="${c}" width="${w}" customWidth="1"${hidden}/>`);
|
|
43804
|
+
}
|
|
43805
|
+
let mergeXml = "";
|
|
43806
|
+
if (sheet.mergedCells.length > 0) {
|
|
43807
|
+
const merges = sheet.mergedCells.map((r) => `<mergeCell ref="${r}"/>`).join("");
|
|
43808
|
+
mergeXml = `<mergeCells count="${sheet.mergedCells.length}">${merges}</mergeCells>`;
|
|
43809
|
+
}
|
|
43810
|
+
let paneXml = "";
|
|
43811
|
+
let selectionXml = `<selection activeCell="A1" sqref="A1"/>`;
|
|
43812
|
+
if (sheet.freeze) {
|
|
43813
|
+
const activePane = sheet.freeze.col > 0 && sheet.freeze.row > 0 ? "bottomRight" : sheet.freeze.row > 0 ? "bottomLeft" : "topRight";
|
|
43814
|
+
const topLeft = rowColToRef(sheet.freeze.row + 1, sheet.freeze.col + 1);
|
|
43815
|
+
paneXml = `<pane xSplit="${sheet.freeze.col}" ySplit="${sheet.freeze.row}" topLeftCell="${topLeft}" activePane="${activePane}" state="frozen"/>`;
|
|
43816
|
+
selectionXml = `<selection pane="${activePane}" activeCell="${topLeft}" sqref="${topLeft}"/>`;
|
|
43817
|
+
}
|
|
43818
|
+
const tabSelected = isActive ? ' tabSelected="1"' : "";
|
|
43819
|
+
const sheetView = `<sheetView${tabSelected} workbookViewId="0"${!sheet.view.showGridLines ? ' showGridLines="0"' : ""}>${paneXml}${selectionXml}</sheetView>`;
|
|
43820
|
+
let autoFilterXml = "";
|
|
43821
|
+
if (sheet.autoFilter) {
|
|
43822
|
+
let filterCols = "";
|
|
43823
|
+
for (const col of sheet.autoFilter.columns) {
|
|
43824
|
+
if (col.filterValues && col.filterValues.length > 0) {
|
|
43825
|
+
const filters = col.filterValues.map((v) => `<filter val="${escapeXml(v)}"/>`).join("");
|
|
43826
|
+
filterCols += `<filterColumn colId="${col.colIndex}"><filters>${filters}</filters></filterColumn>`;
|
|
43827
|
+
}
|
|
43828
|
+
}
|
|
43829
|
+
autoFilterXml = `<autoFilter ref="${sheet.autoFilter.ref}">${filterCols}</autoFilter>`;
|
|
43830
|
+
}
|
|
43831
|
+
let dvXml = "";
|
|
43832
|
+
if (sheet.dataValidations.length > 0) {
|
|
43833
|
+
const dvEntries = sheet.dataValidations.map((dv) => {
|
|
43834
|
+
let attrs = `sqref="${dv.ref}" type="${dv.type}"`;
|
|
43835
|
+
if (dv.operator) attrs += ` operator="${dv.operator}"`;
|
|
43836
|
+
if (!dv.showDropdown) attrs += ' showDropDown="1"';
|
|
43837
|
+
if (dv.errorStyle) attrs += ` errorStyle="${dv.errorStyle}"`;
|
|
43838
|
+
if (dv.errorTitle) attrs += ` errorTitle="${escapeXml(dv.errorTitle)}"`;
|
|
43839
|
+
if (dv.errorMessage) attrs += ` error="${escapeXml(dv.errorMessage)}"`;
|
|
43840
|
+
if (dv.promptTitle) attrs += ` promptTitle="${escapeXml(dv.promptTitle)}"`;
|
|
43841
|
+
if (dv.promptMessage) attrs += ` prompt="${escapeXml(dv.promptMessage)}"`;
|
|
43842
|
+
let inner = "";
|
|
43843
|
+
if (dv.formula1) inner += `<formula1>${escapeXml(dv.formula1)}</formula1>`;
|
|
43844
|
+
if (dv.formula2) inner += `<formula2>${escapeXml(dv.formula2)}</formula2>`;
|
|
43845
|
+
return `<dataValidation ${attrs}>${inner}</dataValidation>`;
|
|
43846
|
+
}).join("");
|
|
43847
|
+
dvXml = `<dataValidations count="${sheet.dataValidations.length}">${dvEntries}</dataValidations>`;
|
|
43848
|
+
}
|
|
43849
|
+
let cfXml = "";
|
|
43850
|
+
if (sheet.conditionalFormats.length > 0) {
|
|
43851
|
+
cfXml = sheet.conditionalFormats.map((cf) => buildConditionalFormattingXml(cf, dxfMap)).join("");
|
|
43852
|
+
}
|
|
43853
|
+
let hyperlinksXml = "";
|
|
43854
|
+
if (hyperlinkRIds && hyperlinkRIds.size > 0) {
|
|
43855
|
+
const hlEntries = Array.from(hyperlinkRIds.entries()).map(([ref, rId]) => `<hyperlink ref="${ref}" r:id="${rId}"/>`).join("");
|
|
43856
|
+
hyperlinksXml = `<hyperlinks>${hlEntries}</hyperlinks>`;
|
|
43857
|
+
}
|
|
43858
|
+
const drawingXml = drawingRId ? `<drawing r:id="${drawingRId}"/>` : "";
|
|
43859
|
+
let tablePartsXml = "";
|
|
43860
|
+
if (tableRIds && tableRIds.length > 0) {
|
|
43861
|
+
const parts = tableRIds.map((rId) => `<tablePart r:id="${rId}"/>`).join("");
|
|
43862
|
+
tablePartsXml = `<tableParts count="${tableRIds.length}">${parts}</tableParts>`;
|
|
43863
|
+
}
|
|
43864
|
+
const ps = sheet.pageSetup;
|
|
43865
|
+
const hf = sheet.headerFooter;
|
|
43866
|
+
const fitToPage = ps && (ps.fitToWidth !== void 0 || ps.fitToHeight !== void 0);
|
|
43867
|
+
const sheetPrXml = fitToPage ? `<sheetPr><pageSetUpPr fitToPage="1"/></sheetPr>` : "";
|
|
43868
|
+
const marginsXml = (() => {
|
|
43869
|
+
const m = ps?.margins;
|
|
43870
|
+
const left = m?.left ?? 0.7;
|
|
43871
|
+
const right = m?.right ?? 0.7;
|
|
43872
|
+
const top = m?.top ?? 0.75;
|
|
43873
|
+
const bottom = m?.bottom ?? 0.75;
|
|
43874
|
+
const header = m?.header ?? 0.3;
|
|
43875
|
+
const footer = m?.footer ?? 0.3;
|
|
43876
|
+
return `<pageMargins left="${left}" right="${right}" top="${top}" bottom="${bottom}" header="${header}" footer="${footer}"/>`;
|
|
43877
|
+
})();
|
|
43878
|
+
let pageSetupXml = "";
|
|
43879
|
+
if (ps) {
|
|
43880
|
+
const attrs = [];
|
|
43881
|
+
if (ps.paperSize !== void 0) attrs.push(`paperSize="${ps.paperSize}"`);
|
|
43882
|
+
if (ps.scale !== void 0) attrs.push(`scale="${ps.scale}"`);
|
|
43883
|
+
if (ps.fitToWidth !== void 0) attrs.push(`fitToWidth="${ps.fitToWidth}"`);
|
|
43884
|
+
if (ps.fitToHeight !== void 0) attrs.push(`fitToHeight="${ps.fitToHeight}"`);
|
|
43885
|
+
if (ps.orientation) attrs.push(`orientation="${ps.orientation}"`);
|
|
43886
|
+
if (attrs.length > 0) pageSetupXml = `<pageSetup ${attrs.join(" ")}/>`;
|
|
43887
|
+
}
|
|
43888
|
+
let headerFooterXml = "";
|
|
43889
|
+
if (hf) {
|
|
43890
|
+
const rootAttrs = [];
|
|
43891
|
+
if (hf.differentOddEven) rootAttrs.push(`differentOddEven="1"`);
|
|
43892
|
+
if (hf.differentFirst) rootAttrs.push(`differentFirst="1"`);
|
|
43893
|
+
const inner = [];
|
|
43894
|
+
if (hf.oddHeader) inner.push(`<oddHeader>${escapeXml(hf.oddHeader)}</oddHeader>`);
|
|
43895
|
+
if (hf.oddFooter) inner.push(`<oddFooter>${escapeXml(hf.oddFooter)}</oddFooter>`);
|
|
43896
|
+
if (hf.evenHeader) inner.push(`<evenHeader>${escapeXml(hf.evenHeader)}</evenHeader>`);
|
|
43897
|
+
if (hf.evenFooter) inner.push(`<evenFooter>${escapeXml(hf.evenFooter)}</evenFooter>`);
|
|
43898
|
+
if (hf.firstHeader) inner.push(`<firstHeader>${escapeXml(hf.firstHeader)}</firstHeader>`);
|
|
43899
|
+
if (hf.firstFooter) inner.push(`<firstFooter>${escapeXml(hf.firstFooter)}</firstFooter>`);
|
|
43900
|
+
if (inner.length > 0) {
|
|
43901
|
+
const attrStr = rootAttrs.length > 0 ? ` ${rootAttrs.join(" ")}` : "";
|
|
43902
|
+
headerFooterXml = `<headerFooter${attrStr}>${inner.join("")}</headerFooter>`;
|
|
42999
43903
|
}
|
|
43000
|
-
}).join("");
|
|
43001
|
-
return `<conditionalFormatting sqref="${cf.ref}">${rules}</conditionalFormatting>`;
|
|
43002
|
-
}
|
|
43003
|
-
function buildDxfXml(style) {
|
|
43004
|
-
let inner = "";
|
|
43005
|
-
if (style.fontBold || style.fontItalic || style.fontColor) {
|
|
43006
|
-
let fontParts = "";
|
|
43007
|
-
if (style.fontBold) fontParts += "<b/>";
|
|
43008
|
-
if (style.fontItalic) fontParts += "<i/>";
|
|
43009
|
-
if (style.fontColor) fontParts += `<color rgb="${hexToArgb(style.fontColor)}"/>`;
|
|
43010
|
-
inner += `<font>${fontParts}</font>`;
|
|
43011
43904
|
}
|
|
43012
|
-
|
|
43013
|
-
|
|
43905
|
+
let dimensionRef = "A1";
|
|
43906
|
+
if (sortedRows.length > 0) {
|
|
43907
|
+
let minCol = Infinity, maxCol = 0;
|
|
43908
|
+
const minRow = sortedRows[0];
|
|
43909
|
+
const maxRow = sortedRows[sortedRows.length - 1];
|
|
43910
|
+
for (const rowNum of sortedRows) {
|
|
43911
|
+
const cells = rowMap.get(rowNum);
|
|
43912
|
+
for (const { col } of cells) {
|
|
43913
|
+
if (col < minCol) minCol = col;
|
|
43914
|
+
if (col > maxCol) maxCol = col;
|
|
43915
|
+
}
|
|
43916
|
+
}
|
|
43917
|
+
dimensionRef = `${rowColToRef(minRow, minCol)}:${rowColToRef(maxRow, maxCol)}`;
|
|
43014
43918
|
}
|
|
43015
|
-
return
|
|
43016
|
-
|
|
43017
|
-
|
|
43018
|
-
|
|
43019
|
-
|
|
43020
|
-
|
|
43021
|
-
|
|
43022
|
-
|
|
43023
|
-
|
|
43024
|
-
|
|
43025
|
-
|
|
43026
|
-
|
|
43027
|
-
const bytes = new Uint8Array(binary.length);
|
|
43028
|
-
for (let i2 = 0; i2 < binary.length; i2++) bytes[i2] = binary.charCodeAt(i2);
|
|
43029
|
-
return bytes;
|
|
43919
|
+
return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
43920
|
+
<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"
|
|
43921
|
+
xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
|
|
43922
|
+
${sheetPrXml}<dimension ref="${dimensionRef}"/>
|
|
43923
|
+
<sheetViews>${sheetView}</sheetViews>
|
|
43924
|
+
<sheetFormatPr defaultRowHeight="${sheet.defaultRowHeight}" defaultColWidth="${sheet.defaultColWidth}"/>
|
|
43925
|
+
${cols.length > 0 ? `<cols>${cols.join("")}</cols>` : ""}
|
|
43926
|
+
<sheetData>
|
|
43927
|
+
${rows.join("\n")}
|
|
43928
|
+
</sheetData>
|
|
43929
|
+
${autoFilterXml}${mergeXml}${cfXml}${dvXml}${hyperlinksXml}${marginsXml}${pageSetupXml}${headerFooterXml}${drawingXml}${tablePartsXml}
|
|
43930
|
+
</worksheet>`;
|
|
43030
43931
|
}
|
|
43031
|
-
function
|
|
43032
|
-
|
|
43932
|
+
function getCellType(cell, ssIndex) {
|
|
43933
|
+
if (cell.error) return "e";
|
|
43934
|
+
if (cell.formula && typeof cell.value === "string") return "str";
|
|
43935
|
+
if (typeof cell.value === "string" && ssIndex.has(cell.value)) return "s";
|
|
43936
|
+
if (typeof cell.value === "boolean") return "b";
|
|
43937
|
+
return void 0;
|
|
43033
43938
|
}
|
|
43034
|
-
|
|
43035
|
-
|
|
43036
|
-
|
|
43037
|
-
|
|
43939
|
+
function getCellValue(cell, ssIndex) {
|
|
43940
|
+
if (cell.value === null) return void 0;
|
|
43941
|
+
if (cell.error) return cell.error;
|
|
43942
|
+
if (cell.formula && typeof cell.value === "string") return cell.value;
|
|
43943
|
+
if (typeof cell.value === "string") {
|
|
43944
|
+
const idx = ssIndex.get(cell.value);
|
|
43945
|
+
return idx !== void 0 ? idx : cell.value;
|
|
43946
|
+
}
|
|
43947
|
+
if (typeof cell.value === "boolean") return cell.value ? 1 : 0;
|
|
43948
|
+
return cell.value;
|
|
43038
43949
|
}
|
|
43039
|
-
function
|
|
43040
|
-
|
|
43041
|
-
return { borderTop: b, borderRight: b, borderBottom: b, borderLeft: b };
|
|
43950
|
+
function quoteSheetName(name) {
|
|
43951
|
+
return /^[A-Za-z_][A-Za-z0-9_]*$/.test(name) ? name : `'${name.replace(/'/g, "''")}'`;
|
|
43042
43952
|
}
|
|
43043
|
-
|
|
43044
|
-
|
|
43045
|
-
|
|
43046
|
-
|
|
43047
|
-
const
|
|
43048
|
-
const
|
|
43049
|
-
|
|
43050
|
-
|
|
43051
|
-
|
|
43052
|
-
|
|
43053
|
-
|
|
43054
|
-
|
|
43055
|
-
|
|
43056
|
-
|
|
43057
|
-
|
|
43058
|
-
|
|
43059
|
-
bucket = [];
|
|
43060
|
-
groups.set(key, bucket);
|
|
43953
|
+
function buildWorkbookXml(workbook, pivotInfo) {
|
|
43954
|
+
const sheets = workbook.sheets.map(
|
|
43955
|
+
(s, i2) => `<sheet name="${escapeXml(s.name)}" sheetId="${i2 + 1}" r:id="rId${i2 + 1}"/>`
|
|
43956
|
+
).join("\n");
|
|
43957
|
+
const nameEntries = [];
|
|
43958
|
+
for (const [name, value] of workbook.namedRanges) {
|
|
43959
|
+
nameEntries.push(`<definedName name="${escapeXml(name)}">${escapeXml(value)}</definedName>`);
|
|
43960
|
+
}
|
|
43961
|
+
workbook.sheets.forEach((s, i2) => {
|
|
43962
|
+
const pt = s.printTitles;
|
|
43963
|
+
if (!pt || !pt.repeatRows && !pt.repeatCols) return;
|
|
43964
|
+
const parts = [];
|
|
43965
|
+
const sheetName = quoteSheetName(s.name);
|
|
43966
|
+
if (pt.repeatCols) {
|
|
43967
|
+
const [start, end] = pt.repeatCols;
|
|
43968
|
+
parts.push(`${sheetName}!$${colNumToLetters(start)}:$${colNumToLetters(end)}`);
|
|
43061
43969
|
}
|
|
43062
|
-
|
|
43970
|
+
if (pt.repeatRows) {
|
|
43971
|
+
const [start, end] = pt.repeatRows;
|
|
43972
|
+
parts.push(`${sheetName}!$${start}:$${end}`);
|
|
43973
|
+
}
|
|
43974
|
+
nameEntries.push(
|
|
43975
|
+
`<definedName name="_xlnm.Print_Titles" localSheetId="${i2}">${escapeXml(parts.join(","))}</definedName>`
|
|
43976
|
+
);
|
|
43977
|
+
});
|
|
43978
|
+
const definedNames = nameEntries.length > 0 ? `
|
|
43979
|
+
<definedNames>
|
|
43980
|
+
${nameEntries.join("\n")}
|
|
43981
|
+
</definedNames>` : "";
|
|
43982
|
+
let pivotCachesBlock = "";
|
|
43983
|
+
if (pivotInfo && pivotInfo.cachesByWorkbook.size > 0) {
|
|
43984
|
+
const baseRId = workbook.sheets.length + 3;
|
|
43985
|
+
const cacheIds = [...pivotInfo.cachesByWorkbook.keys()].sort((a, b) => a - b);
|
|
43986
|
+
const items = cacheIds.map((cacheId, i2) => `<pivotCache cacheId="${cacheId}" r:id="rId${baseRId + i2}"/>`).join("\n");
|
|
43987
|
+
pivotCachesBlock = `
|
|
43988
|
+
<pivotCaches>
|
|
43989
|
+
${items}
|
|
43990
|
+
</pivotCaches>`;
|
|
43063
43991
|
}
|
|
43064
|
-
return
|
|
43992
|
+
return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
43993
|
+
<workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"
|
|
43994
|
+
xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
|
|
43995
|
+
<bookViews>
|
|
43996
|
+
<workbookView activeTab="${workbook.activeSheetIndex}"/>
|
|
43997
|
+
</bookViews>
|
|
43998
|
+
<sheets>
|
|
43999
|
+
${sheets}
|
|
44000
|
+
</sheets>${definedNames}${pivotCachesBlock}
|
|
44001
|
+
<calcPr fullCalcOnLoad="1"/>
|
|
44002
|
+
</workbook>`;
|
|
43065
44003
|
}
|
|
43066
|
-
function
|
|
43067
|
-
const
|
|
43068
|
-
|
|
43069
|
-
const cfg = table.fields[fi];
|
|
43070
|
-
if (cfg?.selectedPageItem == null) continue;
|
|
43071
|
-
const cacheField = cache.fields[fi];
|
|
43072
|
-
if (!cacheField) continue;
|
|
43073
|
-
const allowed = cacheField.items[cfg.selectedPageItem];
|
|
43074
|
-
if (allowed) filters.push({ fieldIndex: fi, allowed });
|
|
43075
|
-
}
|
|
43076
|
-
if (filters.length === 0) return records;
|
|
43077
|
-
return records.filter(
|
|
43078
|
-
(rec) => filters.every(
|
|
43079
|
-
({ fieldIndex, allowed }) => cellMatchesItem(rec[fieldIndex], allowed)
|
|
43080
|
-
)
|
|
44004
|
+
function buildWorkbookRels(workbook, pivotInfo) {
|
|
44005
|
+
const rels = workbook.sheets.map(
|
|
44006
|
+
(_, i2) => `<Relationship Id="rId${i2 + 1}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet" Target="worksheets/sheet${i2 + 1}.xml"/>`
|
|
43081
44007
|
);
|
|
43082
|
-
}
|
|
43083
|
-
|
|
43084
|
-
|
|
43085
|
-
|
|
43086
|
-
|
|
43087
|
-
|
|
43088
|
-
|
|
43089
|
-
|
|
43090
|
-
|
|
43091
|
-
|
|
43092
|
-
|
|
43093
|
-
|
|
43094
|
-
return cell === void 0 || cell === null || cell === "";
|
|
43095
|
-
case "error":
|
|
43096
|
-
return typeof cell === "string" && cell === item.value;
|
|
44008
|
+
rels.push(`<Relationship Id="rId${workbook.sheets.length + 1}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" Target="styles.xml"/>`);
|
|
44009
|
+
rels.push(`<Relationship Id="rId${workbook.sheets.length + 2}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings" Target="sharedStrings.xml"/>`);
|
|
44010
|
+
if (pivotInfo && pivotInfo.cachesByWorkbook.size > 0) {
|
|
44011
|
+
const baseRId = workbook.sheets.length + 3;
|
|
44012
|
+
const cacheIds = [...pivotInfo.cachesByWorkbook.keys()].sort((a, b) => a - b);
|
|
44013
|
+
cacheIds.forEach((cacheId, i2) => {
|
|
44014
|
+
const target = pivotInfo.cachesByWorkbook.get(cacheId);
|
|
44015
|
+
if (!target) return;
|
|
44016
|
+
rels.push(
|
|
44017
|
+
`<Relationship Id="rId${baseRId + i2}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/pivotCacheDefinition" Target="${escapeXml(target)}"/>`
|
|
44018
|
+
);
|
|
44019
|
+
});
|
|
43097
44020
|
}
|
|
44021
|
+
return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
44022
|
+
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
|
|
44023
|
+
${rels.join("\n")}
|
|
44024
|
+
</Relationships>`;
|
|
43098
44025
|
}
|
|
43099
|
-
function
|
|
43100
|
-
|
|
44026
|
+
function buildContentTypes(sheetCount, extraTypes = []) {
|
|
44027
|
+
const sheetTypes = Array.from(
|
|
44028
|
+
{ length: sheetCount },
|
|
44029
|
+
(_, i2) => `<Override PartName="/xl/worksheets/sheet${i2 + 1}.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"/>`
|
|
44030
|
+
).join("\n");
|
|
44031
|
+
return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
44032
|
+
<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
|
|
44033
|
+
<Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>
|
|
44034
|
+
<Default Extension="xml" ContentType="application/xml"/>
|
|
44035
|
+
<Default Extension="png" ContentType="image/png"/>
|
|
44036
|
+
<Default Extension="jpeg" ContentType="image/jpeg"/>
|
|
44037
|
+
<Default Extension="jpg" ContentType="image/jpeg"/>
|
|
44038
|
+
<Default Extension="gif" ContentType="image/gif"/>
|
|
44039
|
+
<Override PartName="/xl/workbook.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"/>
|
|
44040
|
+
${sheetTypes}
|
|
44041
|
+
<Override PartName="/xl/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml"/>
|
|
44042
|
+
<Override PartName="/xl/sharedStrings.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml"/>
|
|
44043
|
+
<Override PartName="/docProps/core.xml" ContentType="application/vnd.openxmlformats-package.core-properties+xml"/>
|
|
44044
|
+
<Override PartName="/docProps/app.xml" ContentType="application/vnd.openxmlformats-officedocument.extended-properties+xml"/>
|
|
44045
|
+
${extraTypes.join("\n")}
|
|
44046
|
+
</Types>`;
|
|
43101
44047
|
}
|
|
43102
|
-
function
|
|
43103
|
-
|
|
43104
|
-
|
|
43105
|
-
|
|
43106
|
-
|
|
43107
|
-
|
|
43108
|
-
|
|
43109
|
-
|
|
43110
|
-
|
|
43111
|
-
}
|
|
43112
|
-
|
|
43113
|
-
|
|
43114
|
-
|
|
43115
|
-
|
|
43116
|
-
|
|
43117
|
-
|
|
43118
|
-
|
|
43119
|
-
|
|
43120
|
-
if (as > bs) return 1;
|
|
43121
|
-
}
|
|
43122
|
-
return 0;
|
|
43123
|
-
});
|
|
43124
|
-
return out;
|
|
44048
|
+
function buildRootRels() {
|
|
44049
|
+
return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
44050
|
+
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
|
|
44051
|
+
<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="xl/workbook.xml"/>
|
|
44052
|
+
<Relationship Id="rId2" Type="http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties" Target="docProps/core.xml"/>
|
|
44053
|
+
<Relationship Id="rId3" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties" Target="docProps/app.xml"/>
|
|
44054
|
+
</Relationships>`;
|
|
44055
|
+
}
|
|
44056
|
+
function buildCoreProps() {
|
|
44057
|
+
const now = (/* @__PURE__ */ new Date()).toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
44058
|
+
return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
44059
|
+
<cp:coreProperties xmlns:cp="http://schemas.openxmlformats.org/package/2006/metadata/core-properties"
|
|
44060
|
+
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
|
44061
|
+
xmlns:dcterms="http://purl.org/dc/terms/"
|
|
44062
|
+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
|
44063
|
+
<dcterms:created xsi:type="dcterms:W3CDTF">${now}</dcterms:created>
|
|
44064
|
+
<dcterms:modified xsi:type="dcterms:W3CDTF">${now}</dcterms:modified>
|
|
44065
|
+
</cp:coreProperties>`;
|
|
43125
44066
|
}
|
|
43126
|
-
function
|
|
43127
|
-
|
|
43128
|
-
|
|
43129
|
-
|
|
43130
|
-
|
|
43131
|
-
case "countNums":
|
|
43132
|
-
return numeric.length;
|
|
43133
|
-
case "sum":
|
|
43134
|
-
return numeric.reduce((a, b) => a + b, 0);
|
|
43135
|
-
case "average":
|
|
43136
|
-
if (numeric.length === 0) return null;
|
|
43137
|
-
return numeric.reduce((a, b) => a + b, 0) / numeric.length;
|
|
43138
|
-
case "min":
|
|
43139
|
-
return numeric.length === 0 ? null : Math.min(...numeric);
|
|
43140
|
-
case "max":
|
|
43141
|
-
return numeric.length === 0 ? null : Math.max(...numeric);
|
|
43142
|
-
case "product":
|
|
43143
|
-
return numeric.length === 0 ? null : numeric.reduce((a, b) => a * b, 1);
|
|
43144
|
-
}
|
|
44067
|
+
function buildAppProps() {
|
|
44068
|
+
return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
44069
|
+
<Properties xmlns="http://schemas.openxmlformats.org/officeDocument/2006/extended-properties">
|
|
44070
|
+
<Application>Microsoft Excel</Application>
|
|
44071
|
+
</Properties>`;
|
|
43145
44072
|
}
|
|
43146
|
-
|
|
43147
|
-
|
|
43148
|
-
|
|
43149
|
-
|
|
43150
|
-
|
|
43151
|
-
|
|
43152
|
-
|
|
43153
|
-
|
|
43154
|
-
|
|
43155
|
-
|
|
43156
|
-
|
|
43157
|
-
|
|
43158
|
-
|
|
43159
|
-
|
|
43160
|
-
|
|
44073
|
+
var CHART_TYPE_MAP2 = {
|
|
44074
|
+
bar: "c:barChart",
|
|
44075
|
+
col: "c:barChart",
|
|
44076
|
+
line: "c:lineChart",
|
|
44077
|
+
pie: "c:pieChart",
|
|
44078
|
+
doughnut: "c:doughnutChart",
|
|
44079
|
+
area: "c:areaChart",
|
|
44080
|
+
scatter: "c:scatterChart",
|
|
44081
|
+
bubble: "c:bubbleChart",
|
|
44082
|
+
radar: "c:radarChart",
|
|
44083
|
+
stock: "c:stockChart",
|
|
44084
|
+
surface: "c:surfaceChart"
|
|
44085
|
+
};
|
|
44086
|
+
function buildSeriesXml(s, idx, chartType, categories) {
|
|
44087
|
+
let nameXml = "";
|
|
44088
|
+
if (s.name) nameXml = `<c:tx><c:strRef><c:strCache><c:ptCount val="1"/><c:pt idx="0"><c:v>${escapeXml(s.name)}</c:v></c:pt></c:strCache></c:strRef></c:tx>`;
|
|
44089
|
+
let colorXml = "";
|
|
44090
|
+
if (s.color) colorXml = `<c:spPr><a:solidFill><a:srgbClr val="${hexToOoxmlRgb(s.color)}"/></a:solidFill></c:spPr>`;
|
|
44091
|
+
const valTag = chartType === "scatter" || chartType === "bubble" ? "c:yVal" : "c:val";
|
|
44092
|
+
const valPts = s.values.map((v, i2) => `<c:pt idx="${i2}"><c:v>${v}</c:v></c:pt>`).join("");
|
|
44093
|
+
const valXml = `<${valTag}><c:numRef><c:numCache><c:ptCount val="${s.values.length}"/>${valPts}</c:numCache></c:numRef></${valTag}>`;
|
|
44094
|
+
let catXml = "";
|
|
44095
|
+
if (categories && categories.length > 0) {
|
|
44096
|
+
const catTag = chartType === "scatter" || chartType === "bubble" ? "c:xVal" : "c:cat";
|
|
44097
|
+
const catPts = categories.map((c, i2) => `<c:pt idx="${i2}"><c:v>${escapeXml(c)}</c:v></c:pt>`).join("");
|
|
44098
|
+
catXml = `<${catTag}><c:strRef><c:strCache><c:ptCount val="${categories.length}"/>${catPts}</c:strCache></c:strRef></${catTag}>`;
|
|
43161
44099
|
}
|
|
43162
|
-
|
|
43163
|
-
|
|
43164
|
-
|
|
43165
|
-
|
|
43166
|
-
for (let i2 = 0; i2 < numDataFields; i2++) {
|
|
43167
|
-
cells[level][col + i2] = { kind: "colHeader", depth: level, text };
|
|
43168
|
-
}
|
|
43169
|
-
col += numDataFields;
|
|
43170
|
-
}
|
|
44100
|
+
let bubbleXml = "";
|
|
44101
|
+
if (s.bubbleSizes) {
|
|
44102
|
+
const bPts = s.bubbleSizes.map((v, i2) => `<c:pt idx="${i2}"><c:v>${v}</c:v></c:pt>`).join("");
|
|
44103
|
+
bubbleXml = `<c:bubbleSize><c:numRef><c:numCache><c:ptCount val="${s.bubbleSizes.length}"/>${bPts}</c:numCache></c:numRef></c:bubbleSize>`;
|
|
43171
44104
|
}
|
|
43172
|
-
|
|
43173
|
-
|
|
43174
|
-
|
|
43175
|
-
|
|
43176
|
-
|
|
43177
|
-
|
|
43178
|
-
|
|
43179
|
-
|
|
43180
|
-
};
|
|
43181
|
-
}
|
|
43182
|
-
col += numDataFields;
|
|
43183
|
-
}
|
|
43184
|
-
if (showColGrand) {
|
|
43185
|
-
for (let d = 0; d < table.dataFields.length; d++) {
|
|
43186
|
-
cells[labelRow][rowLabelCols + dataCols + d] = {
|
|
43187
|
-
kind: "valueLabel",
|
|
43188
|
-
text: table.dataFields[d].name
|
|
43189
|
-
};
|
|
43190
|
-
}
|
|
43191
|
-
}
|
|
44105
|
+
return `<c:ser><c:idx val="${idx}"/><c:order val="${idx}"/>${nameXml}${colorXml}${catXml}${valXml}${bubbleXml}</c:ser>`;
|
|
44106
|
+
}
|
|
44107
|
+
function buildChartTypeElement(chartType, seriesXml, needsAxIds) {
|
|
44108
|
+
const chartTag = CHART_TYPE_MAP2[chartType] ?? "c:barChart";
|
|
44109
|
+
const isBar = chartType === "bar";
|
|
44110
|
+
let barDir = "";
|
|
44111
|
+
if (chartTag === "c:barChart") {
|
|
44112
|
+
barDir = isBar ? '<c:barDir val="bar"/>' : '<c:barDir val="col"/>';
|
|
43192
44113
|
}
|
|
43193
|
-
|
|
43194
|
-
|
|
43195
|
-
|
|
43196
|
-
|
|
43197
|
-
|
|
43198
|
-
kind: "rowHeader",
|
|
43199
|
-
depth: level,
|
|
43200
|
-
text: formatCellLabel(rowTuple[level])
|
|
43201
|
-
};
|
|
43202
|
-
}
|
|
43203
|
-
for (let c = 0; c < colTuples.length; c++) {
|
|
43204
|
-
const colTuple = colTuples[c];
|
|
43205
|
-
const groupRecords = groups.get(JSON.stringify([rowTuple, colTuple])) ?? [];
|
|
43206
|
-
for (let d = 0; d < table.dataFields.length; d++) {
|
|
43207
|
-
const df = table.dataFields[d];
|
|
43208
|
-
const values2 = groupRecords.map((rec) => rec[df.fieldIndex]);
|
|
43209
|
-
cells[gridRow][rowLabelCols + c * numDataFields + d] = {
|
|
43210
|
-
kind: "value",
|
|
43211
|
-
value: aggregate(values2, df.subtotal),
|
|
43212
|
-
numFmt: df.numFmt
|
|
43213
|
-
};
|
|
43214
|
-
}
|
|
43215
|
-
}
|
|
43216
|
-
if (showColGrand) {
|
|
43217
|
-
const rowOnly = allRecords.filter(
|
|
43218
|
-
(rec) => sameTuple(tupleOf(rec, table.rowFieldIndices), rowTuple)
|
|
43219
|
-
);
|
|
43220
|
-
for (let d = 0; d < table.dataFields.length; d++) {
|
|
43221
|
-
const df = table.dataFields[d];
|
|
43222
|
-
cells[gridRow][rowLabelCols + dataCols + d] = {
|
|
43223
|
-
kind: "rowTotal",
|
|
43224
|
-
value: aggregate(
|
|
43225
|
-
rowOnly.map((rec) => rec[df.fieldIndex]),
|
|
43226
|
-
df.subtotal
|
|
43227
|
-
)
|
|
43228
|
-
};
|
|
43229
|
-
}
|
|
43230
|
-
}
|
|
44114
|
+
let grouping = "";
|
|
44115
|
+
if (chartTag === "c:barChart") {
|
|
44116
|
+
grouping = '<c:grouping val="clustered"/>';
|
|
44117
|
+
} else if (chartTag === "c:lineChart" || chartTag === "c:areaChart") {
|
|
44118
|
+
grouping = '<c:grouping val="clustered"/>';
|
|
43231
44119
|
}
|
|
43232
|
-
|
|
43233
|
-
|
|
43234
|
-
|
|
43235
|
-
|
|
43236
|
-
|
|
43237
|
-
|
|
43238
|
-
|
|
43239
|
-
|
|
43240
|
-
|
|
43241
|
-
|
|
43242
|
-
|
|
43243
|
-
|
|
43244
|
-
|
|
43245
|
-
|
|
43246
|
-
df.subtotal
|
|
43247
|
-
)
|
|
43248
|
-
};
|
|
43249
|
-
}
|
|
43250
|
-
}
|
|
43251
|
-
if (showColGrand) {
|
|
43252
|
-
for (let d = 0; d < table.dataFields.length; d++) {
|
|
43253
|
-
const df = table.dataFields[d];
|
|
43254
|
-
cells[gridRow][rowLabelCols + dataCols + d] = {
|
|
43255
|
-
kind: "grandTotal",
|
|
43256
|
-
value: aggregate(
|
|
43257
|
-
allRecords.map((rec) => rec[df.fieldIndex]),
|
|
43258
|
-
df.subtotal
|
|
43259
|
-
)
|
|
43260
|
-
};
|
|
44120
|
+
const axIds = needsAxIds ? '<c:axId val="1"/><c:axId val="2"/>' : "";
|
|
44121
|
+
return `<${chartTag}>${barDir}${grouping}${seriesXml}${axIds}</${chartTag}>`;
|
|
44122
|
+
}
|
|
44123
|
+
function buildChartXml(chart) {
|
|
44124
|
+
const needsAxIds = chart.chartType !== "pie" && chart.chartType !== "doughnut";
|
|
44125
|
+
let plotArea;
|
|
44126
|
+
if (chart.chartType === "combo") {
|
|
44127
|
+
const groups = /* @__PURE__ */ new Map();
|
|
44128
|
+
chart.series.forEach((s, idx) => {
|
|
44129
|
+
const sType = s.seriesChartType ?? "col";
|
|
44130
|
+
let group = groups.get(sType);
|
|
44131
|
+
if (!group) {
|
|
44132
|
+
group = [];
|
|
44133
|
+
groups.set(sType, group);
|
|
43261
44134
|
}
|
|
44135
|
+
group.push({ series: s, idx });
|
|
44136
|
+
});
|
|
44137
|
+
let chartElements = "";
|
|
44138
|
+
for (const [groupType, groupSeries] of groups) {
|
|
44139
|
+
const groupSeriesXml = groupSeries.map(
|
|
44140
|
+
({ series, idx }) => buildSeriesXml(series, idx, groupType, chart.categories)
|
|
44141
|
+
).join("");
|
|
44142
|
+
chartElements += buildChartTypeElement(groupType, groupSeriesXml, true);
|
|
43262
44143
|
}
|
|
44144
|
+
plotArea = `<c:plotArea><c:layout/>${chartElements}`;
|
|
44145
|
+
} else {
|
|
44146
|
+
const seriesXml = chart.series.map(
|
|
44147
|
+
(s, idx) => buildSeriesXml(s, idx, chart.chartType, chart.categories)
|
|
44148
|
+
).join("");
|
|
44149
|
+
plotArea = `<c:plotArea><c:layout/>${buildChartTypeElement(chart.chartType, seriesXml, needsAxIds)}`;
|
|
43263
44150
|
}
|
|
43264
|
-
|
|
43265
|
-
|
|
43266
|
-
|
|
43267
|
-
|
|
43268
|
-
|
|
43269
|
-
|
|
43270
|
-
|
|
43271
|
-
|
|
43272
|
-
|
|
43273
|
-
|
|
43274
|
-
|
|
43275
|
-
|
|
43276
|
-
|
|
43277
|
-
|
|
43278
|
-
|
|
43279
|
-
|
|
44151
|
+
if (chart.chartType !== "pie" && chart.chartType !== "doughnut") {
|
|
44152
|
+
const axes = chart.axes ?? [{ type: "category" }, { type: "value" }];
|
|
44153
|
+
for (let i2 = 0; i2 < axes.length; i2++) {
|
|
44154
|
+
const ax = axes[i2];
|
|
44155
|
+
const axId = i2 + 1;
|
|
44156
|
+
const crossId = i2 === 0 ? 2 : 1;
|
|
44157
|
+
let axTag;
|
|
44158
|
+
switch (ax.type) {
|
|
44159
|
+
case "value":
|
|
44160
|
+
axTag = "c:valAx";
|
|
44161
|
+
break;
|
|
44162
|
+
case "date":
|
|
44163
|
+
axTag = "c:dateAx";
|
|
44164
|
+
break;
|
|
44165
|
+
case "series":
|
|
44166
|
+
axTag = "c:serAx";
|
|
44167
|
+
break;
|
|
44168
|
+
default:
|
|
44169
|
+
axTag = "c:catAx";
|
|
44170
|
+
break;
|
|
44171
|
+
}
|
|
44172
|
+
let titleXml2 = "";
|
|
44173
|
+
if (ax.title) titleXml2 = `<c:title><c:tx><c:rich><a:bodyPr/><a:lstStyle/><a:p><a:r><a:t>${escapeXml(ax.title)}</a:t></a:r></a:p></c:rich></c:tx></c:title>`;
|
|
44174
|
+
let scalingXml = '<c:scaling><c:orientation val="minMax"/>';
|
|
44175
|
+
if (ax.min !== void 0) scalingXml += `<c:min val="${ax.min}"/>`;
|
|
44176
|
+
if (ax.max !== void 0) scalingXml += `<c:max val="${ax.max}"/>`;
|
|
44177
|
+
scalingXml += "</c:scaling>";
|
|
44178
|
+
const numFmt = ax.numFmt ? `<c:numFmt formatCode="${escapeXml(ax.numFmt)}" sourceLinked="0"/>` : "";
|
|
44179
|
+
plotArea += `<${axTag}><c:axId val="${axId}"/>${scalingXml}${titleXml2}${numFmt}<c:crossAx val="${crossId}"/></${axTag}>`;
|
|
43280
44180
|
}
|
|
43281
44181
|
}
|
|
43282
|
-
|
|
44182
|
+
plotArea += "</c:plotArea>";
|
|
44183
|
+
let titleXml = "";
|
|
44184
|
+
if (chart.title) {
|
|
44185
|
+
titleXml = `<c:title><c:tx><c:rich><a:bodyPr/><a:lstStyle/><a:p><a:r><a:t>${escapeXml(chart.title)}</a:t></a:r></a:p></c:rich></c:tx></c:title>`;
|
|
44186
|
+
}
|
|
44187
|
+
let legendXml = "";
|
|
44188
|
+
if (chart.legendPosition && chart.legendPosition !== "none") {
|
|
44189
|
+
const posMap = { top: "t", bottom: "b", left: "l", right: "r" };
|
|
44190
|
+
legendXml = `<c:legend><c:legendPos val="${posMap[chart.legendPosition] ?? "b"}"/></c:legend>`;
|
|
44191
|
+
}
|
|
44192
|
+
return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
44193
|
+
<c:chartSpace xmlns:c="http://schemas.openxmlformats.org/drawingml/2006/chart" xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
|
|
44194
|
+
<c:chart>${titleXml}${plotArea}${legendXml}</c:chart>
|
|
44195
|
+
</c:chartSpace>`;
|
|
43283
44196
|
}
|
|
43284
|
-
function
|
|
43285
|
-
|
|
43286
|
-
if (typeof v === "boolean") return v ? "TRUE" : "FALSE";
|
|
43287
|
-
return String(v);
|
|
44197
|
+
function buildAnchorPosition(pos) {
|
|
44198
|
+
return `<xdr:col>${pos.col}</xdr:col><xdr:colOff>${pos.colOffset ?? 0}</xdr:colOff><xdr:row>${pos.row}</xdr:row><xdr:rowOff>${pos.rowOffset ?? 0}</xdr:rowOff>`;
|
|
43288
44199
|
}
|
|
43289
|
-
|
|
43290
|
-
|
|
43291
|
-
|
|
43292
|
-
|
|
43293
|
-
|
|
43294
|
-
|
|
44200
|
+
function buildChartAnchorXml(chart, rId) {
|
|
44201
|
+
return `<xdr:twoCellAnchor>
|
|
44202
|
+
<xdr:from>${buildAnchorPosition(chart.anchor.from)}</xdr:from>
|
|
44203
|
+
<xdr:to>${buildAnchorPosition(chart.anchor.to)}</xdr:to>
|
|
44204
|
+
<xdr:graphicFrame macro="">
|
|
44205
|
+
<xdr:nvGraphicFramePr><xdr:cNvPr id="0" name="Chart"/><xdr:cNvGraphicFramePr/></xdr:nvGraphicFramePr>
|
|
44206
|
+
<xdr:xfrm><a:off x="0" y="0"/><a:ext cx="0" cy="0"/></xdr:xfrm>
|
|
44207
|
+
<a:graphic><a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/chart"><c:chart xmlns:c="http://schemas.openxmlformats.org/drawingml/2006/chart" r:id="${rId}"/></a:graphicData></a:graphic>
|
|
44208
|
+
</xdr:graphicFrame>
|
|
44209
|
+
<xdr:clientData/>
|
|
44210
|
+
</xdr:twoCellAnchor>`;
|
|
44211
|
+
}
|
|
44212
|
+
function buildImageAnchorXml(image, rId) {
|
|
44213
|
+
return `<xdr:twoCellAnchor editAs="oneCell">
|
|
44214
|
+
<xdr:from>${buildAnchorPosition(image.tl)}</xdr:from>
|
|
44215
|
+
<xdr:to>${buildAnchorPosition(image.br)}</xdr:to>
|
|
44216
|
+
<xdr:pic>
|
|
44217
|
+
<xdr:nvPicPr><xdr:cNvPr id="0" name="Image"/><xdr:cNvPicPr/></xdr:nvPicPr>
|
|
44218
|
+
<xdr:blipFill><a:blip xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" r:embed="${rId}"/><a:stretch><a:fillRect/></a:stretch></xdr:blipFill>
|
|
44219
|
+
<xdr:spPr><a:prstGeom prst="rect"><a:avLst/></a:prstGeom></xdr:spPr>
|
|
44220
|
+
</xdr:pic>
|
|
44221
|
+
<xdr:clientData/>
|
|
44222
|
+
</xdr:twoCellAnchor>`;
|
|
44223
|
+
}
|
|
44224
|
+
function buildShapeAnchorXml(drawing) {
|
|
44225
|
+
let fillXml = "";
|
|
44226
|
+
if (drawing.fillColor) fillXml = `<a:solidFill><a:srgbClr val="${hexToOoxmlRgb(drawing.fillColor)}"/></a:solidFill>`;
|
|
44227
|
+
let outlineXml = "";
|
|
44228
|
+
if (drawing.outlineColor) {
|
|
44229
|
+
const w = Math.round((drawing.outlineWidth ?? 1) * 12700);
|
|
44230
|
+
outlineXml = `<a:ln w="${w}"><a:solidFill><a:srgbClr val="${hexToOoxmlRgb(drawing.outlineColor)}"/></a:solidFill></a:ln>`;
|
|
43295
44231
|
}
|
|
43296
|
-
|
|
43297
|
-
|
|
43298
|
-
|
|
43299
|
-
|
|
43300
|
-
|
|
43301
|
-
|
|
43302
|
-
|
|
43303
|
-
|
|
43304
|
-
|
|
43305
|
-
|
|
44232
|
+
const geom = drawing.geometry ?? "rect";
|
|
44233
|
+
let textXml = "";
|
|
44234
|
+
if (drawing.text) textXml = `<xdr:txBody><a:bodyPr/><a:lstStyle/><a:p><a:r><a:t>${escapeXml(drawing.text)}</a:t></a:r></a:p></xdr:txBody>`;
|
|
44235
|
+
return `<xdr:twoCellAnchor>
|
|
44236
|
+
<xdr:from>${buildAnchorPosition(drawing.anchor.from)}</xdr:from>
|
|
44237
|
+
<xdr:to>${buildAnchorPosition(drawing.anchor.to)}</xdr:to>
|
|
44238
|
+
<xdr:sp><xdr:nvSpPr><xdr:cNvPr id="0" name="Shape"/><xdr:cNvSpPr/></xdr:nvSpPr>
|
|
44239
|
+
<xdr:spPr><a:xfrm><a:off x="0" y="0"/><a:ext cx="0" cy="0"/></a:xfrm><a:prstGeom prst="${geom}"><a:avLst/></a:prstGeom>${fillXml}${outlineXml}</xdr:spPr>
|
|
44240
|
+
${textXml}</xdr:sp>
|
|
44241
|
+
<xdr:clientData/>
|
|
44242
|
+
</xdr:twoCellAnchor>`;
|
|
44243
|
+
}
|
|
44244
|
+
function buildTableXml(table, tableId) {
|
|
44245
|
+
const colsXml = table.columns.map((col) => {
|
|
44246
|
+
let inner = "";
|
|
44247
|
+
if (col.totalsFunction) inner += `<totalsRowFunction>${escapeXml(col.totalsFunction)}</totalsRowFunction>`;
|
|
44248
|
+
if (col.totalsFormula) inner += `<totalsRowFormula>${escapeXml(col.totalsFormula)}</totalsRowFormula>`;
|
|
44249
|
+
return `<tableColumn id="${col.id}" name="${escapeXml(col.name)}">${inner}</tableColumn>`;
|
|
44250
|
+
}).join("");
|
|
44251
|
+
const autoFilterXml = table.autoFilter ? `<autoFilter ref="${escapeXml(table.ref)}"/>` : "";
|
|
44252
|
+
const styleName = table.styleName ?? "TableStyleMedium2";
|
|
44253
|
+
return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
44254
|
+
<table xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" id="${tableId}" name="${escapeXml(table.name)}" displayName="${escapeXml(table.displayName)}" ref="${escapeXml(table.ref)}" totalsRowCount="${table.totalsRow ? 1 : 0}">
|
|
44255
|
+
${autoFilterXml}
|
|
44256
|
+
<tableColumns count="${table.columns.length}">${colsXml}</tableColumns>
|
|
44257
|
+
<tableStyleInfo name="${escapeXml(styleName)}" showFirstColumn="0" showLastColumn="0" showRowStripes="1" showColumnStripes="0"/>
|
|
44258
|
+
</table>`;
|
|
44259
|
+
}
|
|
44260
|
+
function buildConditionalFormattingXml(cf, dxfMap) {
|
|
44261
|
+
const rules = cf.rules.map((rule) => {
|
|
44262
|
+
switch (rule.ruleType) {
|
|
44263
|
+
case "colorScale": {
|
|
44264
|
+
const count = rule.colors.length;
|
|
44265
|
+
const cfvos = count === 2 ? '<cfvo type="min"/><cfvo type="max"/>' : '<cfvo type="min"/><cfvo type="percentile" val="50"/><cfvo type="max"/>';
|
|
44266
|
+
const colors = rule.colors.map((c) => `<color rgb="${hexToArgb(c)}"/>`).join("");
|
|
44267
|
+
return `<cfRule type="colorScale" priority="${rule.priority}"><colorScale>${cfvos}${colors}</colorScale></cfRule>`;
|
|
44268
|
+
}
|
|
44269
|
+
case "dataBar": {
|
|
44270
|
+
const showVal = rule.showValue ? "1" : "0";
|
|
44271
|
+
return `<cfRule type="dataBar" priority="${rule.priority}"><dataBar minLength="${rule.minLength}" maxLength="${rule.maxLength}" showValue="${showVal}"><cfvo type="min"/><cfvo type="max"/><color rgb="${hexToArgb(rule.color)}"/></dataBar></cfRule>`;
|
|
44272
|
+
}
|
|
44273
|
+
case "iconSet": {
|
|
44274
|
+
const thresholds = rule.thresholds.map((t) => {
|
|
44275
|
+
if (t.type === "min" || t.type === "autoMin") return '<cfvo type="min"/>';
|
|
44276
|
+
if (t.type === "max" || t.type === "autoMax") return '<cfvo type="max"/>';
|
|
44277
|
+
return `<cfvo type="${t.type}" val="${t.value ?? 0}"/>`;
|
|
44278
|
+
}).join("");
|
|
44279
|
+
const showVal = rule.showValue ? "" : ' showValue="0"';
|
|
44280
|
+
const reverse = rule.reverse ? ' reverse="1"' : "";
|
|
44281
|
+
return `<cfRule type="iconSet" priority="${rule.priority}"><iconSet iconSet="${rule.iconSet}"${showVal}${reverse}>${thresholds}</iconSet></cfRule>`;
|
|
44282
|
+
}
|
|
44283
|
+
case "style": {
|
|
44284
|
+
let attrs = `type="${rule.type}" priority="${rule.priority}"`;
|
|
44285
|
+
if (rule.style) {
|
|
44286
|
+
const dxfId = dxfMap.get(JSON.stringify(rule.style));
|
|
44287
|
+
if (dxfId !== void 0) attrs += ` dxfId="${dxfId}"`;
|
|
44288
|
+
}
|
|
44289
|
+
if (rule.operator) attrs += ` operator="${rule.operator}"`;
|
|
44290
|
+
if (rule.text) attrs += ` text="${escapeXml(rule.text)}"`;
|
|
44291
|
+
if (rule.rank !== void 0) attrs += ` rank="${rule.rank}"`;
|
|
44292
|
+
if (rule.percent) attrs += ' percent="1"';
|
|
44293
|
+
if (rule.bottom) attrs += ' bottom="1"';
|
|
44294
|
+
if (rule.aboveAverage === false) attrs += ' aboveAverage="0"';
|
|
44295
|
+
if (rule.timePeriod) attrs += ` timePeriod="${rule.timePeriod}"`;
|
|
44296
|
+
let inner = "";
|
|
44297
|
+
if (rule.formulae) {
|
|
44298
|
+
inner = rule.formulae.map((f) => `<formula>${escapeXml(String(f))}</formula>`).join("");
|
|
44299
|
+
}
|
|
44300
|
+
return `<cfRule ${attrs}>${inner}</cfRule>`;
|
|
44301
|
+
}
|
|
43306
44302
|
}
|
|
43307
|
-
|
|
43308
|
-
}
|
|
43309
|
-
}
|
|
43310
|
-
function
|
|
43311
|
-
|
|
43312
|
-
|
|
43313
|
-
|
|
43314
|
-
|
|
43315
|
-
|
|
43316
|
-
|
|
43317
|
-
|
|
43318
|
-
for (let col = range.startCol; col <= range.endCol; col++) {
|
|
43319
|
-
const cell = sheet.getCell(rowColToRef(range.startRow, col));
|
|
43320
|
-
header.push(formatHeader(cell?.value));
|
|
44303
|
+
}).join("");
|
|
44304
|
+
return `<conditionalFormatting sqref="${cf.ref}">${rules}</conditionalFormatting>`;
|
|
44305
|
+
}
|
|
44306
|
+
function buildDxfXml(style) {
|
|
44307
|
+
let inner = "";
|
|
44308
|
+
if (style.fontBold || style.fontItalic || style.fontColor) {
|
|
44309
|
+
let fontParts = "";
|
|
44310
|
+
if (style.fontBold) fontParts += "<b/>";
|
|
44311
|
+
if (style.fontItalic) fontParts += "<i/>";
|
|
44312
|
+
if (style.fontColor) fontParts += `<color rgb="${hexToArgb(style.fontColor)}"/>`;
|
|
44313
|
+
inner += `<font>${fontParts}</font>`;
|
|
43321
44314
|
}
|
|
43322
|
-
|
|
43323
|
-
|
|
43324
|
-
const rec = [];
|
|
43325
|
-
for (let col = range.startCol; col <= range.endCol; col++) {
|
|
43326
|
-
const cell = sheet.getCell(rowColToRef(row, col));
|
|
43327
|
-
rec.push(coerceValue(cell?.value));
|
|
43328
|
-
}
|
|
43329
|
-
records.push(rec);
|
|
44315
|
+
if (style.backgroundColor) {
|
|
44316
|
+
inner += `<fill><patternFill><bgColor rgb="${hexToArgb(style.backgroundColor)}"/></patternFill></fill>`;
|
|
43330
44317
|
}
|
|
43331
|
-
return {
|
|
44318
|
+
return `<dxf>${inner}</dxf>`;
|
|
43332
44319
|
}
|
|
43333
|
-
function
|
|
43334
|
-
if (
|
|
43335
|
-
|
|
44320
|
+
function getImageExtension(dataUrl) {
|
|
44321
|
+
if (dataUrl.startsWith("data:image/png")) return "png";
|
|
44322
|
+
if (dataUrl.startsWith("data:image/jpeg") || dataUrl.startsWith("data:image/jpg")) return "jpeg";
|
|
44323
|
+
if (dataUrl.startsWith("data:image/gif")) return "gif";
|
|
44324
|
+
return "png";
|
|
43336
44325
|
}
|
|
43337
|
-
function
|
|
43338
|
-
|
|
43339
|
-
if (
|
|
43340
|
-
|
|
43341
|
-
|
|
43342
|
-
|
|
44326
|
+
function dataUrlToBytes(dataUrl) {
|
|
44327
|
+
const match = dataUrl.match(/^data:[^;]+;base64,(.+)$/);
|
|
44328
|
+
if (!match) return null;
|
|
44329
|
+
const binary = atob(match[1]);
|
|
44330
|
+
const bytes = new Uint8Array(binary.length);
|
|
44331
|
+
for (let i2 = 0; i2 < binary.length; i2++) bytes[i2] = binary.charCodeAt(i2);
|
|
44332
|
+
return bytes;
|
|
43343
44333
|
}
|
|
43344
|
-
|
|
43345
|
-
|
|
43346
|
-
|
|
43347
|
-
|
|
43348
|
-
|
|
43349
|
-
|
|
43350
|
-
|
|
43351
|
-
|
|
43352
|
-
const end = refToRowCol(endRef);
|
|
43353
|
-
if (!end) return void 0;
|
|
43354
|
-
return {
|
|
43355
|
-
startRow: start.row,
|
|
43356
|
-
startCol: start.col,
|
|
43357
|
-
endRow: end.row,
|
|
43358
|
-
endCol: end.col
|
|
43359
|
-
};
|
|
44334
|
+
|
|
44335
|
+
// ../xlsx/src/style_helpers.ts
|
|
44336
|
+
function border(style = "thin", color = "#000000") {
|
|
44337
|
+
return { width: 1, style, color };
|
|
44338
|
+
}
|
|
44339
|
+
function allBorders(style = "thin", color = "#000000") {
|
|
44340
|
+
const b = border(style, color);
|
|
44341
|
+
return { borderTop: b, borderRight: b, borderBottom: b, borderLeft: b };
|
|
43360
44342
|
}
|
|
43361
44343
|
|
|
43362
44344
|
// ../xlsx/src/workbook_model.ts
|
|
@@ -47923,6 +48905,8 @@ async function runDocxCommand(subcommand, toolArgs, restArgs) {
|
|
|
47923
48905
|
}
|
|
47924
48906
|
|
|
47925
48907
|
// src/cli.ts
|
|
48908
|
+
dns.setDefaultResultOrder("ipv4first");
|
|
48909
|
+
net2.setDefaultAutoSelectFamilyAttemptTimeout(2e3);
|
|
47926
48910
|
function printHelp() {
|
|
47927
48911
|
console.log(`Lotics CLI v${VERSION} \u2014 AI agent interface for Lotics
|
|
47928
48912
|
|
|
@@ -47979,9 +48963,21 @@ COMMANDS
|
|
|
47979
48963
|
lotics app deploy [-m <message>] Build + upload current dir as a new version
|
|
47980
48964
|
(code + queries only \u2014 workflow bindings are
|
|
47981
48965
|
managed by set_app_workflow / remove_app_workflow)
|
|
48966
|
+
lotics app codegen [path] Regenerate .lotics/* (types + field/option ids)
|
|
48967
|
+
from the manifest + workspace schema \u2014 no deploy
|
|
48968
|
+
lotics app workflow run <alias> '<json>' Execute a bound app workflow end-to-end
|
|
48969
|
+
(inputs: inline JSON, @file, or stdin;
|
|
48970
|
+
--print-created reports created records +
|
|
48971
|
+
a paste-ready cleanup plan; --cleanup also
|
|
48972
|
+
deletes those records \u2014 NOT a rollback)
|
|
48973
|
+
lotics app workflow set <alias> Push the edited src/workflows/<alias>.ts body
|
|
48974
|
+
through set_app_workflow (server verifies)
|
|
48975
|
+
lotics app workflow pull Rewrite src/workflows/*.ts from the server
|
|
47982
48976
|
lotics app subdomain <new-subdomain> Rename the app's public <slug>.lotics.app address
|
|
47983
48977
|
lotics app rename "<new name>" Rename the app's display name (launcher title)
|
|
47984
48978
|
lotics app dev [path] Run the app locally with HMR (RPC forwarded to prod)
|
|
48979
|
+
lotics ui link <component> [--remove] Dev-link @lotics/ui to the monorepo's
|
|
48980
|
+
packages/ui/src for live HMR (monorepo only)
|
|
47985
48981
|
lotics xlsx <subcommand> ... Read/write/edit .xlsx files on your local filesystem
|
|
47986
48982
|
(uses the bundled Lotics xlsx engine; prefer over
|
|
47987
48983
|
npm xlsx/exceljs for round-trip fidelity)
|
|
@@ -48341,6 +49337,34 @@ async function main() {
|
|
|
48341
49337
|
await runDocxCommand(subcommand, toolArgs, restArgs);
|
|
48342
49338
|
return;
|
|
48343
49339
|
}
|
|
49340
|
+
if (command === "ui") {
|
|
49341
|
+
if (subcommand === "link") {
|
|
49342
|
+
const component = toolArgs;
|
|
49343
|
+
if (!component) {
|
|
49344
|
+
console.error("Usage: lotics ui link <component> [--remove]");
|
|
49345
|
+
console.error("Dev-links @lotics/ui to the monorepo's packages/ui/src for live HMR.");
|
|
49346
|
+
process.exit(1);
|
|
49347
|
+
}
|
|
49348
|
+
appUiLink({ component, remove: restArgs.includes("--remove") });
|
|
49349
|
+
return;
|
|
49350
|
+
}
|
|
49351
|
+
console.error(`Unknown ui subcommand: ${subcommand ?? "(none)"}`);
|
|
49352
|
+
console.error("Usage: lotics ui link <component> [--remove]");
|
|
49353
|
+
process.exit(1);
|
|
49354
|
+
}
|
|
49355
|
+
if (command === "app" && subcommand === "codegen") {
|
|
49356
|
+
const projectDir = toolArgs;
|
|
49357
|
+
const ctx2 = resolveContext(flags);
|
|
49358
|
+
if (!ctx2) {
|
|
49359
|
+
await appCodegen({ projectDir });
|
|
49360
|
+
return;
|
|
49361
|
+
}
|
|
49362
|
+
const viewAsMemberId = flags.viewAs ?? process.env.LOTICS_VIEW_AS;
|
|
49363
|
+
const client2 = new LoticsClient({ apiKey: ctx2.apiKey, workspaceId: ctx2.workspaceId, viewAsMemberId });
|
|
49364
|
+
await resolveWorkspace(client2, ctx2);
|
|
49365
|
+
await appCodegen({ projectDir, client: client2 });
|
|
49366
|
+
return;
|
|
49367
|
+
}
|
|
48344
49368
|
if (command === "org") {
|
|
48345
49369
|
const global2 = loadGlobalConfig() ?? {};
|
|
48346
49370
|
const profiles = global2.profiles ?? {};
|
|
@@ -48408,6 +49432,10 @@ async function main() {
|
|
|
48408
49432
|
console.error(" lotics app create <name> [path] Scaffold a new app locally");
|
|
48409
49433
|
console.error(" lotics app pull <app_id> [path] Pull an existing app for local editing");
|
|
48410
49434
|
console.error(" lotics app deploy [-m <message>] Build + upload the current directory");
|
|
49435
|
+
console.error(" lotics app codegen [path] Regenerate .lotics/* (types + field ids) \u2014 no deploy");
|
|
49436
|
+
console.error(" lotics app workflow run <alias> '<json>' Execute a bound app workflow end-to-end");
|
|
49437
|
+
console.error(" lotics app workflow set <alias> Push the edited src/workflows/<alias>.ts body");
|
|
49438
|
+
console.error(" lotics app workflow pull Rewrite src/workflows/*.ts from the server");
|
|
48411
49439
|
console.error(" lotics app subdomain <new-subdomain> Rename the app's public <slug>.lotics.app address");
|
|
48412
49440
|
console.error(` lotics app rename "<new name>" Rename the app's display name (launcher title)`);
|
|
48413
49441
|
console.error(" lotics app dev [path] Run the app locally with HMR + RPC forwarding");
|
|
@@ -48549,6 +49577,59 @@ Available workspaces:`);
|
|
|
48549
49577
|
await appRename(client, { name: newName });
|
|
48550
49578
|
return;
|
|
48551
49579
|
}
|
|
49580
|
+
if (subcommand === "workflow") {
|
|
49581
|
+
const action = toolArgs;
|
|
49582
|
+
const workflowUsage = () => {
|
|
49583
|
+
console.error("Usage:");
|
|
49584
|
+
console.error(" lotics app workflow run <alias> '<json>' Execute a bound app workflow");
|
|
49585
|
+
console.error(" lotics app workflow set <alias> Push src/workflows/<alias>.ts");
|
|
49586
|
+
console.error(" lotics app workflow pull Rewrite src/workflows/*.ts from the server");
|
|
49587
|
+
process.exit(1);
|
|
49588
|
+
};
|
|
49589
|
+
if (action === "run") {
|
|
49590
|
+
const alias = restArgs[0];
|
|
49591
|
+
if (!alias) {
|
|
49592
|
+
console.error("Usage: lotics app workflow run <alias> '<json>'");
|
|
49593
|
+
console.error(" lotics app workflow run <alias> @inputs.json (read inputs from a file)");
|
|
49594
|
+
console.error(" cat inputs.json | lotics app workflow run <alias> (read inputs from stdin)");
|
|
49595
|
+
console.error("Flags: --print-created (report created records + cleanup plan + caveat)");
|
|
49596
|
+
console.error(" --cleanup (also delete the created records \u2014 records only, NOT a rollback)");
|
|
49597
|
+
process.exit(1);
|
|
49598
|
+
}
|
|
49599
|
+
const ingested = await ingestJsonArgs({
|
|
49600
|
+
rawArg: restArgs[1],
|
|
49601
|
+
stdinIsTTY: process.stdin.isTTY ?? false,
|
|
49602
|
+
readFile: (p) => fs7.readFileSync(p, "utf-8"),
|
|
49603
|
+
readStdin
|
|
49604
|
+
});
|
|
49605
|
+
if (ingested.kind === "error") {
|
|
49606
|
+
console.error(ingested.message);
|
|
49607
|
+
process.exit(1);
|
|
49608
|
+
}
|
|
49609
|
+
await appExecuteWorkflow(client, {
|
|
49610
|
+
alias,
|
|
49611
|
+
inputs: ingested.args,
|
|
49612
|
+
printCreated: flags.printCreated,
|
|
49613
|
+
cleanup: flags.cleanup
|
|
49614
|
+
});
|
|
49615
|
+
return;
|
|
49616
|
+
}
|
|
49617
|
+
if (action === "set") {
|
|
49618
|
+
const alias = restArgs[0];
|
|
49619
|
+
if (!alias) {
|
|
49620
|
+
console.error("Usage: lotics app workflow set <alias>");
|
|
49621
|
+
console.error("Pushes the edited src/workflows/<alias>.ts body via set_app_workflow.");
|
|
49622
|
+
process.exit(1);
|
|
49623
|
+
}
|
|
49624
|
+
await appWorkflowSet(client, { alias });
|
|
49625
|
+
return;
|
|
49626
|
+
}
|
|
49627
|
+
if (action === "pull") {
|
|
49628
|
+
await appWorkflowPull(client);
|
|
49629
|
+
return;
|
|
49630
|
+
}
|
|
49631
|
+
workflowUsage();
|
|
49632
|
+
}
|
|
48552
49633
|
if (subcommand === "dev") {
|
|
48553
49634
|
const projectDir = toolArgs;
|
|
48554
49635
|
let port;
|
|
@@ -48647,29 +49728,17 @@ ${JSON.stringify(info.input_schema, null, 2)}`);
|
|
|
48647
49728
|
}
|
|
48648
49729
|
if (command === "run") {
|
|
48649
49730
|
const toolName = subcommand;
|
|
48650
|
-
|
|
48651
|
-
|
|
48652
|
-
|
|
48653
|
-
|
|
48654
|
-
|
|
48655
|
-
|
|
48656
|
-
|
|
48657
|
-
|
|
48658
|
-
|
|
48659
|
-
process.exit(1);
|
|
48660
|
-
}
|
|
48661
|
-
} else if (!rawArgs && !process.stdin.isTTY) {
|
|
48662
|
-
rawArgs = await readStdin();
|
|
48663
|
-
}
|
|
48664
|
-
let args = {};
|
|
48665
|
-
if (rawArgs) {
|
|
48666
|
-
try {
|
|
48667
|
-
args = JSON.parse(rawArgs);
|
|
48668
|
-
} catch {
|
|
48669
|
-
console.error(`Invalid JSON: ${rawArgs}`);
|
|
48670
|
-
process.exit(1);
|
|
48671
|
-
}
|
|
49731
|
+
const ingested = await ingestJsonArgs({
|
|
49732
|
+
rawArg: toolArgs,
|
|
49733
|
+
stdinIsTTY: process.stdin.isTTY ?? false,
|
|
49734
|
+
readFile: (p) => fs7.readFileSync(p, "utf-8"),
|
|
49735
|
+
readStdin
|
|
49736
|
+
});
|
|
49737
|
+
if (ingested.kind === "error") {
|
|
49738
|
+
console.error(ingested.message);
|
|
49739
|
+
process.exit(1);
|
|
48672
49740
|
}
|
|
49741
|
+
const args = ingested.args;
|
|
48673
49742
|
const timeoutMs = flags.timeout ?? 6e4;
|
|
48674
49743
|
const result = await client.execute(toolName, args, { format: "text", timeoutMs });
|
|
48675
49744
|
if (result.error) {
|