@lotics/cli 0.192.2 → 0.195.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +8 -5
- package/README.md +13 -32
- package/dist/render_page.js +181 -16
- package/dist/src/cli.js +34328 -91405
- package/dist/src/client.d.ts +13 -1
- package/dist/src/client.js +9 -5
- package/docs/building_an_app.md +10 -1
- package/docs/cli_reference.md +5 -7
- package/docs/document_templates.md +1 -1
- package/package.json +2 -1
package/AGENTS.md
CHANGED
|
@@ -23,17 +23,17 @@ conventions are, and where the traps are.
|
|
|
23
23
|
- **Tools** (`lotics tools`, `lotics run <tool>`) — the *agent tool registry*: what an agent, workflow,
|
|
24
24
|
or automation may call. Workspace data, templates, knowledge, admin.
|
|
25
25
|
- **Commands** (`lotics --help` § COMMANDS) — the CLI's *own verbs*. Auth and org/workspace scoping,
|
|
26
|
-
file upload/download/preview,
|
|
27
|
-
|
|
26
|
+
file upload/download/preview, and the whole custom-code app loop (scaffold, pull, deploy, codegen,
|
|
27
|
+
dev, and running a bound workflow or agent end to end).
|
|
28
28
|
|
|
29
29
|
Several capabilities exist **only** as commands and appear nowhere in `lotics tools` — downloading a
|
|
30
30
|
file and running a bound app agent are the two that most often get mistaken for missing. Concluding
|
|
31
31
|
"the platform can't do X" from the tool list alone is a mistake; check both.
|
|
32
32
|
|
|
33
33
|
⚠️ **`lotics <subcommand> --help` prints the generic top-level help**, except `lotics report --help`
|
|
34
|
-
and a bare `lotics auth
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
and a bare `lotics auth`, which print their own. It does not describe the subcommand, so an unhelpful
|
|
35
|
+
response there is *not* evidence the subcommand is absent. To find out whether something exists, read
|
|
36
|
+
`lotics --help` § COMMANDS — the whole section, not a narrow grep.
|
|
37
37
|
|
|
38
38
|
## Conventions that hold across every command
|
|
39
39
|
|
|
@@ -108,5 +108,8 @@ whether something exists, read `lotics --help` § COMMANDS — the whole section
|
|
|
108
108
|
editing `tool_names` or `knowledge_doc_ids` still retypes `useAgentRun` — green locally, unchanged
|
|
109
109
|
in production, and reverted by the next `app codegen`. An agent's PROSE is not in the manifest at
|
|
110
110
|
all: it lives in `src/agents/<alias>.md` and is pushed by `app agent set`.
|
|
111
|
+
- **Editing a local `.xlsx` / `.docx`.** A library call, not a verb: script `@lotics/xlsx` /
|
|
112
|
+
`@lotics/docx` (`lotics docs xlsx` / `lotics docs docx` prints the installed copy's API guide).
|
|
113
|
+
`lotics file preview` draws the result so it can be looked at.
|
|
111
114
|
- **OAuth connections.** Attaching a connected account is web-only; the CLI can list them.
|
|
112
115
|
- **Anything needing a browser.** `app dev` and `file preview` shell out to a local Chrome.
|
package/README.md
CHANGED
|
@@ -110,8 +110,9 @@ irm https://lotics.ai/install.ps1 | iex # Windows PowerShell — no No
|
|
|
110
110
|
|
|
111
111
|
## Update
|
|
112
112
|
|
|
113
|
-
|
|
114
|
-
|
|
113
|
+
`lotics upgrade` updates this CLI in place, running whichever installer this copy came from. By
|
|
114
|
+
hand: re-run whichever installer you used; `npm install -g @lotics/cli@latest` updates an npm
|
|
115
|
+
install.
|
|
115
116
|
|
|
116
117
|
The CLI checks for updates once per day and prints a note on stderr, naming the right installer, when a new version is available.
|
|
117
118
|
|
|
@@ -284,40 +285,20 @@ LOTICS_API_KEY=ltk_... lotics run query_tables '{}'
|
|
|
284
285
|
LOTICS_ORG=acme LOTICS_WORKSPACE=wks_... lotics run query_tables '{}'
|
|
285
286
|
```
|
|
286
287
|
|
|
287
|
-
## Local .xlsx and .docx
|
|
288
|
+
## Local .xlsx and .docx files
|
|
288
289
|
|
|
289
|
-
|
|
290
|
+
Edit them by scripting Lotics's own engines, published as `@lotics/xlsx` and `@lotics/docx`. Prefer them over `xlsx` / `exceljs` / `docx` from npm: they round-trip faithfully with the Lotics editor, template engine, and formula engine. `npm i @lotics/xlsx @lotics/docx`, then read the API guide that ships inside the package: `lotics docs xlsx` / `lotics docs docx` prints the installed copy (`node_modules/@lotics/<pkg>/AGENTS.md` on a machine with no CLI). Both packages ship `.ts` sources as their entry, so run the script under a TypeScript-aware runner.
|
|
290
291
|
|
|
291
|
-
```
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
lotics xlsx read ./report.xlsx --with-format # …plus each cell's resolved style
|
|
295
|
-
lotics xlsx write ./out.xlsx '{"sheets":[{"name":"S1","cells":{"A1":"Hi","B1":42}}]}'
|
|
296
|
-
# A cell is a bare value, or an object with numFmt / style / formula:
|
|
297
|
-
lotics xlsx write ./out.xlsx '{"sheets":[{"name":"S1",
|
|
298
|
-
"colWidths":{"A":34,"B":14}, "rowHeights":{"1":28},
|
|
299
|
-
"cells":{
|
|
300
|
-
"A1":{"value":"Tổng","style":{"fontBold":true}},
|
|
301
|
-
"B1":{"value":1234567,"numFmt":"#,##0"},
|
|
302
|
-
"B2":{"formula":"B1*0.1","numFmt":"#,##0"}}}]}' # unknown keys are rejected, not ignored
|
|
303
|
-
lotics xlsx set-cell ./report.xlsx 'Sheet1!A1' '=SUM(B:B)'
|
|
304
|
-
lotics xlsx add-sheet ./report.xlsx 'Summary'
|
|
305
|
-
lotics xlsx merge ./report.xlsx 'Sheet1!A1:C1'
|
|
306
|
-
lotics xlsx insert-rows ./report.xlsx Sheet1 5 3
|
|
307
|
-
lotics xlsx batch ./report.xlsx '[{"op":"set-cell","sheet":"Sheet1","ref":"A1","value":"Hi"}, {"op":"merge","sheet":"Sheet1","range":"A1:B1"}]'
|
|
308
|
-
|
|
309
|
-
# .docx
|
|
310
|
-
lotics docx read ./report.docx # → JSON of blocks with text + style
|
|
311
|
-
lotics docx write ./out.docx '{"blocks":[{"kind":"paragraph","text":"Title","style":"Heading1"}]}'
|
|
312
|
-
lotics docx append-paragraph ./report.docx 'New paragraph' --style=Heading2
|
|
313
|
-
lotics docx insert-paragraph ./report.docx 'Front matter' --at=0
|
|
314
|
-
lotics docx replace-text ./report.docx '{{name}}' 'Acme Inc.'
|
|
315
|
-
lotics docx batch ./report.docx '[{"op":"append-paragraph","text":"A","style":"Heading1"},{"op":"replace-text","search":"x","replace":"y"}]'
|
|
316
|
-
```
|
|
292
|
+
```ts
|
|
293
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
294
|
+
import { parseDocx, replaceText, serializeDocx } from "@lotics/docx";
|
|
317
295
|
|
|
318
|
-
|
|
296
|
+
const { doc, count } = replaceText(await parseDocx(await readFile("in.docx")), "{{name}}", "Acme Ltd.");
|
|
297
|
+
if (count === 0) throw new Error("{{name}} is not in this document — nothing written");
|
|
298
|
+
await writeFile("out.docx", await serializeDocx(doc));
|
|
299
|
+
```
|
|
319
300
|
|
|
320
|
-
|
|
301
|
+
`lotics preview <file.xlsx|.docx>` draws one of those files to a PNG with the same engines, so a script's output can be looked at rather than guessed at.
|
|
321
302
|
|
|
322
303
|
## Knowledge docs
|
|
323
304
|
|
package/dist/render_page.js
CHANGED
|
@@ -50253,6 +50253,14 @@ ${e.toString()}`);
|
|
|
50253
50253
|
return colon === -1 ? tag : tag.slice(colon + 1);
|
|
50254
50254
|
}
|
|
50255
50255
|
|
|
50256
|
+
// ../xlsx/src/invalid_model_error.ts
|
|
50257
|
+
var InvalidModelError = class extends Error {
|
|
50258
|
+
constructor(reason) {
|
|
50259
|
+
super(reason);
|
|
50260
|
+
this.name = "InvalidModelError";
|
|
50261
|
+
}
|
|
50262
|
+
};
|
|
50263
|
+
|
|
50256
50264
|
// ../xlsx/node_modules/fast-xml-parser/src/util.js
|
|
50257
50265
|
var nameStartChar2 = ":A-Za-z_\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD";
|
|
50258
50266
|
var nameChar2 = nameStartChar2 + "\\-.\\d\\u00B7\\u0300-\\u036F\\u203F-\\u2040";
|
|
@@ -52902,7 +52910,7 @@ ${e.toString()}`);
|
|
|
52902
52910
|
const colCount = Math.max(parsedCols.length > 0 ? parsedCols[parsedCols.length - 1].max : 0, maxCol);
|
|
52903
52911
|
const columns = buildColumns(parsedCols, colHidden, maxContentWidth, colCount, defaultColWidth);
|
|
52904
52912
|
const mergedCells = parseMergedCells(worksheet);
|
|
52905
|
-
const conditionalFormats = parseConditionalFormats(worksheet, theme, indexedColors);
|
|
52913
|
+
const conditionalFormats = parseConditionalFormats(worksheet, theme, indexedColors, styles.dxfs);
|
|
52906
52914
|
const images = parseImages(rels, zipEntries);
|
|
52907
52915
|
const dataValidations = parseDataValidations(worksheet);
|
|
52908
52916
|
const sparklineGroups = parseSparklineGroups(worksheet);
|
|
@@ -53233,7 +53241,7 @@ ${e.toString()}`);
|
|
|
53233
53241
|
const cell = { column: cellRef.col, value: displayValue, content, style };
|
|
53234
53242
|
cell.typedValue = typedValue;
|
|
53235
53243
|
cell.rawValue = cellRawValue;
|
|
53236
|
-
cell.originalXfIndex = styleIndex;
|
|
53244
|
+
if (styles.hasXf(styleIndex)) cell.originalXfIndex = styleIndex;
|
|
53237
53245
|
if (numFmt !== "General") cell.numFmtCode = numFmt;
|
|
53238
53246
|
if (type === "e" && rawValue) cell.error = rawValue;
|
|
53239
53247
|
if (formula) cell.formula = formula;
|
|
@@ -53383,7 +53391,7 @@ ${e.toString()}`);
|
|
|
53383
53391
|
const dataUrl = `data:${mimeType};base64,${base64}`;
|
|
53384
53392
|
return { dataUrl, tl, br, ext, anchorKind, extent, pos };
|
|
53385
53393
|
}
|
|
53386
|
-
function parseConditionalFormats(worksheet, theme, indexedColors) {
|
|
53394
|
+
function parseConditionalFormats(worksheet, theme, indexedColors, dxfs) {
|
|
53387
53395
|
const cfArr = worksheet["conditionalFormatting"];
|
|
53388
53396
|
if (!cfArr) return [];
|
|
53389
53397
|
const result = [];
|
|
@@ -53394,7 +53402,7 @@ ${e.toString()}`);
|
|
|
53394
53402
|
if (!ruleArr) continue;
|
|
53395
53403
|
const rules = [];
|
|
53396
53404
|
for (const ruleEl of ruleArr) {
|
|
53397
|
-
const parsed = parseCfRule(ruleEl, theme, indexedColors);
|
|
53405
|
+
const parsed = parseCfRule(ruleEl, theme, indexedColors, dxfs);
|
|
53398
53406
|
if (parsed) rules.push(parsed);
|
|
53399
53407
|
}
|
|
53400
53408
|
if (rules.length > 0) {
|
|
@@ -53403,7 +53411,7 @@ ${e.toString()}`);
|
|
|
53403
53411
|
}
|
|
53404
53412
|
return result;
|
|
53405
53413
|
}
|
|
53406
|
-
function parseCfRule(el, theme, indexedColors) {
|
|
53414
|
+
function parseCfRule(el, theme, indexedColors, dxfs) {
|
|
53407
53415
|
const type = el["@_type"];
|
|
53408
53416
|
const priority = parseInt(el["@_priority"] ?? "1", 10);
|
|
53409
53417
|
const stopIfTrue = el["@_stopIfTrue"] === "1";
|
|
@@ -53464,14 +53472,23 @@ ${e.toString()}`);
|
|
|
53464
53472
|
case "aboveAverage":
|
|
53465
53473
|
case "timePeriod":
|
|
53466
53474
|
case "expression": {
|
|
53467
|
-
return parseStyleCfRule(el, type, priority, stopIfTrue,
|
|
53475
|
+
return parseStyleCfRule(el, type, priority, stopIfTrue, dxfs);
|
|
53468
53476
|
}
|
|
53469
53477
|
default:
|
|
53470
53478
|
return void 0;
|
|
53471
53479
|
}
|
|
53472
53480
|
}
|
|
53473
|
-
function parseStyleCfRule(el, type, priority, stopIfTrue,
|
|
53481
|
+
function parseStyleCfRule(el, type, priority, stopIfTrue, dxfs) {
|
|
53474
53482
|
const rule = { ruleType: "style", priority, stopIfTrue, type };
|
|
53483
|
+
const dxfIdAttr = el["@_dxfId"];
|
|
53484
|
+
if (dxfIdAttr !== void 0) {
|
|
53485
|
+
const dxfId = parseInt(dxfIdAttr, 10);
|
|
53486
|
+
const dxf = dxfs[dxfId];
|
|
53487
|
+
if (dxf !== void 0) {
|
|
53488
|
+
rule.style = { ...dxf };
|
|
53489
|
+
rule.originalDxfId = dxfId;
|
|
53490
|
+
}
|
|
53491
|
+
}
|
|
53475
53492
|
if (type === "cellIs") {
|
|
53476
53493
|
rule.operator = el["@_operator"];
|
|
53477
53494
|
const formula = el["formula"];
|
|
@@ -54158,6 +54175,11 @@ ${e.toString()}`);
|
|
|
54158
54175
|
* the styles part gets regenerated to include the new code.
|
|
54159
54176
|
*/
|
|
54160
54177
|
this.knownNumFmts = /* @__PURE__ */ new Set(["General", ""]);
|
|
54178
|
+
/**
|
|
54179
|
+
* What each `cellXfs` index of the loaded file resolves to here — the
|
|
54180
|
+
* baseline `originalXfExpresses` verifies an `originalXfIndex` against.
|
|
54181
|
+
*/
|
|
54182
|
+
this.originalXfs = /* @__PURE__ */ new Map();
|
|
54161
54183
|
this.keyMap.set(styleKey({}), 0);
|
|
54162
54184
|
}
|
|
54163
54185
|
/** Get style by index. Returns empty style for invalid indices. */
|
|
@@ -54191,6 +54213,44 @@ ${e.toString()}`);
|
|
|
54191
54213
|
this.knownNumFmts.add(code2);
|
|
54192
54214
|
this.dirty = true;
|
|
54193
54215
|
}
|
|
54216
|
+
/**
|
|
54217
|
+
* Record what the loaded file's `cellXfs` table resolves to here. The whole
|
|
54218
|
+
* table, because an entry no cell carries still governs the export: a cell
|
|
54219
|
+
* written with no `s=` inherits entry 0. An entry whose style this registry
|
|
54220
|
+
* never interned stays unrecorded, so a write claiming it fails
|
|
54221
|
+
* `originalXfExpresses` and the claim is dropped.
|
|
54222
|
+
*/
|
|
54223
|
+
recordOriginalXfs(cellXfs) {
|
|
54224
|
+
for (let i3 = 0; i3 < cellXfs.length; i3++) {
|
|
54225
|
+
const styleIndex = this.keyMap.get(styleKey(cellXfs[i3].style));
|
|
54226
|
+
if (styleIndex !== void 0) {
|
|
54227
|
+
this.originalXfs.set(i3, { styleIndex, numFmtCode: cellXfs[i3].numFmtCode });
|
|
54228
|
+
}
|
|
54229
|
+
}
|
|
54230
|
+
}
|
|
54231
|
+
/**
|
|
54232
|
+
* Whether the loaded file's xf `index` resolves to exactly this style and
|
|
54233
|
+
* number format here. The claim a caller makes by naming an `originalXfIndex`,
|
|
54234
|
+
* checked at the write so no later scan has to re-ask it.
|
|
54235
|
+
*/
|
|
54236
|
+
originalXfExpresses(index, styleIndex, numFmtCode) {
|
|
54237
|
+
const original = this.originalXfs.get(index);
|
|
54238
|
+
return original !== void 0 && original.styleIndex === styleIndex && original.numFmtCode === (numFmtCode === "" ? "General" : numFmtCode);
|
|
54239
|
+
}
|
|
54240
|
+
/**
|
|
54241
|
+
* True when the xf index the writer emits for `cell` in styles-passthrough
|
|
54242
|
+
* mode still expresses the cell's style. A cell CARRYING an index always
|
|
54243
|
+
* does — every write path drops that index the moment the style or number
|
|
54244
|
+
* format moves off it. The question left is the one no cell states: a cell
|
|
54245
|
+
* the file never carried emits no `s=` and so inherits the file's xf 0,
|
|
54246
|
+
* which is right only when that entry expresses the style the model gives
|
|
54247
|
+
* it. Neither half reads cell protection or `quotePrefix`, which this model
|
|
54248
|
+
* does not carry, so an xf differing only there compares equal.
|
|
54249
|
+
*/
|
|
54250
|
+
keepsOriginalXf(cell) {
|
|
54251
|
+
if (cell.originalXfIndex !== void 0) return true;
|
|
54252
|
+
return this.originalXfExpresses(0, cell.styleIndex, cell.numFmtCode);
|
|
54253
|
+
}
|
|
54194
54254
|
/**
|
|
54195
54255
|
* Reset the `dirty` flag and snapshot the current numFmt set as the
|
|
54196
54256
|
* baseline. Called once after loading from a parsed workbook so that
|
|
@@ -54369,8 +54429,21 @@ ${e.toString()}`);
|
|
|
54369
54429
|
*
|
|
54370
54430
|
* Pass `originalXfIndex` to enable styles-passthrough mode for cells
|
|
54371
54431
|
* copied from a parsed template.
|
|
54432
|
+
*
|
|
54433
|
+
* Both arguments are indexes into tables this sheet's registry owns and
|
|
54434
|
+
* neither is interned here, so both are checked against it — differently.
|
|
54435
|
+
* An unknown `styleIndex` throws: it would reach the writer and render as
|
|
54436
|
+
* the empty style, and there is no style to fall back to. An
|
|
54437
|
+
* `originalXfIndex` the file's xf table contradicts is instead dropped: the
|
|
54438
|
+
* cell still knows its style, so the export rebuilds the styles part rather
|
|
54439
|
+
* than shipping the cell with the one the file gave that index.
|
|
54372
54440
|
*/
|
|
54373
54441
|
setWithStyleIndex(ref2, value2, styleIndex, numFmtCode = "General", formula, originalXfIndex) {
|
|
54442
|
+
if (this.styles && !(Number.isInteger(styleIndex) && styleIndex >= 0 && styleIndex < this.styles.size)) {
|
|
54443
|
+
throw new InvalidModelError(
|
|
54444
|
+
`setWithStyleIndex: styleIndex ${styleIndex} is not in this sheet's registry (0..${this.styles.size - 1})`
|
|
54445
|
+
);
|
|
54446
|
+
}
|
|
54374
54447
|
if (this.styles) this.styles.registerNumFmt(numFmtCode);
|
|
54375
54448
|
const cell = {
|
|
54376
54449
|
value: value2,
|
|
@@ -54380,7 +54453,23 @@ ${e.toString()}`);
|
|
|
54380
54453
|
numFmtCode,
|
|
54381
54454
|
content: { type: "plain", text: "" }
|
|
54382
54455
|
};
|
|
54383
|
-
if (originalXfIndex !== void 0
|
|
54456
|
+
if (originalXfIndex !== void 0 && this.styles?.originalXfExpresses(originalXfIndex, styleIndex, numFmtCode)) {
|
|
54457
|
+
cell.originalXfIndex = originalXfIndex;
|
|
54458
|
+
}
|
|
54459
|
+
this.cells.set(ref2, cell);
|
|
54460
|
+
return cell;
|
|
54461
|
+
}
|
|
54462
|
+
/**
|
|
54463
|
+
* Re-style an existing cell. Replaces it rather than editing it in place, so
|
|
54464
|
+
* a style the cell's `originalXfIndex` no longer expresses drops that index
|
|
54465
|
+
* exactly as `set()` does — keeping it would ship the cell with the style the
|
|
54466
|
+
* FILE gave that index. Returns undefined for a ref holding no cell.
|
|
54467
|
+
*/
|
|
54468
|
+
setStyleIndex(ref2, styleIndex) {
|
|
54469
|
+
const existing = this.cells.get(ref2);
|
|
54470
|
+
if (!existing) return void 0;
|
|
54471
|
+
const cell = { ...existing, styleIndex };
|
|
54472
|
+
if (styleIndex !== existing.styleIndex) delete cell.originalXfIndex;
|
|
54384
54473
|
this.cells.set(ref2, cell);
|
|
54385
54474
|
return cell;
|
|
54386
54475
|
}
|
|
@@ -54449,6 +54538,30 @@ ${e.toString()}`);
|
|
|
54449
54538
|
this.onChange?.(event);
|
|
54450
54539
|
for (const sub of this.subscribers) sub(event);
|
|
54451
54540
|
}
|
|
54541
|
+
/**
|
|
54542
|
+
* True while every reference the regenerated parts make into the styles part
|
|
54543
|
+
* resolves against the loaded file's own — the precondition for exporting
|
|
54544
|
+
* that part unrebuilt. Two kinds of reference exist: a cell's `s=` names a
|
|
54545
|
+
* `cellXfs` entry, and a style conditional-format rule's `dxfId` names a
|
|
54546
|
+
* `dxfs` entry. A rule read out of the file keeps the `dxfs` index it came
|
|
54547
|
+
* in on; a rule painting a style that index cannot name is one only the
|
|
54548
|
+
* rebuild can mint a dxf for, so a workbook holding one cannot skip it —
|
|
54549
|
+
* that rule would ship with no `dxfId` and paint nothing.
|
|
54550
|
+
*/
|
|
54551
|
+
regeneratedPartsReferenceOnlyLoadedStyles() {
|
|
54552
|
+
for (const sheet of this.sheets) {
|
|
54553
|
+
for (const cell of sheet.cells.values()) {
|
|
54554
|
+
if (!this.styles.keepsOriginalXf(cell)) return false;
|
|
54555
|
+
}
|
|
54556
|
+
for (const cf of sheet.conditionalFormats) {
|
|
54557
|
+
for (const rule of cf.rules) {
|
|
54558
|
+
if (rule.ruleType !== "style") continue;
|
|
54559
|
+
if (rule.style !== void 0 && rule.originalDxfId === void 0) return false;
|
|
54560
|
+
}
|
|
54561
|
+
}
|
|
54562
|
+
}
|
|
54563
|
+
return true;
|
|
54564
|
+
}
|
|
54452
54565
|
/** Produce an immutable ParsedSpreadsheet snapshot for read-only consumers. */
|
|
54453
54566
|
toSnapshot() {
|
|
54454
54567
|
return {
|
|
@@ -54550,7 +54663,7 @@ ${e.toString()}`);
|
|
|
54550
54663
|
const styles = new StyleRegistry();
|
|
54551
54664
|
const sheets = [];
|
|
54552
54665
|
for (const ps of parsed.sheets) {
|
|
54553
|
-
const sheet = loadSheetFromParsed(ps, styles);
|
|
54666
|
+
const sheet = loadSheetFromParsed(ps, styles, parsed.cellXfs !== void 0);
|
|
54554
54667
|
sheets.push(sheet);
|
|
54555
54668
|
}
|
|
54556
54669
|
const wb = new WorkbookModel({
|
|
@@ -54577,10 +54690,11 @@ ${e.toString()}`);
|
|
|
54577
54690
|
}
|
|
54578
54691
|
}
|
|
54579
54692
|
}
|
|
54693
|
+
if (parsed.cellXfs) styles.recordOriginalXfs(parsed.cellXfs);
|
|
54580
54694
|
styles.markClean();
|
|
54581
54695
|
return wb;
|
|
54582
54696
|
}
|
|
54583
|
-
function loadSheetFromParsed(ps, styles) {
|
|
54697
|
+
function loadSheetFromParsed(ps, styles, hasCellXfs) {
|
|
54584
54698
|
const sheet = new SheetModel(ps.name, styles);
|
|
54585
54699
|
sheet.sheetState = ps.sheetState;
|
|
54586
54700
|
sheet.defaultRowHeight = ps.defaultRowHeight;
|
|
@@ -54627,20 +54741,28 @@ ${e.toString()}`);
|
|
|
54627
54741
|
for (const cell of row.cells) {
|
|
54628
54742
|
const ref2 = rowColToRef(row.index, cell.column);
|
|
54629
54743
|
const styleIndex = styles.intern(cell.style);
|
|
54744
|
+
const numFmtCode = cell.numFmtCode ?? "General";
|
|
54630
54745
|
styles.registerNumFmt(cell.numFmtCode);
|
|
54631
54746
|
const rawValue = cell.typedValue !== void 0 ? cell.typedValue : inferRawValue(cell.value, cell.content);
|
|
54632
54747
|
const model = {
|
|
54633
54748
|
value: rawValue,
|
|
54634
54749
|
displayValue: cell.value,
|
|
54635
54750
|
styleIndex,
|
|
54636
|
-
numFmtCode
|
|
54751
|
+
numFmtCode,
|
|
54637
54752
|
content: cell.content
|
|
54638
54753
|
};
|
|
54639
54754
|
if (cell.error) model.error = cell.error;
|
|
54640
54755
|
if (cell.formula) model.formula = cell.formula;
|
|
54641
54756
|
if (cell.isArrayFormula) model.isArrayFormula = true;
|
|
54642
54757
|
if (cell.arrayRange) model.arrayRange = cell.arrayRange;
|
|
54643
|
-
if (cell.originalXfIndex !== void 0)
|
|
54758
|
+
if (cell.originalXfIndex !== void 0) {
|
|
54759
|
+
if (!hasCellXfs) {
|
|
54760
|
+
throw new InvalidModelError(
|
|
54761
|
+
`${ps.name}!${ref2} carries originalXfIndex ${cell.originalXfIndex} but the snapshot has no cellXfs table`
|
|
54762
|
+
);
|
|
54763
|
+
}
|
|
54764
|
+
model.originalXfIndex = cell.originalXfIndex;
|
|
54765
|
+
}
|
|
54644
54766
|
if (cell.content.type === "rich_text") {
|
|
54645
54767
|
model.richText = cell.content.parts;
|
|
54646
54768
|
}
|
|
@@ -64979,7 +65101,7 @@ ${e.toString()}`);
|
|
|
64979
65101
|
// dropped before anything looks a tag up — see `stripNsPrefix`.
|
|
64980
65102
|
transformTagName: stripNsPrefix,
|
|
64981
65103
|
processEntities: false,
|
|
64982
|
-
isArray: (tagName) => tagName === "numFmt" || tagName === "font" || tagName === "fill" || tagName === "border" || tagName === "xf" || tagName === "rgbColor" || tagName === "stop"
|
|
65104
|
+
isArray: (tagName) => tagName === "numFmt" || tagName === "font" || tagName === "fill" || tagName === "border" || tagName === "xf" || tagName === "dxf" || tagName === "rgbColor" || tagName === "stop"
|
|
64983
65105
|
});
|
|
64984
65106
|
function parseStyles(stylesXml, theme) {
|
|
64985
65107
|
const doc3 = xmlParser3.parse(stylesXml);
|
|
@@ -65078,7 +65200,18 @@ ${e.toString()}`);
|
|
|
65078
65200
|
if (!cellXfs[xfIndex].applyNumFmt && fmtId === 0) return "General";
|
|
65079
65201
|
return customFmts.get(fmtId) ?? BUILTIN_NUM_FMTS[fmtId] ?? "General";
|
|
65080
65202
|
}
|
|
65081
|
-
|
|
65203
|
+
let resolvedXfs;
|
|
65204
|
+
return {
|
|
65205
|
+
resolveStyle,
|
|
65206
|
+
getNumFmt,
|
|
65207
|
+
hasXf: (xfIndex) => xfIndex >= 0 && xfIndex < cellXfs.length,
|
|
65208
|
+
indexedColors,
|
|
65209
|
+
dxfs: parseDxfs(root, theme, indexedColors),
|
|
65210
|
+
get cellXfs() {
|
|
65211
|
+
resolvedXfs ?? (resolvedXfs = cellXfs.map((_, i3) => ({ style: resolveStyle(i3), numFmtCode: getNumFmt(i3) })));
|
|
65212
|
+
return resolvedXfs;
|
|
65213
|
+
}
|
|
65214
|
+
};
|
|
65082
65215
|
}
|
|
65083
65216
|
function parseIndexedColors(root) {
|
|
65084
65217
|
const result = [...DEFAULT_INDEXED_COLORS];
|
|
@@ -65218,6 +65351,29 @@ ${e.toString()}`);
|
|
|
65218
65351
|
color: colorEl ? parseColorElement(colorEl) : void 0
|
|
65219
65352
|
};
|
|
65220
65353
|
}
|
|
65354
|
+
function parseDxfs(root, theme, indexedColors) {
|
|
65355
|
+
const dxfsEl = root["dxfs"];
|
|
65356
|
+
const dxfArr = dxfsEl?.["dxf"];
|
|
65357
|
+
if (!dxfArr) return [];
|
|
65358
|
+
return dxfArr.map((el) => {
|
|
65359
|
+
const style = {};
|
|
65360
|
+
const fontEl = el["font"]?.[0];
|
|
65361
|
+
if (fontEl) {
|
|
65362
|
+
const font = parseFont(fontEl);
|
|
65363
|
+
if (font.bold) style.fontBold = true;
|
|
65364
|
+
if (font.italic) style.fontItalic = true;
|
|
65365
|
+
const fontColor = resolveColor(font.color, theme, indexedColors, "font");
|
|
65366
|
+
if (fontColor) style.fontColor = prefixHex(fontColor);
|
|
65367
|
+
}
|
|
65368
|
+
const fillEl = el["fill"]?.[0];
|
|
65369
|
+
if (fillEl) {
|
|
65370
|
+
const fill = parseFill(fillEl);
|
|
65371
|
+
const bgHex = resolveColor(fill.bgColor ?? fill.fgColor, theme, indexedColors, "fill");
|
|
65372
|
+
if (bgHex) style.backgroundColor = prefixHex(bgHex);
|
|
65373
|
+
}
|
|
65374
|
+
return style;
|
|
65375
|
+
});
|
|
65376
|
+
}
|
|
65221
65377
|
function parseCellXfs(root) {
|
|
65222
65378
|
const xfsEl = root["cellXfs"];
|
|
65223
65379
|
if (!xfsEl) return [];
|
|
@@ -65303,7 +65459,10 @@ ${e.toString()}`);
|
|
|
65303
65459
|
return {
|
|
65304
65460
|
resolveStyle: () => ({}),
|
|
65305
65461
|
getNumFmt: () => "General",
|
|
65306
|
-
|
|
65462
|
+
hasXf: () => false,
|
|
65463
|
+
indexedColors: [...DEFAULT_INDEXED_COLORS],
|
|
65464
|
+
dxfs: [],
|
|
65465
|
+
cellXfs: []
|
|
65307
65466
|
};
|
|
65308
65467
|
}
|
|
65309
65468
|
|
|
@@ -67074,7 +67233,13 @@ ${e.toString()}`);
|
|
|
67074
67233
|
return { sheets: [emptySheet("Sheet1")], activeSheetIndex: 0 };
|
|
67075
67234
|
}
|
|
67076
67235
|
if (activeSheetIndex >= sheets.length) activeSheetIndex = 0;
|
|
67077
|
-
const result = {
|
|
67236
|
+
const result = {
|
|
67237
|
+
sheets,
|
|
67238
|
+
activeSheetIndex,
|
|
67239
|
+
get cellXfs() {
|
|
67240
|
+
return styles.cellXfs;
|
|
67241
|
+
}
|
|
67242
|
+
};
|
|
67078
67243
|
if (workbookInfo.namedRanges.size > 0) {
|
|
67079
67244
|
result.namedRanges = workbookInfo.namedRanges;
|
|
67080
67245
|
}
|