@tradik/xslt3 0.0.0-stage → 1.0.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.
Files changed (286) hide show
  1. package/LICENSE.md +28 -0
  2. package/README.md +98 -2
  3. package/package.json +43 -4
  4. package/src/errors.js +20 -0
  5. package/src/functions/aggregates.js +144 -0
  6. package/src/functions/arraySort.js +33 -0
  7. package/src/functions/arrays.js +181 -0
  8. package/src/functions/attributeTypes.js +58 -0
  9. package/src/functions/baseUris.js +82 -0
  10. package/src/functions/collations.js +127 -0
  11. package/src/functions/collections.js +84 -0
  12. package/src/functions/context.js +83 -0
  13. package/src/functions/core.js +167 -0
  14. package/src/functions/datetime.js +203 -0
  15. package/src/functions/deepEqual.js +132 -0
  16. package/src/functions/diagnostics.js +88 -0
  17. package/src/functions/focus.js +34 -0
  18. package/src/functions/format/dateComponents.js +176 -0
  19. package/src/functions/format/datePicture.js +115 -0
  20. package/src/functions/format/decimalFormat.js +65 -0
  21. package/src/functions/format/digitPattern.js +145 -0
  22. package/src/functions/format/formatDateTime.js +204 -0
  23. package/src/functions/format/formatInteger.js +109 -0
  24. package/src/functions/format/formatNumber.js +165 -0
  25. package/src/functions/format/fractionFormat.js +80 -0
  26. package/src/functions/format/germanWords.js +89 -0
  27. package/src/functions/format/numberLanguages.js +41 -0
  28. package/src/functions/format/numberPicture.js +202 -0
  29. package/src/functions/format/numberWords.js +155 -0
  30. package/src/functions/format/place.js +74 -0
  31. package/src/functions/format/timezoneFormat.js +89 -0
  32. package/src/functions/higherOrder.js +106 -0
  33. package/src/functions/ids.js +127 -0
  34. package/src/functions/json/index.js +17 -0
  35. package/src/functions/json/jsonChars.js +110 -0
  36. package/src/functions/json/jsonParser.js +203 -0
  37. package/src/functions/json/jsonStrings.js +116 -0
  38. package/src/functions/json/jsonToXml.js +116 -0
  39. package/src/functions/json/parseJson.js +119 -0
  40. package/src/functions/json/xmlRepresentation.js +103 -0
  41. package/src/functions/json/xmlToJson.js +147 -0
  42. package/src/functions/library.js +47 -0
  43. package/src/functions/mapArrayEqual.js +41 -0
  44. package/src/functions/maps.js +152 -0
  45. package/src/functions/math.js +73 -0
  46. package/src/functions/nodePaths.js +181 -0
  47. package/src/functions/nodes.js +199 -0
  48. package/src/functions/numeric.js +148 -0
  49. package/src/functions/options.js +58 -0
  50. package/src/functions/parseIetfDate.js +104 -0
  51. package/src/functions/parseXml.js +77 -0
  52. package/src/functions/qnames.js +68 -0
  53. package/src/functions/random.js +128 -0
  54. package/src/functions/regex/analyzeString.js +144 -0
  55. package/src/functions/regex/charClass.js +112 -0
  56. package/src/functions/regex/compile.js +81 -0
  57. package/src/functions/regex/escapes.js +109 -0
  58. package/src/functions/regex/parser.js +169 -0
  59. package/src/functions/regex/reader.js +37 -0
  60. package/src/functions/regex/regexFunctions.js +140 -0
  61. package/src/functions/regex/translate.js +102 -0
  62. package/src/functions/regex/unicodeBlocks.js +194 -0
  63. package/src/functions/registry.js +140 -0
  64. package/src/functions/sequences.js +173 -0
  65. package/src/functions/serializeFunction.js +53 -0
  66. package/src/functions/signatures.js +105 -0
  67. package/src/functions/sort.js +102 -0
  68. package/src/functions/stringMatch.js +45 -0
  69. package/src/functions/strings.js +194 -0
  70. package/src/functions/stringsCore.js +66 -0
  71. package/src/functions/support.js +106 -0
  72. package/src/functions/textDecoding.js +117 -0
  73. package/src/functions/ucaCollation.js +127 -0
  74. package/src/functions/unparsedText.js +71 -0
  75. package/src/functions/uri.js +166 -0
  76. package/src/functions/xqueryModule.js +24 -0
  77. package/src/index.js +38 -0
  78. package/src/items/array.js +84 -0
  79. package/src/items/function.js +45 -0
  80. package/src/items/map.js +120 -0
  81. package/src/items/mapKey.js +82 -0
  82. package/src/serialize/index.js +129 -0
  83. package/src/serialize/markup/content.js +74 -0
  84. package/src/serialize/markup/dialect.js +178 -0
  85. package/src/serialize/markup/htmlData.js +70 -0
  86. package/src/serialize/markup/namespaces.js +145 -0
  87. package/src/serialize/markup/prolog.js +91 -0
  88. package/src/serialize/markup/writer.js +183 -0
  89. package/src/serialize/methods/adaptive.js +131 -0
  90. package/src/serialize/methods/json.js +158 -0
  91. package/src/serialize/methods/text.js +43 -0
  92. package/src/serialize/output/buffer.js +48 -0
  93. package/src/serialize/output/encoding.js +146 -0
  94. package/src/serialize/output/expander.js +204 -0
  95. package/src/serialize/params/fromElement.js +141 -0
  96. package/src/serialize/params/fromMap.js +128 -0
  97. package/src/serialize/params/names.js +69 -0
  98. package/src/serialize/params/settings.js +153 -0
  99. package/src/serialize/params/values.js +163 -0
  100. package/src/serialize/sequence.js +111 -0
  101. package/src/xdm/arithmetic.js +155 -0
  102. package/src/xdm/atomic.js +142 -0
  103. package/src/xdm/binary.js +92 -0
  104. package/src/xdm/calendar.js +71 -0
  105. package/src/xdm/cast.js +176 -0
  106. package/src/xdm/compare.js +192 -0
  107. package/src/xdm/datetime.js +206 -0
  108. package/src/xdm/decimal.js +200 -0
  109. package/src/xdm/duration.js +128 -0
  110. package/src/xdm/generalCompare.js +152 -0
  111. package/src/xdm/index.js +47 -0
  112. package/src/xdm/lexical.js +126 -0
  113. package/src/xdm/nodes.js +170 -0
  114. package/src/xdm/numeric.js +122 -0
  115. package/src/xdm/qname.js +65 -0
  116. package/src/xdm/strings.js +52 -0
  117. package/src/xdm/temporalArithmetic.js +180 -0
  118. package/src/xdm/timeline.js +68 -0
  119. package/src/xdm/types.js +178 -0
  120. package/src/xpath/eval/atomics.js +45 -0
  121. package/src/xpath/eval/axes.js +212 -0
  122. package/src/xpath/eval/calls.js +168 -0
  123. package/src/xpath/eval/coercion.js +146 -0
  124. package/src/xpath/eval/compiler.js +71 -0
  125. package/src/xpath/eval/constructors.js +129 -0
  126. package/src/xpath/eval/decimalFormats.js +93 -0
  127. package/src/xpath/eval/descendantMemo.js +77 -0
  128. package/src/xpath/eval/documentOrder.js +142 -0
  129. package/src/xpath/eval/domNodes.js +174 -0
  130. package/src/xpath/eval/dynamicCall.js +27 -0
  131. package/src/xpath/eval/dynamicContext.js +161 -0
  132. package/src/xpath/eval/flow.js +115 -0
  133. package/src/xpath/eval/functionItems.js +194 -0
  134. package/src/xpath/eval/groupedChildren.js +88 -0
  135. package/src/xpath/eval/inline.js +71 -0
  136. package/src/xpath/eval/namespaceNodes.js +90 -0
  137. package/src/xpath/eval/nodeTests.js +164 -0
  138. package/src/xpath/eval/operators.js +190 -0
  139. package/src/xpath/eval/paths.js +163 -0
  140. package/src/xpath/eval/positional.js +81 -0
  141. package/src/xpath/eval/predicates.js +56 -0
  142. package/src/xpath/eval/primary.js +99 -0
  143. package/src/xpath/eval/resources.js +149 -0
  144. package/src/xpath/eval/scope.js +108 -0
  145. package/src/xpath/eval/sequenceType.js +193 -0
  146. package/src/xpath/eval/staticContext.js +142 -0
  147. package/src/xpath/eval/steps.js +98 -0
  148. package/src/xpath/eval/subtype.js +154 -0
  149. package/src/xpath/eval/typeExprs.js +147 -0
  150. package/src/xpath/eval/typeNames.js +101 -0
  151. package/src/xpath/eval/uris.js +21 -0
  152. package/src/xpath/eval/values.js +64 -0
  153. package/src/xpath/index.js +217 -0
  154. package/src/xpath/syntax/ast.js +130 -0
  155. package/src/xpath/syntax/chars.js +58 -0
  156. package/src/xpath/syntax/constructors.js +144 -0
  157. package/src/xpath/syntax/expressions.js +107 -0
  158. package/src/xpath/syntax/index.js +44 -0
  159. package/src/xpath/syntax/kindTests.js +134 -0
  160. package/src/xpath/syntax/lexer.js +220 -0
  161. package/src/xpath/syntax/operators.js +111 -0
  162. package/src/xpath/syntax/paths.js +102 -0
  163. package/src/xpath/syntax/postfix.js +91 -0
  164. package/src/xpath/syntax/primaries.js +149 -0
  165. package/src/xpath/syntax/steps.js +146 -0
  166. package/src/xpath/syntax/syntaxError.js +31 -0
  167. package/src/xpath/syntax/tokenStream.js +163 -0
  168. package/src/xpath/syntax/typeAst.js +76 -0
  169. package/src/xpath/syntax/typeOperators.js +127 -0
  170. package/src/xpath/syntax/types.js +158 -0
  171. package/src/xslt/api.js +153 -0
  172. package/src/xslt/compiler/acceptance.js +178 -0
  173. package/src/xslt/compiler/accumulatorDecl.js +146 -0
  174. package/src/xslt/compiler/attributeValues.js +174 -0
  175. package/src/xslt/compiler/attributes.js +211 -0
  176. package/src/xslt/compiler/avt.js +103 -0
  177. package/src/xslt/compiler/body.js +154 -0
  178. package/src/xslt/compiler/children.js +105 -0
  179. package/src/xslt/compiler/compatibility.js +130 -0
  180. package/src/xslt/compiler/components.js +179 -0
  181. package/src/xslt/compiler/contextItem.js +95 -0
  182. package/src/xslt/compiler/decimalFormats.js +132 -0
  183. package/src/xslt/compiler/declarationKinds.js +82 -0
  184. package/src/xslt/compiler/elementInfo.js +246 -0
  185. package/src/xslt/compiler/expressions.js +175 -0
  186. package/src/xslt/compiler/globalContextItem.js +92 -0
  187. package/src/xslt/compiler/globals.js +209 -0
  188. package/src/xslt/compiler/linker.js +134 -0
  189. package/src/xslt/compiler/miscDecl.js +171 -0
  190. package/src/xslt/compiler/modeDecl.js +88 -0
  191. package/src/xslt/compiler/moduleLoading.js +111 -0
  192. package/src/xslt/compiler/modules.js +158 -0
  193. package/src/xslt/compiler/outputDecl.js +209 -0
  194. package/src/xslt/compiler/overrideLinks.js +141 -0
  195. package/src/xslt/compiler/packageChecks.js +84 -0
  196. package/src/xslt/compiler/packageRegistry.js +95 -0
  197. package/src/xslt/compiler/packageTable.js +181 -0
  198. package/src/xslt/compiler/packageVersions.js +143 -0
  199. package/src/xslt/compiler/packages.js +138 -0
  200. package/src/xslt/compiler/registry.js +234 -0
  201. package/src/xslt/compiler/staticStage.js +197 -0
  202. package/src/xslt/compiler/staticVariables.js +93 -0
  203. package/src/xslt/compiler/stylesheet.js +205 -0
  204. package/src/xslt/compiler/tailPosition.js +74 -0
  205. package/src/xslt/compiler/templatesDecl.js +180 -0
  206. package/src/xslt/compiler/useAccumulators.js +76 -0
  207. package/src/xslt/compiler/useWhen.js +94 -0
  208. package/src/xslt/compiler/visibility.js +160 -0
  209. package/src/xslt/index.js +11 -0
  210. package/src/xslt/instructions/analyzeString.js +137 -0
  211. package/src/xslt/instructions/assert.js +72 -0
  212. package/src/xslt/instructions/attributeSets.js +115 -0
  213. package/src/xslt/instructions/conditional.js +99 -0
  214. package/src/xslt/instructions/control.js +123 -0
  215. package/src/xslt/instructions/copy.js +151 -0
  216. package/src/xslt/instructions/elements.js +161 -0
  217. package/src/xslt/instructions/evaluate.js +189 -0
  218. package/src/xslt/instructions/fork.js +35 -0
  219. package/src/xslt/instructions/grouping.js +106 -0
  220. package/src/xslt/instructions/index.js +94 -0
  221. package/src/xslt/instructions/iterate.js +182 -0
  222. package/src/xslt/instructions/literal.js +142 -0
  223. package/src/xslt/instructions/maps.js +72 -0
  224. package/src/xslt/instructions/merge.js +190 -0
  225. package/src/xslt/instructions/number.js +205 -0
  226. package/src/xslt/instructions/output.js +102 -0
  227. package/src/xslt/instructions/params.js +110 -0
  228. package/src/xslt/instructions/resultDocument.js +143 -0
  229. package/src/xslt/instructions/sort.js +114 -0
  230. package/src/xslt/instructions/sourceDocument.js +73 -0
  231. package/src/xslt/instructions/templates.js +153 -0
  232. package/src/xslt/instructions/text.js +151 -0
  233. package/src/xslt/instructions/try.js +186 -0
  234. package/src/xslt/instructions/variables.js +119 -0
  235. package/src/xslt/names.js +204 -0
  236. package/src/xslt/patterns/axisOrigins.js +121 -0
  237. package/src/xslt/patterns/compile.js +151 -0
  238. package/src/xslt/patterns/general.js +132 -0
  239. package/src/xslt/patterns/grammar.js +190 -0
  240. package/src/xslt/patterns/modes.js +153 -0
  241. package/src/xslt/patterns/paths.js +130 -0
  242. package/src/xslt/patterns/patternChecks.js +29 -0
  243. package/src/xslt/patterns/steps.js +162 -0
  244. package/src/xslt/processor.js +178 -0
  245. package/src/xslt/runtime/accumulatorFunctions.js +48 -0
  246. package/src/xslt/runtime/accumulators.js +174 -0
  247. package/src/xslt/runtime/apply.js +153 -0
  248. package/src/xslt/runtime/atomicKeys.js +36 -0
  249. package/src/xslt/runtime/availability.js +162 -0
  250. package/src/xslt/runtime/baseUri.js +64 -0
  251. package/src/xslt/runtime/compilerHook.js +27 -0
  252. package/src/xslt/runtime/conditional.js +110 -0
  253. package/src/xslt/runtime/context.js +106 -0
  254. package/src/xslt/runtime/copy.js +123 -0
  255. package/src/xslt/runtime/copyFunctions.js +71 -0
  256. package/src/xslt/runtime/copyOrigins.js +60 -0
  257. package/src/xslt/runtime/defaultMethod.js +42 -0
  258. package/src/xslt/runtime/documentContent.js +93 -0
  259. package/src/xslt/runtime/dynamicXPath.js +90 -0
  260. package/src/xslt/runtime/functionCache.js +65 -0
  261. package/src/xslt/runtime/functionCall.js +57 -0
  262. package/src/xslt/runtime/functions.js +191 -0
  263. package/src/xslt/runtime/groups.js +108 -0
  264. package/src/xslt/runtime/invocation.js +156 -0
  265. package/src/xslt/runtime/iteration.js +107 -0
  266. package/src/xslt/runtime/keys.js +141 -0
  267. package/src/xslt/runtime/lazy.js +97 -0
  268. package/src/xslt/runtime/locations.js +86 -0
  269. package/src/xslt/runtime/machine.js +137 -0
  270. package/src/xslt/runtime/merging.js +167 -0
  271. package/src/xslt/runtime/namespaceScope.js +141 -0
  272. package/src/xslt/runtime/numberFormat.js +89 -0
  273. package/src/xslt/runtime/numbering.js +168 -0
  274. package/src/xslt/runtime/params.js +59 -0
  275. package/src/xslt/runtime/properties.js +103 -0
  276. package/src/xslt/runtime/rawResults.js +82 -0
  277. package/src/xslt/runtime/sequenceReceiver.js +102 -0
  278. package/src/xslt/runtime/snapshot.js +66 -0
  279. package/src/xslt/runtime/sortKeys.js +119 -0
  280. package/src/xslt/runtime/streamAvailable.js +60 -0
  281. package/src/xslt/runtime/strip.js +102 -0
  282. package/src/xslt/runtime/transformFunction.js +169 -0
  283. package/src/xslt/runtime/transformation.js +168 -0
  284. package/src/xslt/runtime/transformationContext.js +85 -0
  285. package/src/xslt/runtime/treeReceiver.js +194 -0
  286. package/src/xslt/runtime/values.js +92 -0
