xslt-processor 5.0.8 → 5.0.10

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.mjs CHANGED
@@ -9069,13 +9069,9 @@ var XPathBaseParser = class {
9069
9069
  return expr;
9070
9070
  }
9071
9071
  parsePrimaryExpr() {
9072
- var _a, _b, _c;
9072
+ var _a, _b;
9073
9073
  if (this.match("DOLLAR")) {
9074
- const next = this.peek();
9075
- if (!next || !this.isNcNameToken(next.type)) {
9076
- throw grammarViolation(`Expected variable name after $. Got: ${(_a = next == null ? void 0 : next.lexeme) != null ? _a : "EOF"}`);
9077
- }
9078
- const name = this.advance().lexeme;
9074
+ const name = this.parseVariableReferenceName();
9079
9075
  return new XPathVariableReference(name);
9080
9076
  }
9081
9077
  if (this.match("OPEN_PAREN")) {
@@ -9099,7 +9095,7 @@ var XPathBaseParser = class {
9099
9095
  return this.parseFunctionCall();
9100
9096
  }
9101
9097
  throw grammarViolation(
9102
- `Unexpected token in primary expression: ${(_c = (_b = this.peek()) == null ? void 0 : _b.lexeme) != null ? _c : "EOF"}`
9098
+ `Unexpected token in primary expression: ${(_b = (_a = this.peek()) == null ? void 0 : _a.lexeme) != null ? _b : "EOF"}`
9103
9099
  );
9104
9100
  }
9105
9101
  parseFunctionCall() {
@@ -9171,6 +9167,27 @@ var XPathBaseParser = class {
9171
9167
  isFunctionNameToken(type) {
9172
9168
  return type === "IDENTIFIER" || type === "FUNCTION" || type === "OPERATOR" || type === "LOCATION" || type === "EQNAME";
9173
9169
  }
9170
+ parseVariableReferenceName() {
9171
+ var _a, _b;
9172
+ if (this.check("EQNAME")) {
9173
+ return this.advance().lexeme;
9174
+ }
9175
+ const next = this.peek();
9176
+ if (!next || !this.isNcNameToken(next.type)) {
9177
+ throw grammarViolation(`Expected variable name after $. Got: ${(_a = next == null ? void 0 : next.lexeme) != null ? _a : "EOF"}`);
9178
+ }
9179
+ let name = this.advance().lexeme;
9180
+ if (this.match("COLON")) {
9181
+ const local = this.peek();
9182
+ if (!local || !this.isNcNameToken(local.type)) {
9183
+ throw grammarViolation(
9184
+ `Expected local name after namespace prefix in variable reference. Got: ${(_b = local == null ? void 0 : local.lexeme) != null ? _b : "EOF"}`
9185
+ );
9186
+ }
9187
+ name = `${name}:${this.advance().lexeme}`;
9188
+ }
9189
+ return name;
9190
+ }
9174
9191
  isNcNameToken(type) {
9175
9192
  return type === "IDENTIFIER" || type === "FUNCTION" || type === "OPERATOR" || type === "LOCATION" || type === "NODE_TYPE";
9176
9193
  }
@@ -9283,16 +9300,12 @@ var XPath20Parser = class extends XPathBaseParser {
9283
9300
  return left;
9284
9301
  }
9285
9302
  parsePrimaryExpr() {
9286
- var _a, _b;
9287
9303
  if (this.check("RESERVED_WORD") && this.peek().lexeme === "if") {
9288
9304
  return this.parseIfExpr();
9289
9305
  }
9290
9306
  if (this.check("DOLLAR")) {
9291
9307
  this.advance();
9292
- if (!this.isNameToken()) {
9293
- throw new Error(`Expected variable name after $. Got: ${(_b = (_a = this.peek()) == null ? void 0 : _a.lexeme) != null ? _b : "EOF"}`);
9294
- }
9295
- const name = this.advance().lexeme;
9308
+ const name = this.parseVariableReferenceName();
9296
9309
  return new XPathVariableReference(name);
9297
9310
  }
9298
9311
  return super.parsePrimaryExpr();
@@ -9669,7 +9682,7 @@ var XPath30Parser = class extends XPath20Parser {
9669
9682
  let args = [];
9670
9683
  if (this.check("DOLLAR")) {
9671
9684
  this.advance();
9672
- const varName = this.consume("IDENTIFIER", "Expected variable name after $").lexeme;
9685
+ const varName = this.parseVariableReferenceName();
9673
9686
  funcExpr = new XPathVariableReference(varName);
9674
9687
  this.consume(
9675
9688
  "OPEN_PAREN",
@@ -9737,8 +9750,7 @@ var XPath30Parser = class extends XPath20Parser {
9737
9750
  return this.parseStringTemplateFromLexeme(template);
9738
9751
  }
9739
9752
  if (this.match("DOLLAR")) {
9740
- const nameToken = this.consumeNameTokenInternal("Expected variable name after $");
9741
- return new XPathVariableReference(nameToken.lexeme);
9753
+ return new XPathVariableReference(this.parseVariableReferenceName());
9742
9754
  }
9743
9755
  if (this.checkReservedWordInternal("function")) {
9744
9756
  return this.parseInlineFunction();
@@ -11831,7 +11843,9 @@ var NodeConverter = class {
11831
11843
  * We add missing properties but keep the original XNode reference.
11832
11844
  */
11833
11845
  adaptXNode(node) {
11834
- if (!node) return null;
11846
+ if (!node) {
11847
+ throw new Error("Cannot adapt undefined XPath node.");
11848
+ }
11835
11849
  const adapted = node;
11836
11850
  if (!("textContent" in adapted)) {
11837
11851
  Object.defineProperty(adapted, "textContent", {
@@ -11917,7 +11931,12 @@ var NodeConverter = class {
11917
11931
  }
11918
11932
  for (let i = contexts.length - 1; i >= 0; i--) {
11919
11933
  const current = contexts[i];
11920
- for (const [name, value] of Object.entries(current.variables || {})) {
11934
+ const currentVariables = current.variables || {};
11935
+ for (const name in currentVariables) {
11936
+ if (!Object.prototype.hasOwnProperty.call(currentVariables, name)) {
11937
+ continue;
11938
+ }
11939
+ const value = currentVariables[name];
11921
11940
  if (value && typeof value === "object" && "stringValue" in value) {
11922
11941
  const nodeValue = value;
11923
11942
  if (nodeValue.type === "node-set") {
@@ -11966,7 +11985,7 @@ var NodeConverter = class {
11966
11985
  };
11967
11986
  functions["format-number"] = (_context, number, format, decimalFormatName) => {
11968
11987
  const settings = exprContext.decimalFormatSettings;
11969
- return number.toLocaleString();
11988
+ return this.formatXsltNumberPicture(Number(number), String(format), settings);
11970
11989
  };
11971
11990
  functions["xml-to-json"] = (_context, nodes) => {
11972
11991
  if (exprContext.xsltVersion !== "3.0") {
@@ -12047,7 +12066,7 @@ var NodeConverter = class {
12047
12066
  "xsl:with-param"
12048
12067
  ];
12049
12068
  const normalizedName = name.startsWith("xsl:") ? name : `xsl:${name}`;
12050
- return xsltElements.includes(normalizedName) || xsltElements.includes(name);
12069
+ return xsltElements.indexOf(normalizedName) >= 0 || xsltElements.indexOf(name) >= 0;
12051
12070
  };
12052
12071
  functions["function-available"] = (_context, functionName2) => {
12053
12072
  const name = String(functionName2);
@@ -12098,7 +12117,7 @@ var NodeConverter = class {
12098
12117
  "json-to-xml"
12099
12118
  ];
12100
12119
  const allFunctions = [...xpathCoreFunctions, ...xsltFunctions, ...additionalFunctions];
12101
- return allFunctions.includes(name);
12120
+ return allFunctions.indexOf(name) >= 0;
12102
12121
  };
12103
12122
  functions["document"] = (_context, uriOrNodeSet, _baseNode) => {
12104
12123
  var _a, _b;
@@ -12142,6 +12161,95 @@ var NodeConverter = class {
12142
12161
  }
12143
12162
  return functions;
12144
12163
  }
12164
+ /**
12165
+ * Minimal XSLT/XPath format-number() picture formatter.
12166
+ * Supports grouping, decimal precision, percent/per-mille scaling and positive/negative subpictures.
12167
+ */
12168
+ formatXsltNumberPicture(value, picture, settings) {
12169
+ if (Number.isNaN(value)) {
12170
+ return settings.naN;
12171
+ }
12172
+ if (!Number.isFinite(value)) {
12173
+ return value < 0 ? `${settings.minusSign}${settings.infinity}` : settings.infinity;
12174
+ }
12175
+ const subPictures = picture.split(settings.patternSeparator);
12176
+ const isNegative = value < 0;
12177
+ const activePicture = (isNegative && subPictures.length > 1 ? subPictures[1] : subPictures[0]) || "";
12178
+ const absValue = Math.abs(value);
12179
+ const placeholders = /* @__PURE__ */ new Set([settings.digit, settings.zeroDigit, settings.groupingSeparator, settings.decimalSeparator]);
12180
+ let firstPatternIndex = -1;
12181
+ let lastPatternIndex = -1;
12182
+ for (let i = 0; i < activePicture.length; i++) {
12183
+ if (placeholders.has(activePicture[i])) {
12184
+ if (firstPatternIndex === -1) {
12185
+ firstPatternIndex = i;
12186
+ }
12187
+ lastPatternIndex = i;
12188
+ }
12189
+ }
12190
+ if (firstPatternIndex === -1) {
12191
+ return activePicture;
12192
+ }
12193
+ const prefix = activePicture.slice(0, firstPatternIndex);
12194
+ const suffix = activePicture.slice(lastPatternIndex + 1);
12195
+ const numericPicture = activePicture.slice(firstPatternIndex, lastPatternIndex + 1);
12196
+ let scaledValue = absValue;
12197
+ if (activePicture.includes(settings.percent)) {
12198
+ scaledValue *= 100;
12199
+ }
12200
+ if (activePicture.includes(settings.perMille)) {
12201
+ scaledValue *= 1e3;
12202
+ }
12203
+ const decimalIndex = numericPicture.indexOf(settings.decimalSeparator);
12204
+ const integerPattern = decimalIndex >= 0 ? numericPicture.slice(0, decimalIndex) : numericPicture;
12205
+ const fractionPattern = decimalIndex >= 0 ? numericPicture.slice(decimalIndex + 1) : "";
12206
+ const minIntegerDigits = integerPattern.split("").filter((c) => c === settings.zeroDigit).length;
12207
+ const minFractionDigits = fractionPattern.split("").filter((c) => c === settings.zeroDigit).length;
12208
+ const maxFractionDigits = fractionPattern.split("").filter((c) => c === settings.zeroDigit || c === settings.digit).length;
12209
+ const rounded = maxFractionDigits > 0 ? scaledValue.toFixed(maxFractionDigits) : Math.round(scaledValue).toString();
12210
+ let [integerPart, fractionPart = ""] = rounded.split(".");
12211
+ if (integerPart.length < minIntegerDigits) {
12212
+ integerPart = this.leftPad(integerPart, minIntegerDigits, settings.zeroDigit);
12213
+ }
12214
+ while (fractionPart.length > minFractionDigits && fractionPart.endsWith(settings.zeroDigit)) {
12215
+ fractionPart = fractionPart.slice(0, -1);
12216
+ }
12217
+ const lastGroupingPos = integerPattern.lastIndexOf(settings.groupingSeparator);
12218
+ if (lastGroupingPos >= 0) {
12219
+ const groupSize = integerPattern.slice(lastGroupingPos + 1).split("").filter((c) => c === settings.zeroDigit || c === settings.digit).length;
12220
+ if (groupSize > 0) {
12221
+ integerPart = this.applyGrouping(integerPart, settings.groupingSeparator, groupSize);
12222
+ }
12223
+ }
12224
+ const numberText = fractionPart.length > 0 ? `${integerPart}${settings.decimalSeparator}${fractionPart}` : integerPart;
12225
+ if (isNegative && subPictures.length < 2) {
12226
+ return `${settings.minusSign}${prefix}${numberText}${suffix}`;
12227
+ }
12228
+ return `${prefix}${numberText}${suffix}`;
12229
+ }
12230
+ applyGrouping(numberText, separator, groupSize) {
12231
+ if (groupSize <= 0 || numberText.length <= groupSize) {
12232
+ return numberText;
12233
+ }
12234
+ const chunks = [];
12235
+ for (let i = numberText.length; i > 0; i -= groupSize) {
12236
+ const start = Math.max(0, i - groupSize);
12237
+ chunks.unshift(numberText.slice(start, i));
12238
+ }
12239
+ return chunks.join(separator);
12240
+ }
12241
+ leftPad(value, width, fillChar) {
12242
+ if (value.length >= width) {
12243
+ return value;
12244
+ }
12245
+ const padChar = fillChar && fillChar.length > 0 ? fillChar.charAt(0) : "0";
12246
+ const missing = width - value.length;
12247
+ let padding = "";
12248
+ for (let i = 0; i < missing; i++) {
12249
+ padding += padChar;
12250
+ }
12251
+ return padding + value;
12252
+ }
12145
12253
  /**
12146
12254
  * Convert an XPathNode interface tree to actual XNode objects.
12147
12255
  * This is needed to convert json-to-xml() output to XSLT-compatible nodes.
@@ -12154,7 +12262,11 @@ var NodeConverter = class {
12154
12262
  if (xpathNode.nodeType === DOM_DOCUMENT_NODE) {
12155
12263
  if (xpathNode.childNodes && xpathNode.childNodes.length > 0) {
12156
12264
  const rootChild = xpathNode.childNodes[0];
12157
- node = this.convertXPathNodeToXNode(rootChild, ownerDoc);
12265
+ const convertedNode = this.convertXPathNodeToXNode(rootChild, ownerDoc);
12266
+ if (!convertedNode) {
12267
+ return null;
12268
+ }
12269
+ node = convertedNode;
12158
12270
  return node;
12159
12271
  }
12160
12272
  return null;
@@ -15387,7 +15499,7 @@ var Xslt = class {
15387
15499
  );
15388
15500
  if (onCompletionElements.length > 0) {
15389
15501
  const onCompletion = onCompletionElements[0];
15390
- const completionContext = context.clone([], 0);
15502
+ const completionContext = context.clone();
15391
15503
  for (const accName in accumulators) {
15392
15504
  completionContext.variables[accName] = accumulators[accName];
15393
15505
  }