jtlt 0.2.0 → 0.4.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 (70) hide show
  1. package/CHANGES.md +27 -0
  2. package/README.md +61 -164
  3. package/demo/calltemplate-params-demo.js +138 -0
  4. package/demo/codemirror.esm.js +28242 -0
  5. package/demo/codemirror.js +94 -0
  6. package/demo/index.css +7 -0
  7. package/demo/index.html +28 -0
  8. package/demo/index.js +210 -0
  9. package/demo/vendor/jamilih/dist/jml.mjs +2341 -0
  10. package/demo/vendor/jhtml/src/SAJJ/SAJJ.ObjectArrayDelegator.js +356 -0
  11. package/demo/vendor/jhtml/src/SAJJ/SAJJ.Stringifier.js +186 -0
  12. package/demo/vendor/jhtml/src/SAJJ/SAJJ.js +746 -0
  13. package/demo/vendor/jhtml/src/SAJJ/testing/SAJJ.html +33 -0
  14. package/demo/vendor/jhtml/src/SAJJ/testing/SAJJ.testing.js +25 -0
  15. package/demo/vendor/jhtml/src/jhtml-browser.js +5 -0
  16. package/demo/vendor/jhtml/src/jhtml-node.cts +3 -0
  17. package/demo/vendor/jhtml/src/jhtml-node.js +8 -0
  18. package/demo/vendor/jhtml/src/jhtml-node.mts +1 -0
  19. package/demo/vendor/jhtml/src/jhtml.cts +3 -0
  20. package/demo/vendor/jhtml/src/jhtml.js +602 -0
  21. package/demo/vendor/jhtml/src/jhtml.mts +1 -0
  22. package/demo/vendor/jsonpath-plus/dist/index-browser-esm.js +2158 -0
  23. package/demo/vendor/simple-get-json/dist/index-es.js +151 -0
  24. package/demo/xpath2-placeholder.js +1 -0
  25. package/dist/AbstractJoiningTransformer.d.ts +83 -9
  26. package/dist/AbstractJoiningTransformer.d.ts.map +1 -1
  27. package/dist/DOMJoiningTransformer.d.ts +85 -25
  28. package/dist/DOMJoiningTransformer.d.ts.map +1 -1
  29. package/dist/JSONJoiningTransformer.d.ts +159 -51
  30. package/dist/JSONJoiningTransformer.d.ts.map +1 -1
  31. package/dist/JSONPathTransformer.d.ts +37 -38
  32. package/dist/JSONPathTransformer.d.ts.map +1 -1
  33. package/dist/JSONPathTransformerContext.d.ts +334 -124
  34. package/dist/JSONPathTransformerContext.d.ts.map +1 -1
  35. package/dist/StringJoiningTransformer.d.ts +132 -41
  36. package/dist/StringJoiningTransformer.d.ts.map +1 -1
  37. package/dist/XPathTransformer.d.ts +35 -20
  38. package/dist/XPathTransformer.d.ts.map +1 -1
  39. package/dist/XPathTransformerContext.d.ts +281 -105
  40. package/dist/XPathTransformerContext.d.ts.map +1 -1
  41. package/dist/index-browser.d.ts +4 -0
  42. package/dist/index-browser.d.ts.map +1 -0
  43. package/dist/index-node.d.ts +4 -0
  44. package/dist/index-node.d.ts.map +1 -0
  45. package/dist/index.d.ts +330 -57
  46. package/dist/index.d.ts.map +1 -1
  47. package/dist/types.d.ts +204 -0
  48. package/dist/types.d.ts.map +1 -0
  49. package/docs/API.expanded.md +172 -5
  50. package/docs/API.md +92 -2
  51. package/docs/TO-DO.md +168 -0
  52. package/docs/calltemplate-params.md +251 -0
  53. package/eslint.config.js +11 -5
  54. package/package.json +35 -9
  55. package/pnpm-workspace.yaml +1 -0
  56. package/rollup.config.js +13 -0
  57. package/src/AbstractJoiningTransformer.js +54 -15
  58. package/src/DOMJoiningTransformer.js +275 -28
  59. package/src/JSONJoiningTransformer.js +351 -70
  60. package/src/JSONPathTransformer.js +48 -30
  61. package/src/JSONPathTransformerContext.js +729 -107
  62. package/src/StringJoiningTransformer.js +311 -57
  63. package/src/XPathTransformer.js +27 -12
  64. package/src/XPathTransformerContext.js +928 -99
  65. package/src/index-browser.js +5 -0
  66. package/src/index-node.js +7 -0
  67. package/src/index.js +502 -98
  68. package/tsconfig.json +5 -2
  69. package/typings/xpath2-js.d.ts +40 -1
  70. package/src/types/xpath2-js.d.ts +0 -2
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.js"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;GAGG;AACH;;;GAGG;AACH;;;;;GAKG;AACH;;;GAGG;AACH;;;GAGG;AACH;;;GAGG;AAEH;;;;;;GAMG;AAEH;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH;;;GAGG;AACH;;;GAGG;AAEH;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH;;;;;;;;;;GAUG;AAEH;;;;;;;;;;;GAWG;AAEH,oEAAoE;AAEpE;;;;;;GAMG;AAGH,gCAAiC,IAAI,CAAC;yCA3HzB,OAAO,iCAAiC,EAAE,OAAO;sCAIjD,OAAO,8BAA8B,EAAE,OAAO;yCAI9C,OAAO,iCAAiC,EAAE,OAAO,CAAC,QAAQ,CAAC,GACvE,OAAW,iCAAiC,EAAE,OAAO,CAAC,MAAM,CAAC,GAC7D,OAAW,iCAAiC,EAAE,OAAO,CAAC,KAAK,CAAC;oCAIhD,OAAO,4BAA4B,EAAE,OAAO;qCAI5C,OAAO,6BAA6B,EAAE,OAAO;uCAI7C,OAAO,+BAA+B,EAAE,OAAO;;;;6BAM/C,IAAI,IACJ,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,EAAE,OAAO,EACpC,GAAG,CAAC,EAAE;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAC,KAClB,OAAO;;;;2BAKF,IAAI;UAEH,MAAM;;;;cAeN,gBAAgB,CAAC,IAAI,CAAC;;qCAIvB,cAAc,CAAC,0BAA0B,CAAC;kCAI1C,cAAc,CAAC,uBAAuB,CAAC;;;;;;;;;aAOtC,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI;;;;WAEzB,OAAO;;;;;;;;;;;qBAQA,WAAW,KAAK,OAAO;0CACvB,MAAM,KAAK,CAAC,GAAC,GAAG,GAAC,CAAC,GAAG;;;aAG5B,OAAO;;;;;;;kCAOR,eAAe,GAAG;IAC1B,SAAS,CAAC,EAAE,sBAAsB,EAAE,GAClC,gBAAgB,CAAC,0BAA0B,CAAC,CAAC;IAC/C,QAAQ,CAAC,EAAE,sBAAsB,GAC/B,gBAAgB,CAAC,0BAA0B,CAAC,CAAC;IAC/C,KAAK,CAAC,EAAE,gBAAgB,CAAC,0BAA0B,CAAC,CAAC;IACrD,UAAU,CAAC,EAAE,UAAU,CAAA;CACxB;;;;+BAKS,eAAe,GAAG;IAC1B,SAAS,CAAC,EAAE,mBAAmB,EAAE,GAC/B,gBAAgB,CAAC,uBAAuB,CAAC,CAAC;IAC5C,QAAQ,CAAC,EAAE,mBAAmB,GAC5B,gBAAgB,CAAC,uBAAuB,CAAC,CAAC;IAC5C,KAAK,CAAC,EAAE,gBAAgB,CAAC,uBAAuB,CAAC,CAAC;IAClD,UAAU,EAAE,OAAO,CAAC;IACpB,YAAY,CAAC,EAAE,CAAC,GAAC,CAAC,CAAA;CACnB;0BAGU,mBAAmB,GAAG,gBAAgB;;;;;kCAKvC,WAAW,GAAG;IACtB,yBAAyB,CAAC,EAAE,OAAO,CAAA;CACpC"}
@@ -54,7 +54,7 @@ const out = new JTLT({
54
54
  ```ts
55
55
  interface TemplateObject {
56
56
  name?: string; // Optional identifier (for callTemplate)
57
- path: string; // JSONPath or XPath expression
57
+ path?: string; // JSONPath or XPath expression (required for pattern-matching)
58
58
  mode?: string; // Optional mode segregation
59
59
  priority?: number; // Numeric priority (higher wins); fallback uses specificity resolver
60
60
  template(nodeValue, cfg): any; // Executed with `this` bound to context
@@ -62,6 +62,8 @@ interface TemplateObject {
62
62
  ```
63
63
 
64
64
  Edge cases:
65
+ - Either `path` or `name` (or both) must be provided
66
+ - Templates with only `name` (no `path`) are callable only via `callTemplate`
65
67
  - For JSONPath: `path` examples: `$.items[*]`, `$['prop']`, `$..deep`.
66
68
  - For XPath: `//item`, `/root/item`, `//*[@id='x']`.
67
69
  - Root template: path `$` (JSONPath) or `/` (XPath).
@@ -83,17 +85,18 @@ Responsibilities:
83
85
  - Sorts by priority (numeric or specificity resolver).
84
86
  - Invokes winning template; falls back to default rules when no match.
85
87
 
86
- ### `XPathTransformer` (experimental)
88
+ ### `XPathTransformer`
87
89
 
88
90
  Same pattern for XML/HTML DOM data using XPath selectors.
89
91
 
90
92
  Config additions:
91
- - `xpathVersion`: `1` (native `XPathEvaluator`), `2` (`xpath2.js`). Default `1`.
93
+ - `xpathVersion`: `1` (native `XPathEvaluator`), `2` (`xpath2.js`), `3.1` (`fontoxpath`).
94
+ Default `1`.
92
95
 
93
96
  ```js
94
97
  import {XPathTransformer, StringJoiningTransformer} from 'jtlt';
95
98
  // Assume `doc` is an XML Document
96
- const joiner = new StringJoiningTransformer('', {document: doc});
99
+ const joiner = new StringJoiningTransformer('');
97
100
  const templates = [
98
101
  {
99
102
  name: 'root',
@@ -120,7 +123,8 @@ const out = engine.transform('');
120
123
  ```
121
124
 
122
125
  Limitations:
123
- - Version 2 (`xpath2.js`) may lack some XPath 2.0 functions; stick to basic location paths and simple predicates.
126
+ - Versions 2 and 3 (`xpath2.js` and `fontoxpath`) may lack some XPath functions;
127
+ stick to basic location paths and simple predicates.
124
128
  - Namespace resolution not yet exposed (future `namespaceResolver` option).
125
129
 
126
130
  ## Contexts
@@ -131,10 +135,19 @@ Methods (subset):
131
135
  - `applyTemplates(select, mode?, sort?)`
132
136
  - `forEach(select, cb, sort?)`
133
137
  - `valueOf(select?)`
138
+ - `if(select, cb)` — conditionally execute `cb` when selection is truthy
139
+ (non-empty result set or truthy scalar)
140
+ - `choose(select, whenCb, otherwiseCb?)` — like `if()`, but invokes
141
+ `otherwiseCb` when the condition is not met (akin to xsl:choose +
142
+ xsl:otherwise). Selection is evaluated relative to current context
143
+ object (its own `$`).
134
144
  - `variable(name, select)` – stores value/array from JSONPath.
135
145
  - `callTemplate(name, withParam?)`
136
146
  - `key(name, match, use)` / `getKey(name, value)`
137
147
  - Joiner passthrough: `string()`, `text()`, `element()`, `object()`, `array()`, `number()`, `boolean()`, etc.
148
+ \- Cloning helpers:
149
+ - `copy(propertySets?)` — Shallow clone of current context value (object/array). Nested references are preserved. Optional `propertySets` (array of registered names) merge into the top-level clone when object-like.
150
+ - `copyOf(select?, propertySets?)` — Deep clone (prefers `structuredClone`; falls back to JSON + manual). When `select` is provided, clones that target instead of the current value; primitives append directly. Optional `propertySets` merge when cloning objects.
138
151
 
139
152
  ### `XPathTransformerContext`
140
153
 
@@ -142,9 +155,18 @@ Parallels JSONPath context with XPath evaluation:
142
155
  - `get(select, asNodes?)` – returns node array when `asNodes=true` (v1 uses snapshot type; v2 coerces scalar to array).
143
156
  - `forEach(select, cb)` – iterates matches.
144
157
  - `applyTemplates(select, mode?)` – default initialization to `.` then `*` for subsequent calls.
158
+ - `if(select, cb)` — conditionally executes `cb` when XPath selects nodes
159
+ (non-empty) or evaluates to a truthy scalar value. In XPath v1 environments
160
+ without strict result typing, node-set existence is the primary check.
161
+ - `choose(select, whenCb, otherwiseCb?)` — same semantics as `if()` but with
162
+ fallback callback when condition fails. Relative XPath resolves from the
163
+ current context node; absolute paths (`/`, `//`) target the document root.
145
164
  - `variable(name, select)` – always stores node arrays for XPath.
146
165
  - `key(name, match, use)` – index by attribute value; `getKey` returns matching Element or context sentinel (`this`).
147
166
  - Default template rules: root traverses `.`, element traverses `*`, text nodes emit `nodeValue`, scalars emit `valueOf('.')`.
167
+ \- Cloning helpers:
168
+ - `copy()` — Shallow clone of the current context node (`cloneNode(false)`) appended to the joiner.
169
+ - `copyOf(select?)` — Deep clone of each node matched by `select` (node-set) or the current node if omitted, using `cloneNode(true)`. If `select` yields a scalar, that scalar is appended. Document nodes in scalar fallback emit their `documentElement` text. Chainable.
148
170
 
149
171
  ## Sorting API
150
172
 
@@ -226,6 +248,11 @@ When no user template matches:
226
248
  Common joiner methods summary:
227
249
  - `append(value)`
228
250
  - `get()`
251
+ - `document(cb, cfg?)` — Creates a new output document. Similar to XSLT's
252
+ `xsl:document`, this allows templates to generate multiple output documents.
253
+ The callback builds the document content, and optional `cfg` provides output
254
+ configuration (encoding, doctype, etc.). When `exposeDocuments` is enabled,
255
+ each document is added to the array returned by `get()`.
229
256
  - `object(seed?, cb?, usePropertySets?, propSets?)`
230
257
  - `array(seed?, cb?)`
231
258
  - `element(name, attrs?, children?, cb?)`
@@ -233,6 +260,146 @@ Common joiner methods summary:
233
260
  - `text(str)` vs `string(str, cb?)` vs `plainText(str)`
234
261
  - `number()`, `boolean()`, `null()`, `undefined()` (JS mode), `nonfiniteNumber()`, `function(fn)`
235
262
 
263
+ ### document() method details
264
+
265
+ The `document()` method creates a new output document in isolation:
266
+
267
+ **DOM Joiner**: Creates a new XMLDocument with proper declaration and DOCTYPE
268
+ when configured via `output()`.
269
+
270
+ **JSON Joiner**: Creates a new document wrapper object with `$document` property
271
+ containing the Jamilih representation.
272
+
273
+ **String Joiner**: Creates a new document string with XML declaration and
274
+ DOCTYPE when configured.
275
+
276
+ **Signature**: `document(callback, outputConfig?)`
277
+
278
+ **Example**:
279
+ ```js
280
+ joiner.document(() => {
281
+ joiner.output({
282
+ method: 'xml',
283
+ version: '1.0',
284
+ encoding: 'utf8',
285
+ doctypePublic: '-//W3C//DTD XHTML 1.0//EN',
286
+ doctypeSystem: 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'
287
+ });
288
+ joiner.element('html', {xmlns: 'http://www.w3.org/1999/xhtml'}, () => {
289
+ joiner.element('head', {}, () => {
290
+ joiner.element('title', {}, () => {
291
+ joiner.text('Document 1');
292
+ });
293
+ });
294
+ });
295
+ });
296
+
297
+ joiner.document(() => {
298
+ joiner.element('html', {}, () => {
299
+ joiner.element('body', {}, () => {
300
+ joiner.text('Document 2');
301
+ });
302
+ });
303
+ });
304
+
305
+ // When exposeDocuments is true, get() returns array of documents
306
+ const docs = joiner.get();
307
+ ```
308
+
309
+ The method preserves the current joiner state, resets it for the new document,
310
+ executes the callback, captures the result, then restores the previous state.
311
+
312
+ ### resultDocument() method details
313
+
314
+ The `resultDocument()` method creates output documents with associated metadata,
315
+ paralleling XSLT's `xsl:result-document` functionality. Unlike `document()`,
316
+ which stores documents in `_docs`, `resultDocument()` stores them in
317
+ `_resultDocuments` with metadata including href URI and output format.
318
+
319
+ **DOM Joiner**: Creates XMLDocument with href and format metadata.
320
+
321
+ **JSON Joiner**: Creates document wrapper object or raw JSON with metadata.
322
+
323
+ **String Joiner**: Creates document string with XML/HTML markup and metadata.
324
+
325
+ **Signature**: `resultDocument(href, callback, outputConfig?)`
326
+
327
+ **Parameters**:
328
+ - `href` (string): URI or path for the result document (e.g., `'output/page1.html'`)
329
+ - `callback` (function): Builds the document content with `this` bound to joiner
330
+ - `outputConfig` (optional): Output configuration (encoding, doctype, method, etc.)
331
+
332
+ **Result document structure**:
333
+ ```ts
334
+ {
335
+ href: string, // The URI/path provided
336
+ document: any, // The generated document (XMLDocument, object, or string)
337
+ format: string // Output format from config.method ('xml', 'html', 'text', 'xhtml', 'json')
338
+ }
339
+ ```
340
+
341
+ **Example use case - Multi-page site generation**:
342
+ ```js
343
+ const pages = [
344
+ {title: 'Home', slug: 'index', content: 'Welcome'},
345
+ {title: 'About', slug: 'about', content: 'About us'},
346
+ {title: 'Contact', slug: 'contact', content: 'Get in touch'}
347
+ ];
348
+
349
+ pages.forEach((page) => {
350
+ joiner.resultDocument(`output/${page.slug}.html`, () => {
351
+ joiner.output({
352
+ method: 'html',
353
+ doctypePublic: '-//W3C//DTD XHTML 1.0 Strict//EN',
354
+ doctypeSystem: 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'
355
+ });
356
+ joiner.element('html', {xmlns: 'http://www.w3.org/1999/xhtml'}, () => {
357
+ joiner.element('head', {}, () => {
358
+ joiner.element('title', {}, () => {
359
+ joiner.text(page.title);
360
+ });
361
+ });
362
+ joiner.element('body', {}, () => {
363
+ joiner.element('h1', {}, () => {
364
+ joiner.text(page.title);
365
+ });
366
+ joiner.element('p', {}, () => {
367
+ joiner.text(page.content);
368
+ });
369
+ });
370
+ });
371
+ });
372
+ });
373
+
374
+ // Write each result document to its href location
375
+ joiner._resultDocuments.forEach((result) => {
376
+ fs.writeFileSync(result.href, result.document);
377
+ console.log(`Generated: ${result.href} (${result.format})`);
378
+ });
379
+ ```
380
+
381
+ **Interoperability**: `document()` and `resultDocument()` can be used together in
382
+ the same transformation. `document()` populates `_docs` (accessible via `get()`
383
+ when `exposeDocuments` is true), while `resultDocument()` populates
384
+ `_resultDocuments` with metadata.
385
+
386
+ ### Output configuration and formats
387
+
388
+ Joiners accept an output configuration via `output(cfg)` and within `document()`/`resultDocument()`.
389
+
390
+ - `cfg.method`: one of `xml`, `html`, `text`, `xhtml`, or `json`.
391
+ - `xml` and `xhtml` are XML-like: an XML declaration is emitted unless `omitXmlDeclaration` is true; DOCTYPE is included when `doctypePublic` or `doctypeSystem` is provided. For the JSON joiner, DOCTYPE entries are included in `$document.childNodes` only when `method` is `xml` or `xhtml`.
392
+ - `html` emits HTML; the String and DOM joiners serialize accordingly. The JSON joiner does not include a DOCTYPE node in its `$document` wrapper for `html`.
393
+ - `text` emits raw text (no element wrappers). The JSON joiner will not add DOCTYPE; the String joiner writes plain strings.
394
+ - `json` indicates a JSON-centric output; for the JSON joiner, this is the natural mode and does not add XML declarations or DOCTYPE.
395
+ - `omitXmlDeclaration`: when false (or for `xml`/`xhtml` with default), include XML declaration with optional `version`, `encoding`, `standalone`.
396
+ - `doctypePublic`/`doctypeSystem`: when provided and `method` is `xml`/`xhtml`, include a DOCTYPE entry.
397
+
398
+ Notes for JSON joiner with `exposeDocuments`:
399
+
400
+ - When `exposeDocuments` is enabled in the joiner config, `get()` returns an array of `$document` wrappers. Each wrapper has a `childNodes` array where the root element is the last entry; the first entry may be a DOCTYPE object when `method` is `xml` or `xhtml`.
401
+ - For `html`, `text`, or `json` methods, no DOCTYPE is included in the JSON wrapper by default.
402
+
236
403
  ## Error handling
237
404
 
238
405
  - Equal priority templates: either last wins (default) or error if `errorOnEqualPriority=true`.
package/docs/API.md CHANGED
@@ -25,7 +25,7 @@ new JTLT({
25
25
  - JSONPathTransformer: on JSON with JSONPath selectors; resolves
26
26
  priority and falls back to defaults when no template matches.
27
27
  - XPathTransformer (experimental): on XML/HTML DOM. Choose
28
- `engineType: 'xpath'` on JTLT and set `xpathVersion: 1 | 2`.
28
+ `engineType: 'xpath'` on JTLT and set `xpathVersion: 1 | 2 | 3.1`.
29
29
 
30
30
  ## Context basics
31
31
 
@@ -33,11 +33,101 @@ new JTLT({
33
33
  `variable(name, select)`, `key(name, match, use)`, `getKey(name, value)`.
34
34
  JSONPath variables store values; XPath variables store arrays of nodes.
35
35
 
36
+ Cloning:
37
+ `copy()` (shallow clone current JSON value or DOM node) and
38
+ `copyOf(select?)` (deep clone; optional selector overrides target; scalar
39
+ selectors append the scalar). JSONPath deep cloning uses `structuredClone`
40
+ fallbacks; XPath uses `cloneNode(true)`.
41
+
42
+ Conditional execution:
43
+ - `if(select, cb)` — runs `cb` when the selector matches (non-empty
44
+ result set) or coerces to a truthy scalar.
45
+ - `choose(select, whenCb, otherwiseCb?)` — like `if()`, but also runs
46
+ `otherwiseCb` when the condition fails.
47
+
36
48
  ## Joiners
37
49
 
38
50
  StringJoiningTransformer, DOMJoiningTransformer, JSONJoiningTransformer with
39
51
  helpers: `string`, `text`, `element`, `attribute`, `object`, `array`,
40
- `number`, `boolean`, `plainText`, `append`, `get`.
52
+ `number`, `boolean`, `plainText`, `append`, `get`, `document`.
53
+
54
+ ### document() method
55
+
56
+ Similar to XSLT's `xsl:document`, the `document()` method allows templates to
57
+ generate multiple output documents. It accepts a callback that builds the
58
+ document content, and an optional output configuration.
59
+
60
+ **Signature**: `document(callback, outputConfig?)`
61
+
62
+ When `exposeDocuments` is enabled, each document created with `document()` is
63
+ added to the array returned by `get()`.
64
+
65
+ **Example**:
66
+ ```js
67
+ joiner.document(() => {
68
+ joiner.output({method: 'xml', version: '1.0'});
69
+ joiner.element('doc1', {}, () => {
70
+ joiner.text('First document');
71
+ });
72
+ });
73
+
74
+ joiner.document(() => {
75
+ joiner.element('doc2', {}, () => {
76
+ joiner.text('Second document');
77
+ });
78
+ });
79
+
80
+ const docs = joiner.get(); // Returns array of 2 documents
81
+ ```
82
+
83
+ ### resultDocument() method
84
+
85
+ Similar to XSLT's `xsl:result-document`, the `resultDocument()` method allows
86
+ templates to generate multiple output documents **with metadata** (href URI,
87
+ format). Documents are stored in `joiner._resultDocuments` array.
88
+
89
+ **Signature**: `resultDocument(href, callback, outputConfig?)`
90
+
91
+ Each result document is stored with:
92
+ - `href`: The URI/path for the document (e.g., `'output/page1.html'`)
93
+ - `document`: The generated document content
94
+ - `format`: The output format (from `method` in config). One of `xml`, `html`, `text`, `xhtml`, or `json`.
95
+
96
+ **Example**:
97
+ ```js
98
+ joiner.resultDocument('output/doc1.xml', () => {
99
+ joiner.output({method: 'xml', version: '1.0'});
100
+ joiner.element('doc1', {}, () => {
101
+ joiner.text('First document');
102
+ });
103
+ });
104
+
105
+ joiner.resultDocument('output/doc2.html', () => {
106
+ joiner.output({method: 'html'});
107
+ joiner.element('html', {}, () => {
108
+ joiner.text('Second document');
109
+ });
110
+ }, {method: 'html'});
111
+
112
+ // Access result documents with metadata
113
+ joiner._resultDocuments.forEach((result) => {
114
+ console.log(result.href); // e.g., 'output/doc1.xml'
115
+ console.log(result.format); // e.g., 'xml'
116
+ console.log(result.document); // The document content
117
+ });
118
+ ```
119
+
120
+ ### Output configuration (quick reference)
121
+
122
+ - `method`: `xml` | `html` | `text` | `xhtml` | `json`
123
+ - `xml`/`xhtml`: XML declaration unless `omitXmlDeclaration`; DOCTYPE included when `doctypePublic`/`doctypeSystem` present. For the JSON joiner, a DOCTYPE entry appears in `$document.childNodes` only for these methods.
124
+ - `html`: HTML output; JSON joiner wrapper omits DOCTYPE.
125
+ - `text`: raw text; no DOCTYPE.
126
+ - `json`: native JSON output; no XML declaration or DOCTYPE.
127
+ - `omitXmlDeclaration`, `version`, `encoding`, `standalone`: control XML declaration (applicable to `xml`/`xhtml`).
128
+ - `doctypePublic`, `doctypeSystem`: control DOCTYPE (applicable to `xml`/`xhtml`).
129
+
130
+ Note: With `exposeDocuments` enabled on a joiner, `get()` returns an array of `$document` wrappers. In the JSON joiner, the root element is the last entry of `$document.childNodes`; a DOCTYPE may precede it for `xml`/`xhtml`.
41
131
 
42
132
  ## Sorting
43
133
 
package/docs/TO-DO.md ADDED
@@ -0,0 +1,168 @@
1
+ ## To-dos
2
+
3
+ 1. Testing: Could adapt an XSLT/XQuery test suite
4
+
5
+ 1. Document
6
+
7
+ 1. Implement and demo equivalent to applying and calling templates, and
8
+ root template
9
+
10
+ 2. Demo chaining of methods, including [equivalents](https://www.saxonica.com/papers/XTech2005/mhkpaper.html#S4.)
11
+ to XQuery's FLWOR expressions (see also Promises to-do), perhaps
12
+ even making aliases so that XQuery's friendlier terms can be used
13
+ instead of XSLT's.
14
+
15
+ 2. Support processing of JSON documents with `$jtlt-stylesheet` to let
16
+ documents define their own targeted stylesheets and make own
17
+ `<?xml-stylesheet type="text/javascript" href="..."?>` for XML
18
+
19
+ 3. When sufficiently documented, add as example library/tool to
20
+ JSONPath wiki.
21
+
22
+ 4. Allow alternative to `element()`, `array()`, etc. methods by just
23
+ detecting those types from return values (and generic of each
24
+ type like `dom()` and `json()`).
25
+
26
+ 5. Allow, depending on mode, containers to contain containers of other
27
+ types (e.g., a JS container containing DOM objects, or temporary use
28
+ of a string container, etc.).
29
+
30
+ 1. Support XML and add [hXML](https://github.com/brettz9/hxml) methods.
31
+
32
+ 2. Support `appendJSON()`/`appendDOM()` and
33
+ `appendType('json', ...)` (allowing type extensions).
34
+
35
+ 6. Add `appendResult(function () {return result})`.
36
+
37
+ 7. Add JSON update functions (equivalent to Xquery Update Facility for
38
+ XML ([overview](http://www.xmlplease.com/xquery-update))) and create
39
+ JSON serialization (as with XSLT expressed itself in declarative XML)
40
+ so one can submit and evaluate
41
+ through [HTTPQuery](https://github.com/brettz9/httpquery) (and also
42
+ supply to JSONEditor, etc.). Utilize updating by reference.
43
+
44
+ 8. Demo narrowing to subset of JavaScript (as with `jsep`) to make
45
+ JTLT truly "declarative" as far as freedom from scripting
46
+
47
+ ## Possible to-dos
48
+
49
+ 1. Make schema-aware so that templates could target types. Most reusable
50
+ application may be having a type-driven view of a JSON Schema instance
51
+ (e.g., dates could be shown inside a calendar widget). Perhaps this
52
+ schema-awareness could also drive a JSON editor (as with other existing
53
+ projects) (even using same API as JSONEditor?) (or type-aware filtered
54
+ search/raw queries). This would help not only for editors which edit a
55
+ JSON file in full, but also for providing schema paths or other identifiers
56
+ so that a transformed/queried subset of a file (or joining of multiple
57
+ files) could point the way for edited contents to be saved back to the
58
+ correct JSON file and position in the JSON file.
59
+
60
+ 2. ~~Add a [non-eval PR for JSONPath](https://github.com/s3u/JSONPath/pull/4).~~
61
+ The OR condition (outside of filters) is another important feature as
62
+ would be schema-aware path results.
63
+
64
+ 3. Allow hybrid JSON/[Jamilih](https://github.com/brettz9/jamilih) or
65
+ JSON/(X)HTML/XML so that one can add
66
+ XPath or query into HTML in a relevant manner
67
+
68
+ 4. Support pull parsing/streaming? Pass `done()` function to templates to
69
+ signal completion?
70
+
71
+ 5. Add [XQuery Functions](https://code.google.com/p/jsxqueryparser/source/browse/trunk/jsxqueryparser/XQueryParser.js#1768)
72
+ (also supporting DOM and JSON where possible) as plug-in (also any
73
+ missing from XSLT/XQuery 3.0). Also add, if not present among these
74
+ functions (or in XQuery), add equivalents to XSLT's
75
+ `document()` and `unparsed-text()` for allowing non-JSON file
76
+ retrieval (as well as variables/parameters) and also methods for
77
+ iterating or retrieving IndexedDB, `localStorage`, and cookies
78
+ (names, keys and values).
79
+
80
+ 6. Add `outputType` which uses a DOM joiner but allows specialized
81
+ serialized output (e.g., pretty-printed HTML) so the users
82
+ don't need to build it themselves (likewise with stringified
83
+ JSON output).
84
+
85
+ 7. See code for other possible to-dos
86
+
87
+ 8. Consider implementing the following elements from <https://www.w3.org/TR/xslt-30/>
88
+ which are not yet implemented.
89
+
90
+ xsl:accept
91
+ xsl:accumulator
92
+ xsl:accumulator-rule
93
+ ~~"xsl:analyze-string",~~
94
+ "xsl:apply-imports",
95
+ ~~"xsl:apply-templates",~~
96
+ xsl:assert
97
+ ~~"xsl:attribute",~~
98
+ "xsl:attribute-set",
99
+ xsl:break
100
+ ~~"xsl:call-template",~~
101
+ xsl:catch
102
+ "xsl:character-map",
103
+ ~~"xsl:choose",~~
104
+ ~~"xsl:comment",~~
105
+ xsl:context-item
106
+ ~~"xsl:copy",~~
107
+ ~~"xsl:copy-of",~~
108
+ "xsl:decimal-format",
109
+ ~~"xsl:document",~~
110
+ ~~"xsl:element",~~
111
+ xsl:evaluate
112
+ xsl:expose
113
+ "xsl:fallback",
114
+ ~~"xsl:for-each",~~
115
+ "xsl:for-each-group",
116
+ xsl:fork
117
+ "xsl:function",
118
+ xsl:global-context-item
119
+ ~~"xsl:if",~~
120
+ "xsl:import",
121
+ "xsl:import-schema",
122
+ "xsl:include",
123
+ xsl:iterate
124
+ ~~"xsl:key",~~
125
+ xsl:map
126
+ xsl:map-entry
127
+ ~~"xsl:matching-substring",~~
128
+ xsl:merge
129
+ xsl:merge-action
130
+ xsl:merge-key
131
+ xsl:merge-source
132
+ ~~"xsl:message",~~
133
+ xsl:mode
134
+ "xsl:namespace",
135
+ "xsl:namespace-alias",
136
+ xsl:next-iteration
137
+ "xsl:next-match",
138
+ ~~"xsl:non-matching-substring",~~
139
+ ~~"xsl:number",~~
140
+ xsl:on-completion
141
+ xsl:on-empty
142
+ xsl:on-non-empty
143
+ ~~"xsl:otherwise",~~
144
+ ~~"xsl:output",~~
145
+ "xsl:output-character",
146
+ xsl:override
147
+ xsl:package
148
+ "xsl:param",
149
+ "xsl:perform-sort",
150
+ "xsl:preserve-space",
151
+ ~~"xsl:processing-instruction",~~
152
+ ~~"xsl:result-document",~~
153
+ "xsl:sequence",
154
+ ~~"xsl:sort",~~
155
+ xsl:source-document
156
+ "xsl:strip-space",
157
+ ~~"xsl:stylesheet",~~
158
+ ~~"xsl:template",~~
159
+ ~~"xsl:text",~~
160
+ ~~"xsl:transform",~~
161
+ xsl:try
162
+ xsl:use-package
163
+ ~~"xsl:value-of",~~
164
+ ~~"xsl:variable",~~
165
+ ~~"xsl:when",~~
166
+ xsl:where-populated
167
+ ~~"xsl:with-param"~~
168
+