xslt-processor 5.0.8 → 5.0.9

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/index.d.mts CHANGED
@@ -285,7 +285,7 @@ declare class ExprContext {
285
285
  ignoreAttributesWithoutValue: any;
286
286
  returnOnFirstMatch: any;
287
287
  ignoreNonElementNodesForNTA: any;
288
- parent: ExprContext;
288
+ parent: ExprContext | null;
289
289
  root: XNode;
290
290
  decimalFormatSettings: XsltDecimalFormatSettings;
291
291
  inApplyTemplates: boolean;
@@ -348,8 +348,8 @@ declare class ExprContext {
348
348
  * @returns A new ExprContext instance with the specified node list and position, and the current context as its parent.
349
349
  */
350
350
  clone(opt_nodeList?: XNode[], opt_position?: number): ExprContext;
351
- setVariable(name?: string, value?: NodeValue | string): void;
352
- getVariable(name: string): NodeValue;
351
+ setVariable(name: string, value?: NodeValue | string): void;
352
+ getVariable(name: string): NodeValue | null;
353
353
  /**
354
354
  * Gets a regex group from xsl:analyze-string context.
355
355
  * Searches up the parent chain for regexGroups.
@@ -612,6 +612,13 @@ declare class NodeConverter {
612
612
  * followed by the evaluated function arguments.
613
613
  */
614
614
  private createCustomFunctions;
615
+ /**
616
+ * Minimal XSLT/XPath format-number() picture formatter.
617
+ * Supports grouping, decimal precision, percent/per-mille scaling and positive/negative subpictures.
618
+ */
619
+ private formatXsltNumberPicture;
620
+ private applyGrouping;
621
+ private leftPad;
615
622
  /**
616
623
  * Convert an XPathNode interface tree to actual XNode objects.
617
624
  * This is needed to convert json-to-xml() output to XSLT-compatible nodes.
package/dist/index.d.ts CHANGED
@@ -285,7 +285,7 @@ declare class ExprContext {
285
285
  ignoreAttributesWithoutValue: any;
286
286
  returnOnFirstMatch: any;
287
287
  ignoreNonElementNodesForNTA: any;
288
- parent: ExprContext;
288
+ parent: ExprContext | null;
289
289
  root: XNode;
290
290
  decimalFormatSettings: XsltDecimalFormatSettings;
291
291
  inApplyTemplates: boolean;
@@ -348,8 +348,8 @@ declare class ExprContext {
348
348
  * @returns A new ExprContext instance with the specified node list and position, and the current context as its parent.
349
349
  */
350
350
  clone(opt_nodeList?: XNode[], opt_position?: number): ExprContext;
351
- setVariable(name?: string, value?: NodeValue | string): void;
352
- getVariable(name: string): NodeValue;
351
+ setVariable(name: string, value?: NodeValue | string): void;
352
+ getVariable(name: string): NodeValue | null;
353
353
  /**
354
354
  * Gets a regex group from xsl:analyze-string context.
355
355
  * Searches up the parent chain for regexGroups.
@@ -612,6 +612,13 @@ declare class NodeConverter {
612
612
  * followed by the evaluated function arguments.
613
613
  */
614
614
  private createCustomFunctions;
615
+ /**
616
+ * Minimal XSLT/XPath format-number() picture formatter.
617
+ * Supports grouping, decimal precision, percent/per-mille scaling and positive/negative subpictures.
618
+ */
619
+ private formatXsltNumberPicture;
620
+ private applyGrouping;
621
+ private leftPad;
615
622
  /**
616
623
  * Convert an XPathNode interface tree to actual XNode objects.
617
624
  * This is needed to convert json-to-xml() output to XSLT-compatible nodes.
package/dist/index.js CHANGED
@@ -11846,7 +11846,9 @@ var NodeConverter = class {
11846
11846
  * We add missing properties but keep the original XNode reference.
11847
11847
  */
11848
11848
  adaptXNode(node) {
11849
- if (!node) return null;
11849
+ if (!node) {
11850
+ throw new Error("Cannot adapt undefined XPath node.");
11851
+ }
11850
11852
  const adapted = node;
11851
11853
  if (!("textContent" in adapted)) {
11852
11854
  Object.defineProperty(adapted, "textContent", {
@@ -11932,7 +11934,12 @@ var NodeConverter = class {
11932
11934
  }
11933
11935
  for (let i = contexts.length - 1; i >= 0; i--) {
11934
11936
  const current = contexts[i];
11935
- for (const [name, value] of Object.entries(current.variables || {})) {
11937
+ const currentVariables = current.variables || {};
11938
+ for (const name in currentVariables) {
11939
+ if (!Object.prototype.hasOwnProperty.call(currentVariables, name)) {
11940
+ continue;
11941
+ }
11942
+ const value = currentVariables[name];
11936
11943
  if (value && typeof value === "object" && "stringValue" in value) {
11937
11944
  const nodeValue = value;
11938
11945
  if (nodeValue.type === "node-set") {
@@ -11981,7 +11988,7 @@ var NodeConverter = class {
11981
11988
  };
11982
11989
  functions["format-number"] = (_context, number, format, decimalFormatName) => {
11983
11990
  const settings = exprContext.decimalFormatSettings;
11984
- return number.toLocaleString();
11991
+ return this.formatXsltNumberPicture(Number(number), String(format), settings);
11985
11992
  };
11986
11993
  functions["xml-to-json"] = (_context, nodes) => {
11987
11994
  if (exprContext.xsltVersion !== "3.0") {
@@ -12062,7 +12069,7 @@ var NodeConverter = class {
12062
12069
  "xsl:with-param"
12063
12070
  ];
12064
12071
  const normalizedName = name.startsWith("xsl:") ? name : `xsl:${name}`;
12065
- return xsltElements.includes(normalizedName) || xsltElements.includes(name);
12072
+ return xsltElements.indexOf(normalizedName) >= 0 || xsltElements.indexOf(name) >= 0;
12066
12073
  };
12067
12074
  functions["function-available"] = (_context, functionName2) => {
12068
12075
  const name = String(functionName2);
@@ -12113,7 +12120,7 @@ var NodeConverter = class {
12113
12120
  "json-to-xml"
12114
12121
  ];
12115
12122
  const allFunctions = [...xpathCoreFunctions, ...xsltFunctions, ...additionalFunctions];
12116
- return allFunctions.includes(name);
12123
+ return allFunctions.indexOf(name) >= 0;
12117
12124
  };
12118
12125
  functions["document"] = (_context, uriOrNodeSet, _baseNode) => {
12119
12126
  var _a, _b;
@@ -12157,6 +12164,95 @@ var NodeConverter = class {
12157
12164
  }
12158
12165
  return functions;
12159
12166
  }
12167
+ /**
12168
+ * Minimal XSLT/XPath format-number() picture formatter.
12169
+ * Supports grouping, decimal precision, percent/per-mille scaling and positive/negative subpictures.
12170
+ */
12171
+ formatXsltNumberPicture(value, picture, settings) {
12172
+ if (Number.isNaN(value)) {
12173
+ return settings.naN;
12174
+ }
12175
+ if (!Number.isFinite(value)) {
12176
+ return value < 0 ? `${settings.minusSign}${settings.infinity}` : settings.infinity;
12177
+ }
12178
+ const subPictures = picture.split(settings.patternSeparator);
12179
+ const isNegative = value < 0;
12180
+ const activePicture = (isNegative && subPictures.length > 1 ? subPictures[1] : subPictures[0]) || "";
12181
+ const absValue = Math.abs(value);
12182
+ const placeholders = /* @__PURE__ */ new Set([settings.digit, settings.zeroDigit, settings.groupingSeparator, settings.decimalSeparator]);
12183
+ let firstPatternIndex = -1;
12184
+ let lastPatternIndex = -1;
12185
+ for (let i = 0; i < activePicture.length; i++) {
12186
+ if (placeholders.has(activePicture[i])) {
12187
+ if (firstPatternIndex === -1) {
12188
+ firstPatternIndex = i;
12189
+ }
12190
+ lastPatternIndex = i;
12191
+ }
12192
+ }
12193
+ if (firstPatternIndex === -1) {
12194
+ return activePicture;
12195
+ }
12196
+ const prefix = activePicture.slice(0, firstPatternIndex);
12197
+ const suffix = activePicture.slice(lastPatternIndex + 1);
12198
+ const numericPicture = activePicture.slice(firstPatternIndex, lastPatternIndex + 1);
12199
+ let scaledValue = absValue;
12200
+ if (activePicture.includes(settings.percent)) {
12201
+ scaledValue *= 100;
12202
+ }
12203
+ if (activePicture.includes(settings.perMille)) {
12204
+ scaledValue *= 1e3;
12205
+ }
12206
+ const decimalIndex = numericPicture.indexOf(settings.decimalSeparator);
12207
+ const integerPattern = decimalIndex >= 0 ? numericPicture.slice(0, decimalIndex) : numericPicture;
12208
+ const fractionPattern = decimalIndex >= 0 ? numericPicture.slice(decimalIndex + 1) : "";
12209
+ const minIntegerDigits = integerPattern.split("").filter((c) => c === settings.zeroDigit).length;
12210
+ const minFractionDigits = fractionPattern.split("").filter((c) => c === settings.zeroDigit).length;
12211
+ const maxFractionDigits = fractionPattern.split("").filter((c) => c === settings.zeroDigit || c === settings.digit).length;
12212
+ const rounded = maxFractionDigits > 0 ? scaledValue.toFixed(maxFractionDigits) : Math.round(scaledValue).toString();
12213
+ let [integerPart, fractionPart = ""] = rounded.split(".");
12214
+ if (integerPart.length < minIntegerDigits) {
12215
+ integerPart = this.leftPad(integerPart, minIntegerDigits, settings.zeroDigit);
12216
+ }
12217
+ while (fractionPart.length > minFractionDigits && fractionPart.endsWith(settings.zeroDigit)) {
12218
+ fractionPart = fractionPart.slice(0, -1);
12219
+ }
12220
+ const lastGroupingPos = integerPattern.lastIndexOf(settings.groupingSeparator);
12221
+ if (lastGroupingPos >= 0) {
12222
+ const groupSize = integerPattern.slice(lastGroupingPos + 1).split("").filter((c) => c === settings.zeroDigit || c === settings.digit).length;
12223
+ if (groupSize > 0) {
12224
+ integerPart = this.applyGrouping(integerPart, settings.groupingSeparator, groupSize);
12225
+ }
12226
+ }
12227
+ const numberText = fractionPart.length > 0 ? `${integerPart}${settings.decimalSeparator}${fractionPart}` : integerPart;
12228
+ if (isNegative && subPictures.length < 2) {
12229
+ return `${settings.minusSign}${prefix}${numberText}${suffix}`;
12230
+ }
12231
+ return `${prefix}${numberText}${suffix}`;
12232
+ }
12233
+ applyGrouping(numberText, separator, groupSize) {
12234
+ if (groupSize <= 0 || numberText.length <= groupSize) {
12235
+ return numberText;
12236
+ }
12237
+ const chunks = [];
12238
+ for (let i = numberText.length; i > 0; i -= groupSize) {
12239
+ const start = Math.max(0, i - groupSize);
12240
+ chunks.unshift(numberText.slice(start, i));
12241
+ }
12242
+ return chunks.join(separator);
12243
+ }
12244
+ leftPad(value, width, fillChar) {
12245
+ if (value.length >= width) {
12246
+ return value;
12247
+ }
12248
+ const padChar = fillChar && fillChar.length > 0 ? fillChar.charAt(0) : "0";
12249
+ const missing = width - value.length;
12250
+ let padding = "";
12251
+ for (let i = 0; i < missing; i++) {
12252
+ padding += padChar;
12253
+ }
12254
+ return padding + value;
12255
+ }
12160
12256
  /**
12161
12257
  * Convert an XPathNode interface tree to actual XNode objects.
12162
12258
  * This is needed to convert json-to-xml() output to XSLT-compatible nodes.
@@ -12169,7 +12265,11 @@ var NodeConverter = class {
12169
12265
  if (xpathNode.nodeType === DOM_DOCUMENT_NODE) {
12170
12266
  if (xpathNode.childNodes && xpathNode.childNodes.length > 0) {
12171
12267
  const rootChild = xpathNode.childNodes[0];
12172
- node = this.convertXPathNodeToXNode(rootChild, ownerDoc);
12268
+ const convertedNode = this.convertXPathNodeToXNode(rootChild, ownerDoc);
12269
+ if (!convertedNode) {
12270
+ return null;
12271
+ }
12272
+ node = convertedNode;
12173
12273
  return node;
12174
12274
  }
12175
12275
  return null;