@cj-tech-master/excelts 9.5.5 → 9.5.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser/modules/excel/worksheet.d.ts +11 -0
- package/dist/browser/modules/excel/worksheet.js +13 -0
- package/dist/browser/modules/formula/integration/apply-writeback-plan.js +17 -3
- package/dist/browser/modules/formula/integration/workbook-adapter.js +20 -1
- package/dist/browser/modules/formula/integration/workbook-snapshot.d.ts +12 -0
- package/dist/browser/modules/formula/materialize/build-writeback-plan.js +47 -0
- package/dist/browser/modules/formula/materialize/types.d.ts +19 -3
- package/dist/browser/modules/formula/materialize/types.js +13 -3
- package/dist/browser/modules/pdf/builder/document-builder.js +2 -2
- package/dist/browser/modules/pdf/font/system-fonts.d.ts +24 -4
- package/dist/browser/modules/pdf/font/system-fonts.js +76 -32
- package/dist/browser/modules/pdf/render/pdf-exporter.js +6 -3
- package/dist/browser/modules/word/advanced/field-engine.js +151 -23
- package/dist/browser/modules/word/advanced/math-convert.js +2 -1
- package/dist/browser/modules/word/advanced/style-map.js +44 -6
- package/dist/browser/modules/word/convert/html/html-import.js +434 -71
- package/dist/browser/modules/word/convert/markdown/markdown-renderer.js +11 -3
- package/dist/browser/modules/word/layout/layout-full.js +4 -1
- package/dist/browser/modules/word/security/digital-signatures.js +160 -33
- package/dist/browser/modules/word/security/encryption.js +109 -9
- package/dist/cjs/modules/excel/worksheet.js +13 -0
- package/dist/cjs/modules/formula/integration/apply-writeback-plan.js +17 -3
- package/dist/cjs/modules/formula/integration/workbook-adapter.js +20 -1
- package/dist/cjs/modules/formula/materialize/build-writeback-plan.js +47 -0
- package/dist/cjs/modules/formula/materialize/types.js +13 -3
- package/dist/cjs/modules/pdf/builder/document-builder.js +1 -1
- package/dist/cjs/modules/pdf/font/system-fonts.js +77 -32
- package/dist/cjs/modules/pdf/render/pdf-exporter.js +5 -2
- package/dist/cjs/modules/word/advanced/field-engine.js +151 -23
- package/dist/cjs/modules/word/advanced/math-convert.js +2 -1
- package/dist/cjs/modules/word/advanced/style-map.js +44 -6
- package/dist/cjs/modules/word/convert/html/html-import.js +434 -71
- package/dist/cjs/modules/word/convert/markdown/markdown-renderer.js +11 -3
- package/dist/cjs/modules/word/layout/layout-full.js +4 -1
- package/dist/cjs/modules/word/security/digital-signatures.js +160 -33
- package/dist/cjs/modules/word/security/encryption.js +109 -9
- package/dist/esm/modules/excel/worksheet.js +13 -0
- package/dist/esm/modules/formula/integration/apply-writeback-plan.js +17 -3
- package/dist/esm/modules/formula/integration/workbook-adapter.js +20 -1
- package/dist/esm/modules/formula/materialize/build-writeback-plan.js +47 -0
- package/dist/esm/modules/formula/materialize/types.js +13 -3
- package/dist/esm/modules/pdf/builder/document-builder.js +2 -2
- package/dist/esm/modules/pdf/font/system-fonts.js +76 -32
- package/dist/esm/modules/pdf/render/pdf-exporter.js +6 -3
- package/dist/esm/modules/word/advanced/field-engine.js +151 -23
- package/dist/esm/modules/word/advanced/math-convert.js +2 -1
- package/dist/esm/modules/word/advanced/style-map.js +44 -6
- package/dist/esm/modules/word/convert/html/html-import.js +434 -71
- package/dist/esm/modules/word/convert/markdown/markdown-renderer.js +11 -3
- package/dist/esm/modules/word/layout/layout-full.js +4 -1
- package/dist/esm/modules/word/security/digital-signatures.js +160 -33
- package/dist/esm/modules/word/security/encryption.js +109 -9
- package/dist/iife/excelts.iife.js +40 -26
- package/dist/iife/excelts.iife.js.map +1 -1
- package/dist/iife/excelts.iife.min.js +3 -3
- package/dist/types/modules/excel/worksheet.d.ts +11 -0
- package/dist/types/modules/formula/integration/workbook-snapshot.d.ts +12 -0
- package/dist/types/modules/formula/materialize/types.d.ts +19 -3
- package/dist/types/modules/pdf/font/system-fonts.d.ts +24 -4
- package/package.json +1 -1
|
@@ -180,32 +180,160 @@ function parseSeqSwitches(args) {
|
|
|
180
180
|
}
|
|
181
181
|
/** Parse IF field: IF expr1 op expr2 "trueText" "falseText" */
|
|
182
182
|
function parseIfField(args) {
|
|
183
|
-
//
|
|
184
|
-
//
|
|
185
|
-
//
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
//
|
|
197
|
-
const
|
|
198
|
-
if (
|
|
199
|
-
return
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
183
|
+
// Hand-rolled parser used in place of the previous chained regex
|
|
184
|
+
// (`/^"?([^"=<>!]*?)"?\s*(<=|>=|<>|=|<|>)\s*"?([^"]*?)"?\s+"([^"]*)"\s+"([^"]*)"/`).
|
|
185
|
+
// CodeQL flagged that regex as polynomial-redos. The grammar is also
|
|
186
|
+
// permissive in ways the regex captured implicitly: real Word IF
|
|
187
|
+
// fields contain operands such as `MERGEFIELD foo` (with internal
|
|
188
|
+
// whitespace) and operands wrapped in quotes. The scanner below
|
|
189
|
+
// mirrors the regex's accepted shape:
|
|
190
|
+
//
|
|
191
|
+
// args := SP* leftOperand SP* op SP* rightOperand SP+ "trueText" SP+ "falseText" …
|
|
192
|
+
//
|
|
193
|
+
// where `leftOperand` runs up to the first comparison operator that
|
|
194
|
+
// is not inside a quoted span, and `rightOperand` runs up to the
|
|
195
|
+
// first `"` that begins the trueText literal.
|
|
196
|
+
// 1. Find the comparison operator outside any quoted span.
|
|
197
|
+
const opPos = findIfOperator(args, 0);
|
|
198
|
+
if (!opPos) {
|
|
199
|
+
return null;
|
|
200
|
+
}
|
|
201
|
+
// 2. Left operand: everything before the operator, with surrounding
|
|
202
|
+
// whitespace and outer quotes stripped.
|
|
203
|
+
const left = stripOuterQuotes(args.slice(0, opPos.start).trim());
|
|
204
|
+
// 3. Right operand: text between the operator and the first quoted
|
|
205
|
+
// literal, with surrounding whitespace and outer quotes stripped.
|
|
206
|
+
let cursor = opPos.next;
|
|
207
|
+
// Scan to the next `"` that is not the immediate value-quoted operand.
|
|
208
|
+
// We have to be careful: the right operand itself may be quoted, e.g.
|
|
209
|
+
// `1 = "bar" "y" "n"`. To match the previous regex we adopt: skip
|
|
210
|
+
// whitespace, optionally consume one quoted span as the right operand,
|
|
211
|
+
// otherwise consume up to the next whitespace+`"` boundary.
|
|
212
|
+
cursor = skipSpaces(args, cursor);
|
|
213
|
+
let right;
|
|
214
|
+
if (args.charCodeAt(cursor) === 0x22 /* '"' */) {
|
|
215
|
+
const close = args.indexOf('"', cursor + 1);
|
|
216
|
+
if (close < 0) {
|
|
217
|
+
return null;
|
|
218
|
+
}
|
|
219
|
+
right = args.slice(cursor + 1, close);
|
|
220
|
+
cursor = close + 1;
|
|
221
|
+
}
|
|
222
|
+
else {
|
|
223
|
+
// Read until the next `"` (which begins the trueText literal).
|
|
224
|
+
const nextQuote = args.indexOf('"', cursor);
|
|
225
|
+
if (nextQuote < 0) {
|
|
226
|
+
return null;
|
|
227
|
+
}
|
|
228
|
+
right = args.slice(cursor, nextQuote).trim();
|
|
229
|
+
cursor = nextQuote;
|
|
230
|
+
}
|
|
231
|
+
// 4. trueText (required quoted string).
|
|
232
|
+
cursor = skipSpaces(args, cursor);
|
|
233
|
+
const trueRead = readQuotedString(args, cursor);
|
|
234
|
+
if (!trueRead) {
|
|
235
|
+
return null;
|
|
236
|
+
}
|
|
237
|
+
cursor = skipSpaces(args, trueRead.next);
|
|
238
|
+
// 5. falseText (required quoted string).
|
|
239
|
+
const falseRead = readQuotedString(args, cursor);
|
|
240
|
+
if (!falseRead) {
|
|
241
|
+
return null;
|
|
242
|
+
}
|
|
243
|
+
return {
|
|
244
|
+
left,
|
|
245
|
+
operator: opPos.value,
|
|
246
|
+
right,
|
|
247
|
+
trueText: trueRead.value,
|
|
248
|
+
falseText: falseRead.value
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Find the first IF-field comparison operator (`<=`, `>=`, `<>`, `=`,
|
|
253
|
+
* `<`, `>`) starting at `from`, skipping over any quoted (`"…"`) spans
|
|
254
|
+
* so that operators inside operand strings are not mistaken for the
|
|
255
|
+
* top-level comparator.
|
|
256
|
+
*
|
|
257
|
+
* Bare `!` is reported as "no operator" rather than absorbed into the
|
|
258
|
+
* preceding operand: the previous regex excluded `!` from the left
|
|
259
|
+
* operand character class, so `1 != 1 …` was rejected outright. We
|
|
260
|
+
* preserve that rejection here to avoid silently parsing `!=` (not a
|
|
261
|
+
* Word IF-field operator) as `=` with `!` glued to the left operand.
|
|
262
|
+
*/
|
|
263
|
+
function findIfOperator(s, from) {
|
|
264
|
+
const n = s.length;
|
|
265
|
+
let i = from;
|
|
266
|
+
while (i < n) {
|
|
267
|
+
const c = s.charCodeAt(i);
|
|
268
|
+
if (c === 0x22 /* '"' */) {
|
|
269
|
+
// Skip quoted span.
|
|
270
|
+
const close = s.indexOf('"', i + 1);
|
|
271
|
+
if (close < 0) {
|
|
272
|
+
return null;
|
|
273
|
+
}
|
|
274
|
+
i = close + 1;
|
|
275
|
+
continue;
|
|
276
|
+
}
|
|
277
|
+
if (c === 0x21 /* '!' */) {
|
|
278
|
+
// Reject `!` outside quotes — matches the previous regex behaviour.
|
|
279
|
+
return null;
|
|
280
|
+
}
|
|
281
|
+
if (c === 0x3c /* '<' */) {
|
|
282
|
+
const next = s.charCodeAt(i + 1);
|
|
283
|
+
if (next === 0x3d) {
|
|
284
|
+
return { start: i, next: i + 2, value: "<=" };
|
|
285
|
+
}
|
|
286
|
+
if (next === 0x3e) {
|
|
287
|
+
return { start: i, next: i + 2, value: "<>" };
|
|
288
|
+
}
|
|
289
|
+
return { start: i, next: i + 1, value: "<" };
|
|
290
|
+
}
|
|
291
|
+
if (c === 0x3e /* '>' */) {
|
|
292
|
+
if (s.charCodeAt(i + 1) === 0x3d) {
|
|
293
|
+
return { start: i, next: i + 2, value: ">=" };
|
|
294
|
+
}
|
|
295
|
+
return { start: i, next: i + 1, value: ">" };
|
|
296
|
+
}
|
|
297
|
+
if (c === 0x3d /* '=' */) {
|
|
298
|
+
return { start: i, next: i + 1, value: "=" };
|
|
299
|
+
}
|
|
300
|
+
i++;
|
|
206
301
|
}
|
|
207
302
|
return null;
|
|
208
303
|
}
|
|
304
|
+
/**
|
|
305
|
+
* Strip a single matched pair of outer quotes (`"…"`) from a trimmed
|
|
306
|
+
* operand. Mirrors the implicit `"?…"?` shape of the original regex.
|
|
307
|
+
*/
|
|
308
|
+
function stripOuterQuotes(s) {
|
|
309
|
+
if (s.length >= 2 && s.charCodeAt(0) === 0x22 && s.charCodeAt(s.length - 1) === 0x22) {
|
|
310
|
+
return s.slice(1, -1);
|
|
311
|
+
}
|
|
312
|
+
return s;
|
|
313
|
+
}
|
|
314
|
+
function skipSpaces(s, from) {
|
|
315
|
+
const n = s.length;
|
|
316
|
+
let i = from;
|
|
317
|
+
while (i < n) {
|
|
318
|
+
const c = s.charCodeAt(i);
|
|
319
|
+
if (c !== 0x20 && c !== 0x09 && c !== 0x0a && c !== 0x0d) {
|
|
320
|
+
break;
|
|
321
|
+
}
|
|
322
|
+
i++;
|
|
323
|
+
}
|
|
324
|
+
return i;
|
|
325
|
+
}
|
|
326
|
+
/** Read a quoted (`"…"`) string starting at `from`, or return null. */
|
|
327
|
+
function readQuotedString(s, from) {
|
|
328
|
+
if (s.charCodeAt(from) !== 0x22 /* '"' */) {
|
|
329
|
+
return null;
|
|
330
|
+
}
|
|
331
|
+
const close = s.indexOf('"', from + 1);
|
|
332
|
+
if (close < 0) {
|
|
333
|
+
return null;
|
|
334
|
+
}
|
|
335
|
+
return { value: s.slice(from + 1, close), next: close + 1 };
|
|
336
|
+
}
|
|
209
337
|
/** Parse STYLEREF field to get the style name. */
|
|
210
338
|
function parseStyleRef(args) {
|
|
211
339
|
// STYLEREF "StyleName" or STYLEREF StyleName
|
|
@@ -405,7 +405,8 @@ function parseMMLTree(xml) {
|
|
|
405
405
|
// forever (indexOf returning -1 used to set pos = 0, hanging the CPU).
|
|
406
406
|
const end = xml.indexOf(">", pos);
|
|
407
407
|
if (end === -1) {
|
|
408
|
-
pos
|
|
408
|
+
// Malformed input — stop parsing. (`pos` is unused after the
|
|
409
|
+
// outer loop terminates, so no further assignment is needed.)
|
|
409
410
|
break;
|
|
410
411
|
}
|
|
411
412
|
pos = end + 1;
|
|
@@ -293,14 +293,52 @@ function parseTarget(targetStr) {
|
|
|
293
293
|
}
|
|
294
294
|
const tagName = tagMatch[1];
|
|
295
295
|
const className = tagMatch[2] ? tagMatch[2].substring(1).replace(/\./g, " ") : undefined;
|
|
296
|
-
// Parse attributes [key=value]
|
|
296
|
+
// Parse attributes [key=value]. Implemented as a linear scan rather
|
|
297
|
+
// than a global regex so that adversarial mapping strings cannot
|
|
298
|
+
// trigger CodeQL's `js/polynomial-redos`. The regex form
|
|
299
|
+
// `/\[([^=]+)=([^\]]+)\]/g` exhibits backtracking on inputs like
|
|
300
|
+
// `[xxxxxxxxxxxxx`.
|
|
297
301
|
let attributes;
|
|
298
|
-
|
|
302
|
+
const attrSection = tagMatch[3];
|
|
303
|
+
if (attrSection) {
|
|
299
304
|
attributes = {};
|
|
300
|
-
const
|
|
301
|
-
let
|
|
302
|
-
while (
|
|
303
|
-
|
|
305
|
+
const len = attrSection.length;
|
|
306
|
+
let i = 0;
|
|
307
|
+
while (i < len) {
|
|
308
|
+
if (attrSection.charCodeAt(i) !== 0x5b /* '[' */) {
|
|
309
|
+
i++;
|
|
310
|
+
continue;
|
|
311
|
+
}
|
|
312
|
+
const eq = attrSection.indexOf("=", i + 1);
|
|
313
|
+
const close = attrSection.indexOf("]", i + 1);
|
|
314
|
+
if (close < 0) {
|
|
315
|
+
break;
|
|
316
|
+
}
|
|
317
|
+
if (eq < 0 || eq > close) {
|
|
318
|
+
// No `=` inside this `[...]` — skip past it.
|
|
319
|
+
i = close + 1;
|
|
320
|
+
continue;
|
|
321
|
+
}
|
|
322
|
+
const key = attrSection.slice(i + 1, eq);
|
|
323
|
+
const rawValue = attrSection.slice(eq + 1, close);
|
|
324
|
+
// Strip a single leading and trailing quote (' or "). Two
|
|
325
|
+
// independent linear strips replace the previous
|
|
326
|
+
// `/^['"]|['"]$/g` regex.
|
|
327
|
+
let v = rawValue;
|
|
328
|
+
if (v.length >= 2) {
|
|
329
|
+
const first = v.charCodeAt(0);
|
|
330
|
+
if (first === 0x27 || first === 0x22) {
|
|
331
|
+
v = v.slice(1);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
if (v.length >= 1) {
|
|
335
|
+
const last = v.charCodeAt(v.length - 1);
|
|
336
|
+
if (last === 0x27 || last === 0x22) {
|
|
337
|
+
v = v.slice(0, -1);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
attributes[key] = v;
|
|
341
|
+
i = close + 1;
|
|
304
342
|
}
|
|
305
343
|
}
|
|
306
344
|
return { tagName, className: className || undefined, attributes };
|