@@ -0,0 +1,168 @@
1
+ /**
2
+ * A transformation (XSLT 3.0 section 2.3): the dynamic context shared by
3
+ * every instruction, whitespace stripping of the source documents, the
4
+ * global variables evaluated on first use, and the results collected.
5
+ *
6
+ * @module @tradik/xslt3/xslt/runtime/transformation
7
+ */
8
+
9
+ import { withinLimits } from "../../xpath/eval/compiler.js";
10
+ import { isEligibleMode } from "../compiler/packageChecks.js";
11
+ import { displayName, xsltError } from "../names.js";
12
+ import {
13
+ checkLibraryContextItems,
14
+ globalContextItem,
15
+ } from "../compiler/globalContextItem.js";
16
+ import { setInitialAccumulators } from "./accumulators.js";
17
+ import { withDefaultMethod } from "./defaultMethod.js";
18
+ import { finishTree, invoke } from "./invocation.js";
19
+ import { LazyEntry } from "./lazy.js";
20
+ import { Machine } from "./machine.js";
21
+ import { normalizeParams } from "./params.js";
22
+ import { isStrippedText } from "./strip.js";
23
+ import {
24
+ documentStripper,
25
+ transformationContext,
26
+ } from "./transformationContext.js";
27
+
28
+ /**
29
+ * The lazily evaluated entries of the global variables.
30
+ * @param {object} tx
31
+ * @param {Map<string, Array>} params - Supplied stylesheet parameters
32
+ * @returns {object|null} the environment (see xpath/eval/scope.js)
33
+ */
34
+ function globalEnvironment(tx, params) {
35
+ let env = null;
36
+ for (const global of tx.stylesheet.globals) {
37
+ if (global.required && !params.has(global.key)) {
38
+ throw xsltError(
39
+ "XTDE0050",
40
+ `The parameter $${displayName(global.key)} is required`,
41
+ );
42
+ }
43
+ const compute =
44
+ global.isParam && params.has(global.key)
45
+ ? () => global.convert(params.get(global.key))
46
+ : () => global.value(tx.globalContext, tx.machine);
47
+ env = new LazyEntry(env, compute, global.key, true);
48
+ }
49
+ return env;
50
+ }
51
+
52
+ /**
53
+ * The document factory of a transformation: the option, else the DOM of
54
+ * the source, else the DOM of the stylesheet (a transformation without a
55
+ * source, from an initial template), else the global document.
56
+ * @param {object} options
57
+ * @param {object} stylesheet - Compiled stylesheet (its module tree)
58
+ * @returns {() => Document}
59
+ */
60
+ function documentFactory(options, stylesheet) {
61
+ if (options.createDocument) return options.createDocument;
62
+ return () => {
63
+ const owner =
64
+ options.source?.ownerDocument ??
65
+ options.source ??
66
+ stylesheet.tree.root.ownerDocument;
67
+ const implementation =
68
+ owner?.implementation ?? globalThis.document?.implementation;
69
+ if (!implementation) {
70
+ throw xsltError(
71
+ "XPDY0130",
72
+ "No DOM to build results: pass createDocument",
73
+ );
74
+ }
75
+ return implementation.createDocument(null, null, null);
76
+ };
77
+ }
78
+
79
+ /**
80
+ * The initial mode: `#unnamed`, `#default` or a Clark name of a mode
81
+ * eligible as initial mode (XTDE0045).
82
+ * @param {object} stylesheet
83
+ * @param {string|undefined} requested - Option initialMode
84
+ * @returns {object} the mode
85
+ */
86
+ function initialMode(stylesheet, requested) {
87
+ const token = requested?.replace(/^\{\}(?=#)/, "");
88
+ if (token === undefined || token === "#default") {
89
+ return stylesheet.mode(stylesheet.defaultModeName);
90
+ }
91
+ const name = token === "#unnamed" ? "" : token;
92
+ if (!isEligibleMode(stylesheet, name)) {
93
+ throw xsltError("XTDE0045", `The mode ${requested} is not eligible`);
94
+ }
95
+ return stylesheet.mode(name);
96
+ }
97
+
98
+ /**
99
+ * Runs a transformation.
100
+ * @param {object} stylesheet - Compiled stylesheet (StylesheetCompiler)
101
+ * @param {object} options - See CompiledStylesheet.transform
102
+ * @returns {{principal: Node|Array, secondary: Map<string, object>,
103
+ * messages: Array}}
104
+ */
105
+ export function runTransformation(stylesheet, options) {
106
+ checkLibraryContextItems(stylesheet);
107
+ const createDocument = documentFactory(options, stylesheet);
108
+ let scratchDocument = null;
109
+ const strip = documentStripper();
110
+ // a source text node that stripping removes is no source (XPDY0002)
111
+ const source = isStrippedText(options.source ?? {}, stylesheet.spaceRules)
112
+ ? undefined
113
+ : strip(options.source, stylesheet.spaceRules);
114
+ const tx = {
115
+ stylesheet,
116
+ options,
117
+ machine: new Machine(options.maxDepth),
118
+ scratch: () => (scratchDocument ??= createDocument()),
119
+ messages: [],
120
+ onMessage: options.onMessage,
121
+ resultUris: new Set(),
122
+ baseOutputUri: options.baseOutputUri,
123
+ secondary: new Map(),
124
+ keyIndexes: new Map(),
125
+ defaultMode: initialMode(stylesheet, options.initialMode),
126
+ principalOverride: null,
127
+ dynamicEvaluation: options.dynamicEvaluation !== false,
128
+ assertions: options.assertions !== false,
129
+ principalOutput: null,
130
+ dyn: transformationContext(stylesheet, options, strip, createDocument),
131
+ };
132
+ tx.addResult = (uri, fragment, output) => {
133
+ const tree = Array.isArray(fragment)
134
+ ? fragment
135
+ : finishTree(fragment, createDocument);
136
+ const params = withDefaultMethod(output, tree);
137
+ if (uri === "") {
138
+ tx.principalOverride = tree;
139
+ tx.principalOutput = params;
140
+ } else tx.secondary.set(uri, { document: tree, output: params });
141
+ };
142
+ tx.globalContext = {
143
+ tx,
144
+ item: globalContextItem(
145
+ stylesheet.globalContextItem,
146
+ options.globalContextItem ?? source,
147
+ ),
148
+ position: 1,
149
+ size: 1,
150
+ env: null,
151
+ mode: tx.defaultMode,
152
+ rule: null,
153
+ group: undefined,
154
+ groupKey: undefined,
155
+ regex: undefined,
156
+ tunnel: null,
157
+ temporary: false,
158
+ outputUri: options.baseOutputUri,
159
+ dyn: null,
160
+ };
161
+ setInitialAccumulators(tx, options, source);
162
+ tx.globalEnv = globalEnvironment(
163
+ tx,
164
+ normalizeParams(options.params, options.paramsAsUntyped),
165
+ );
166
+ tx.globalContext.env = tx.globalEnv;
167
+ return withinLimits(() => invoke(tx, options, source, createDocument));
168
+ }
@@ -0,0 +1,85 @@
1
+ /**
2
+ * The XPath dynamic context of a transformation: the resources it reads
3
+ * (documents, text, collections) with relative URIs resolved against the
4
+ * base URI of the calling expression, and the documents it loads stripped
5
+ * of whitespace by the xsl:strip-space rules of the package of that
6
+ * expression (XSLT 3.0 section 4.3).
7
+ *
8
+ * @module @tradik/xslt3/xslt/runtime/transformationContext
9
+ */
10
+
11
+ import { createDynamicContext } from "../../xpath/eval/dynamicContext.js";
12
+ import { resolveUri } from "../../xpath/eval/uris.js";
13
+ import { stripDocument } from "./strip.js";
14
+
15
+ /**
16
+ * Whitespace stripping of loaded documents, once per document and rule
17
+ * set, so that a document read twice by one package is one node.
18
+ * @returns {(document: Node, rules: object[]) => Node}
19
+ */
20
+ export function documentStripper() {
21
+ const copies = new WeakMap();
22
+ return (document, rules) => {
23
+ if (document?.nodeType !== 9) return document;
24
+ let byRules = copies.get(document);
25
+ if (!byRules) copies.set(document, (byRules = new Map()));
26
+ let stripped = byRules.get(rules);
27
+ if (!stripped) {
28
+ stripped = stripDocument(document, rules);
29
+ byRules.set(rules, stripped);
30
+ }
31
+ return stripped;
32
+ };
33
+ }
34
+
35
+ /**
36
+ * Builds the dynamic context of a transformation.
37
+ * @param {object} stylesheet - The top-level package's compiler
38
+ * @param {object} options - See CompiledStylesheet.transform
39
+ * @param {(document: Node, rules: object[]) => Node} strip - From
40
+ * {@link documentStripper}
41
+ * @param {() => Document} createDocument
42
+ * @returns {object}
43
+ */
44
+ export function transformationContext(
45
+ stylesheet,
46
+ options,
47
+ strip,
48
+ createDocument,
49
+ ) {
50
+ const dyn = createDynamicContext(
51
+ stylesheet.sc,
52
+ {
53
+ documentLoader: options.documentLoader,
54
+ createDocument,
55
+ implicitTimezone: options.implicitTimezone,
56
+ currentDateTime: options.currentDateTime,
57
+ textLoader: options.textLoader,
58
+ xmlParser: options.xmlParser,
59
+ collections: options.collections,
60
+ },
61
+ options.source,
62
+ );
63
+ const { loadDocument, loadText, collection } = dyn;
64
+ /** @this {object} the dynamic context of the calling expression */
65
+ function rulesOf() {
66
+ return (this.sc?.owner ?? stylesheet).spaceRules ?? stylesheet.spaceRules;
67
+ }
68
+ // `this` is the dynamic context of the calling expression
69
+ dyn.loadDocument = function load(uri) {
70
+ const base = this.staticBaseUri;
71
+ const document = loadDocument(resolveUri(uri, base), base);
72
+ return strip(document, rulesOf.call(this));
73
+ };
74
+ dyn.loadText = function loadTextFrom(href, encoding) {
75
+ return loadText(href, encoding, this.staticBaseUri);
76
+ };
77
+ dyn.collection = function collectionFrom(href) {
78
+ const rules = rulesOf.call(this);
79
+ return collection(href, this.staticBaseUri).map((item) =>
80
+ strip(item, rules),
81
+ );
82
+ };
83
+ dyn.xc = null;
84
+ return dyn;
85
+ }
@@ -0,0 +1,194 @@
1
+ /**
2
+ * The receiver that builds the content of a node in a result tree
3
+ * (XSLT 3.0 section 5.7.1, constructing complex content): adjacent
4
+ * atomic values become text separated by spaces, document nodes are
5
+ * replaced by their children, adjacent text is merged, attributes and
6
+ * namespaces must come before children, and namespace declarations are
7
+ * added where names need them.
8
+ *
9
+ * @module @tradik/xslt3/xslt/runtime/treeReceiver
10
+ */
11
+
12
+ import { isArray, isAtomic, isFunctionItem } from "../../xdm/atomic.js";
13
+ import { canonicalString } from "../../xdm/lexical.js";
14
+ import { xsltError } from "../names.js";
15
+ import { copyNode } from "./copy.js";
16
+ import { DocumentContent } from "./documentContent.js";
17
+ import { NamespaceScope, prefixOf } from "./namespaceScope.js";
18
+
19
+ export { prefixOf };
20
+
21
+ /** Builds the children (and attributes) of an element or document. */
22
+ export class TreeReceiver extends NamespaceScope {
23
+ /**
24
+ * @param {Node} parent - Element, document or document fragment
25
+ * @param {Map<string, string>} namespaces - In scope at the parent
26
+ */
27
+ constructor(parent, namespaces) {
28
+ super(parent, namespaces);
29
+ this.doc = parent.nodeType === 9 ? parent : parent.ownerDocument;
30
+ this.hasChildren = false;
31
+ this.lastAtomic = false;
32
+ /** @type {boolean} the receiver of the top of a result tree */
33
+ this.resultTree = false;
34
+ }
35
+
36
+ /**
37
+ * Appends a child node.
38
+ * @param {Node} node
39
+ */
40
+ append(node) {
41
+ this.parent.appendChild(node);
42
+ this.hasChildren = true;
43
+ this.lastAtomic = false;
44
+ }
45
+
46
+ /**
47
+ * Starts an element child.
48
+ * @param {string} uri - Namespace URI, "" for none
49
+ * @param {string} qname - Lexical name
50
+ * @returns {TreeReceiver} the receiver of its content (`.parent` is it)
51
+ */
52
+ element(uri, qname) {
53
+ const element = this.doc.createElementNS(uri || null, qname);
54
+ this.append(element);
55
+ const content = new TreeReceiver(element, this.namespaces);
56
+ content.declare(prefixOf(qname), uri);
57
+ return content;
58
+ }
59
+
60
+ /**
61
+ * Checks that an attribute or namespace may be added now.
62
+ * @param {string} what
63
+ */
64
+ checkAttributePosition(what) {
65
+ if (this.parent.nodeType !== 1) {
66
+ throw xsltError("XTDE0420", `A ${what} cannot be added to a document`);
67
+ }
68
+ if (this.hasChildren) {
69
+ throw xsltError(
70
+ "XTDE0410",
71
+ `A ${what} cannot be added after the children of an element`,
72
+ );
73
+ }
74
+ }
75
+
76
+ /**
77
+ * Adds an attribute (replacing one of the same name); its prefix is
78
+ * changed when the element binds it to another namespace.
79
+ * @param {string} uri
80
+ * @param {string} qname
81
+ * @param {string} value
82
+ */
83
+ attribute(uri, qname, value) {
84
+ this.checkAttributePosition("attribute");
85
+ let name = qname;
86
+ if (uri) {
87
+ let prefix = prefixOf(qname);
88
+ const local = qname.slice(prefix.length ? prefix.length + 1 : 0);
89
+ if (prefix === "" || !this.declare(prefix, uri)) {
90
+ prefix = this.prefixFor(uri, prefix);
91
+ }
92
+ name = `${prefix}:${local}`;
93
+ const existing = this.parent.getAttributeNodeNS(uri, local);
94
+ if (existing) this.parent.removeAttributeNode(existing);
95
+ }
96
+ this.parent.setAttributeNS(uri || null, name, value);
97
+ this.lastAtomic = false;
98
+ }
99
+
100
+ /**
101
+ * Adds a namespace node.
102
+ * @param {string} prefix
103
+ * @param {string} uri
104
+ */
105
+ namespace(prefix, uri) {
106
+ this.checkAttributePosition("namespace node");
107
+ if (prefix === "" && this.parent.namespaceURI === null && uri !== "") {
108
+ throw xsltError(
109
+ "XTDE0440",
110
+ "A default namespace cannot be added to an element in no namespace",
111
+ );
112
+ }
113
+ if (
114
+ !this.declareExplicit(prefix, uri) &&
115
+ !(this.rebind(prefix, uri) && this.explicit.add(prefix))
116
+ ) {
117
+ throw xsltError(
118
+ "XTDE0430",
119
+ `The prefix "${prefix}" is already bound to another namespace`,
120
+ );
121
+ }
122
+ this.lastAtomic = false;
123
+ }
124
+
125
+ /**
126
+ * Adds text (merged with preceding text); zero-length text adds no node
127
+ * but separates atomic values.
128
+ * @param {string} text
129
+ */
130
+ text(text) {
131
+ if (text === "") {
132
+ this.lastAtomic = false;
133
+ return;
134
+ }
135
+ const last = this.parent.lastChild;
136
+ if (last && last.nodeType === 3) last.appendData(text);
137
+ else this.append(this.doc.createTextNode(text));
138
+ this.hasChildren = true;
139
+ this.lastAtomic = false;
140
+ }
141
+
142
+ /** @param {string} text */
143
+ comment(text) {
144
+ this.append(this.doc.createComment(text));
145
+ }
146
+
147
+ /**
148
+ * @param {string} target
149
+ * @param {string} data
150
+ */
151
+ pi(target, data) {
152
+ this.append(this.doc.createProcessingInstruction(target, data));
153
+ }
154
+
155
+ /** @param {import("../../xdm/atomic.js").AtomicValue} value */
156
+ atomic(value) {
157
+ const text = canonicalString(value);
158
+ this.text(this.lastAtomic ? ` ${text}` : text);
159
+ this.lastAtomic = true;
160
+ }
161
+
162
+ /**
163
+ * Adds an item of a sequence: nodes are copied, arrays flattened.
164
+ * @param {*} item
165
+ */
166
+ item(item) {
167
+ if (isAtomic(item)) this.atomic(item);
168
+ else if (isArray(item)) {
169
+ for (const member of item.members) for (const x of member) this.item(x);
170
+ } else if (isFunctionItem(item)) {
171
+ // the top of a result tree is built by sequence normalization
172
+ // (XSLT 3.0 section 2.3.6), whose error is SENR0001
173
+ throw xsltError(
174
+ this.resultTree ? "SENR0001" : "XTDE0450",
175
+ "A function item cannot be added to a tree",
176
+ );
177
+ } else this.copy(item, true);
178
+ }
179
+
180
+ /**
181
+ * Copies a node and its descendants.
182
+ * @param {Node} node
183
+ * @param {boolean} copyNamespaces
184
+ */
185
+ copy(node, copyNamespaces) {
186
+ copyNode(node, this, copyNamespaces);
187
+ }
188
+
189
+ /** @returns {DocumentContent} the receiver of a document node's content */
190
+ document() {
191
+ this.lastAtomic = false;
192
+ return new DocumentContent(this);
193
+ }
194
+ }
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Values computed from sequence constructors at run time: the sequence a
3
+ * body produces, temporary trees, simple content (XSLT 3.0 section
4
+ * 5.7.2) and attribute value templates.
5
+ *
6
+ * @module @tradik/xslt3/xslt/runtime/values
7
+ */
8
+
9
+ import { atomize } from "../../xdm/nodes.js";
10
+ import { canonicalString } from "../../xdm/lexical.js";
11
+ import { derive, evaluate } from "./context.js";
12
+ import { SequenceReceiver } from "./sequenceReceiver.js";
13
+ import { TreeReceiver } from "./treeReceiver.js";
14
+
15
+ /**
16
+ * Runs a body and returns the sequence it produces.
17
+ * @param {import("./machine.js").Body} body
18
+ * @param {object} xc
19
+ * @param {import("./machine.js").Machine} machine
20
+ * @param {boolean} [temporary] - The body runs in temporary output state
21
+ * (XSLT 3.0 section 25.2: variables, functions, keys, sort keys...),
22
+ * not for the content of xsl:attribute, xsl:value-of, xsl:comment,
23
+ * xsl:message and the like
24
+ * @returns {Array}
25
+ */
26
+ export function bodySequence(body, xc, machine, temporary = true) {
27
+ const out = new SequenceReceiver(xc.tx.scratch);
28
+ const context = temporary ? derive(xc, { temporary: true }) : xc;
29
+ machine.runBody(body, context, out);
30
+ return out.items;
31
+ }
32
+
33
+ /**
34
+ * Runs a body to build a temporary tree.
35
+ * @param {import("./machine.js").Body} body
36
+ * @param {object} xc
37
+ * @param {import("./machine.js").Machine} machine
38
+ * @returns {Node} its document node (a document fragment)
39
+ */
40
+ export function temporaryTree(body, xc, machine) {
41
+ const fragment = xc.tx.scratch().createDocumentFragment();
42
+ const out = new TreeReceiver(fragment, new Map());
43
+ machine.runBody(body, derive(xc, { temporary: true }), out);
44
+ return fragment;
45
+ }
46
+
47
+ /**
48
+ * The string of simple content: zero-length text nodes dropped, adjacent
49
+ * text nodes merged, then the items atomized and joined.
50
+ * @param {Array} items
51
+ * @param {string} separator
52
+ * @returns {string}
53
+ */
54
+ export function simpleContent(items, separator) {
55
+ const parts = [];
56
+ let text = null;
57
+ for (const item of items) {
58
+ if (item?.nodeType === 3) {
59
+ if (item.nodeValue !== "") text = (text ?? "") + item.nodeValue;
60
+ continue;
61
+ }
62
+ if (text !== null) parts.push(text);
63
+ text = null;
64
+ for (const value of atomize([item])) parts.push(canonicalString(value));
65
+ }
66
+ if (text !== null) parts.push(text);
67
+ return parts.join(separator);
68
+ }
69
+
70
+ /**
71
+ * Evaluator of a compiled attribute value template.
72
+ * @param {Array<string|object>} parts - See ExpressionCompiler.avt
73
+ * @param {boolean} [compatible] - Backwards-compatible: first item only
74
+ * @returns {(xc: object) => string}
75
+ */
76
+ export function avtEvaluator(parts, compatible = false) {
77
+ if (parts.length === 1 && typeof parts[0] === "string") {
78
+ const constant = parts[0];
79
+ return () => constant;
80
+ }
81
+ return (xc) => {
82
+ let result = "";
83
+ for (const part of parts) {
84
+ if (typeof part === "string") result += part;
85
+ else {
86
+ const value = evaluate(part, xc);
87
+ result += simpleContent(compatible ? value.slice(0, 1) : value, " ");
88
+ }
89
+ }
90
+ return result;
91
+ };
92
+ }