jtlt 0.1.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.
- package/.editorconfig +16 -0
- package/CHANGES.md +5 -0
- package/LICENSE-MIT.txt +21 -0
- package/README.md +534 -0
- package/dist/AbstractJoiningTransformer.d.ts +42 -0
- package/dist/AbstractJoiningTransformer.d.ts.map +1 -0
- package/dist/DOMJoiningTransformer.d.ts +113 -0
- package/dist/DOMJoiningTransformer.d.ts.map +1 -0
- package/dist/JSONJoiningTransformer.d.ts +160 -0
- package/dist/JSONJoiningTransformer.d.ts.map +1 -0
- package/dist/JSONPathTransformer.d.ts +95 -0
- package/dist/JSONPathTransformer.d.ts.map +1 -0
- package/dist/JSONPathTransformerContext.d.ts +263 -0
- package/dist/JSONPathTransformerContext.d.ts.map +1 -0
- package/dist/StringJoiningTransformer.d.ts +168 -0
- package/dist/StringJoiningTransformer.d.ts.map +1 -0
- package/dist/XPathTransformer.d.ts +51 -0
- package/dist/XPathTransformer.d.ts.map +1 -0
- package/dist/XPathTransformerContext.d.ts +260 -0
- package/dist/XPathTransformerContext.d.ts.map +1 -0
- package/dist/XSLTStyleJSONPathResolver.d.ts +16 -0
- package/dist/XSLTStyleJSONPathResolver.d.ts.map +1 -0
- package/dist/index.d.ts +168 -0
- package/dist/index.d.ts.map +1 -0
- package/docs/API.expanded.md +263 -0
- package/docs/API.md +69 -0
- package/eslint.config.js +30 -0
- package/package.json +53 -0
- package/pnpm-workspace.yaml +3 -0
- package/src/AbstractJoiningTransformer.js +73 -0
- package/src/DOMJoiningTransformer.js +237 -0
- package/src/JSONJoiningTransformer.js +472 -0
- package/src/JSONPathTransformer.js +159 -0
- package/src/JSONPathTransformerContext.js +807 -0
- package/src/StringJoiningTransformer.js +589 -0
- package/src/XPathTransformer.js +94 -0
- package/src/XPathTransformerContext.js +496 -0
- package/src/XSLTStyleJSONPathResolver.js +39 -0
- package/src/index.js +299 -0
- package/src/types/xpath2-js.d.ts +2 -0
- package/tsconfig-prod.json +19 -0
- package/tsconfig.json +14 -0
- package/typings/xpath2-js.d.ts +2 -0
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
# API (Expanded)
|
|
2
|
+
|
|
3
|
+
This document describes the public API surface of JTLT (JavaScript Template Language Transformations), including the JSONPath and experimental XPath engines, execution contexts, and joiners.
|
|
4
|
+
|
|
5
|
+
> Early alpha: APIs may evolve; experimental sections (XPath) can change without major version bumps.
|
|
6
|
+
|
|
7
|
+
## Core façade: `JTLT`
|
|
8
|
+
|
|
9
|
+
High-level entry point for running a transform over JSON data using JSONPath.
|
|
10
|
+
|
|
11
|
+
```js
|
|
12
|
+
import JTLT from 'jtlt';
|
|
13
|
+
|
|
14
|
+
const out = new JTLT({
|
|
15
|
+
data: {title: 'Hello'},
|
|
16
|
+
outputType: 'string',
|
|
17
|
+
templates: [
|
|
18
|
+
{
|
|
19
|
+
path: '$.title',
|
|
20
|
+
template (v) {
|
|
21
|
+
this.string('<h1>', () => this.text(v));
|
|
22
|
+
this.string('</h1>');
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
],
|
|
26
|
+
success: (res) => res
|
|
27
|
+
}).transform('');
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### `new JTLT(config)` options
|
|
31
|
+
|
|
32
|
+
| Option | Type | Description |
|
|
33
|
+
| ------ | ---- | ----------- |
|
|
34
|
+
| `data` | any | Root JSON/JS object. Required unless `ajaxData` provided. |
|
|
35
|
+
| `ajaxData` | string | URL to fetch JSON (async start). |
|
|
36
|
+
| `templates` | Array<TemplateObject> | Template declarations; see below. |
|
|
37
|
+
| `template` | Function \| TemplateObject | Single root template convenience. |
|
|
38
|
+
| `query` | Function | Root template convenience (wrapped as `path: '$'`). |
|
|
39
|
+
| `forQuery` | [select, cb] | One-off query (like FLWOR `for`). Auto-wrapped as root template. |
|
|
40
|
+
| `success` | Function(result) | Required callback; also receives transform return. |
|
|
41
|
+
| `mode` | string | Starting mode for template matching. |
|
|
42
|
+
| `outputType` | 'string' \| 'dom' \| 'json' | Chooses joiner. Default 'string'. |
|
|
43
|
+
| `joiningTransformer` | Joiner instance | Custom joiner; skip auto creation. |
|
|
44
|
+
| `joiningConfig` | object | Passed to joiner (e.g., `{xmlElements:true}`). |
|
|
45
|
+
| `unwrapSingleResult` | boolean | For JSON joiner: unwrap single-item root array. |
|
|
46
|
+
| `errorOnEqualPriority` | boolean | Throw when multiple templates share priority on a node. |
|
|
47
|
+
| `specificityPriorityResolver` | fn(path)=>number | Custom resolver for relative priorities. Defaults to XSLT-like JSONPath resolver. |
|
|
48
|
+
| `engine` | fn(config)=>any | Override transform engine (defaults to JSONPathTransformer). |
|
|
49
|
+
| `autostart` | boolean | If `false`, don’t auto-call `transform()` in constructor. |
|
|
50
|
+
| `preventEval` | boolean | Disable parenthetical eval portions of JSONPath (security). |
|
|
51
|
+
|
|
52
|
+
## Template objects
|
|
53
|
+
|
|
54
|
+
```ts
|
|
55
|
+
interface TemplateObject {
|
|
56
|
+
name?: string; // Optional identifier (for callTemplate)
|
|
57
|
+
path: string; // JSONPath or XPath expression
|
|
58
|
+
mode?: string; // Optional mode segregation
|
|
59
|
+
priority?: number; // Numeric priority (higher wins); fallback uses specificity resolver
|
|
60
|
+
template(nodeValue, cfg): any; // Executed with `this` bound to context
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Edge cases:
|
|
65
|
+
- For JSONPath: `path` examples: `$.items[*]`, `$['prop']`, `$..deep`.
|
|
66
|
+
- For XPath: `//item`, `/root/item`, `//*[@id='x']`.
|
|
67
|
+
- Root template: path `$` (JSONPath) or `/` (XPath).
|
|
68
|
+
|
|
69
|
+
## Engines
|
|
70
|
+
|
|
71
|
+
### `JSONPathTransformer`
|
|
72
|
+
|
|
73
|
+
Applies JSONPath-based templates over JSON data.
|
|
74
|
+
|
|
75
|
+
```js
|
|
76
|
+
import {JSONPathTransformer} from 'jtlt';
|
|
77
|
+
const engine = new JSONPathTransformer({data, templates});
|
|
78
|
+
const out = engine.transform('html');
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Responsibilities:
|
|
82
|
+
- Selects matching templates for current node + mode.
|
|
83
|
+
- Sorts by priority (numeric or specificity resolver).
|
|
84
|
+
- Invokes winning template; falls back to default rules when no match.
|
|
85
|
+
|
|
86
|
+
### `XPathTransformer` (experimental)
|
|
87
|
+
|
|
88
|
+
Same pattern for XML/HTML DOM data using XPath selectors.
|
|
89
|
+
|
|
90
|
+
Config additions:
|
|
91
|
+
- `xpathVersion`: `1` (native `XPathEvaluator`), `2` (`xpath2.js`). Default `1`.
|
|
92
|
+
|
|
93
|
+
```js
|
|
94
|
+
import {XPathTransformer, StringJoiningTransformer} from 'jtlt';
|
|
95
|
+
// Assume `doc` is an XML Document
|
|
96
|
+
const joiner = new StringJoiningTransformer('', {document: doc});
|
|
97
|
+
const templates = [
|
|
98
|
+
{
|
|
99
|
+
name: 'root',
|
|
100
|
+
path: '/',
|
|
101
|
+
template () {
|
|
102
|
+
this.applyTemplates('//item');
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
name: 'item',
|
|
107
|
+
path: '//item',
|
|
108
|
+
template (node) {
|
|
109
|
+
this.element('li', {}, [], () => this.text(node.textContent));
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
];
|
|
113
|
+
const engine = new XPathTransformer({
|
|
114
|
+
data: doc,
|
|
115
|
+
templates,
|
|
116
|
+
joiningTransformer: joiner,
|
|
117
|
+
xpathVersion: 1
|
|
118
|
+
});
|
|
119
|
+
const out = engine.transform('');
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Limitations:
|
|
123
|
+
- Version 2 (`xpath2.js`) may lack some XPath 2.0 functions; stick to basic location paths and simple predicates.
|
|
124
|
+
- Namespace resolution not yet exposed (future `namespaceResolver` option).
|
|
125
|
+
|
|
126
|
+
## Contexts
|
|
127
|
+
|
|
128
|
+
### `JSONPathTransformerContext`
|
|
129
|
+
|
|
130
|
+
Methods (subset):
|
|
131
|
+
- `applyTemplates(select, mode?, sort?)`
|
|
132
|
+
- `forEach(select, cb, sort?)`
|
|
133
|
+
- `valueOf(select?)`
|
|
134
|
+
- `variable(name, select)` – stores value/array from JSONPath.
|
|
135
|
+
- `callTemplate(name, withParam?)`
|
|
136
|
+
- `key(name, match, use)` / `getKey(name, value)`
|
|
137
|
+
- Joiner passthrough: `string()`, `text()`, `element()`, `object()`, `array()`, `number()`, `boolean()`, etc.
|
|
138
|
+
|
|
139
|
+
### `XPathTransformerContext`
|
|
140
|
+
|
|
141
|
+
Parallels JSONPath context with XPath evaluation:
|
|
142
|
+
- `get(select, asNodes?)` – returns node array when `asNodes=true` (v1 uses snapshot type; v2 coerces scalar to array).
|
|
143
|
+
- `forEach(select, cb)` – iterates matches.
|
|
144
|
+
- `applyTemplates(select, mode?)` – default initialization to `.` then `*` for subsequent calls.
|
|
145
|
+
- `variable(name, select)` – always stores node arrays for XPath.
|
|
146
|
+
- `key(name, match, use)` – index by attribute value; `getKey` returns matching Element or context sentinel (`this`).
|
|
147
|
+
- Default template rules: root traverses `.`, element traverses `*`, text nodes emit `nodeValue`, scalars emit `valueOf('.')`.
|
|
148
|
+
|
|
149
|
+
## Sorting API
|
|
150
|
+
|
|
151
|
+
Both `applyTemplates` and `forEach` accept a `sort` parameter.
|
|
152
|
+
|
|
153
|
+
Types:
|
|
154
|
+
1. String JSONPath (or XPath) – ascending text compare of selected values.
|
|
155
|
+
2. Function comparator `(a, b) => number`.
|
|
156
|
+
3. Object spec:
|
|
157
|
+
```js
|
|
158
|
+
const sortSpec = {
|
|
159
|
+
select: '$.price',
|
|
160
|
+
// type can be 'number' or 'text'
|
|
161
|
+
type: 'number',
|
|
162
|
+
// order can be 'ascending' or 'descending'
|
|
163
|
+
order: 'ascending',
|
|
164
|
+
// optional Intl collation/language options
|
|
165
|
+
locale,
|
|
166
|
+
localeOptions
|
|
167
|
+
};
|
|
168
|
+
```
|
|
169
|
+
4. Array of string/object specs for multi-key sorting.
|
|
170
|
+
|
|
171
|
+
Numeric sorting treats non-numeric or `NaN` values with stable ordering (equal falls back to next spec or preserves order).
|
|
172
|
+
|
|
173
|
+
## Keys (Indexing)
|
|
174
|
+
|
|
175
|
+
`key(name, match, use)` builds an index of nodes/items by an attribute/property value. Later `getKey(name, value)` performs O(1) lookup. If not found, JSONPath returns context object; XPath returns context (`this`). Check identity to skip.
|
|
176
|
+
|
|
177
|
+
Example (join):
|
|
178
|
+
```js
|
|
179
|
+
ctx.key('customerById', '$.customers[*]', 'id');
|
|
180
|
+
const c = ctx.getKey('customerById', order.customerId);
|
|
181
|
+
if (c !== ctx) {
|
|
182
|
+
// emit joined row
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
## Variables
|
|
187
|
+
|
|
188
|
+
`variable(name, select)` caches selection results:
|
|
189
|
+
- JSONPath: plain value or array depending on path.
|
|
190
|
+
- XPath: node array (even single result).
|
|
191
|
+
|
|
192
|
+
Use variables to avoid repeated path evaluation inside loops.
|
|
193
|
+
|
|
194
|
+
## Property sets
|
|
195
|
+
|
|
196
|
+
`propertySet(name, obj, useNames?)` registers a named property object; `useNames` merges listed sets into base.
|
|
197
|
+
`_usePropertySets(obj, name)` (internal) merges a set into `obj`.
|
|
198
|
+
|
|
199
|
+
Use within joiner object building:
|
|
200
|
+
```js
|
|
201
|
+
ctx.propertySet('base', {role: 'user'});
|
|
202
|
+
ctx.propertySet('admin', {priv: 'all'}, ['base']);
|
|
203
|
+
// Later inside object-building
|
|
204
|
+
ctx.object({}, () => {
|
|
205
|
+
ctx.propSets = ['admin'];
|
|
206
|
+
});
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
## Default template rules
|
|
210
|
+
|
|
211
|
+
When no user template matches:
|
|
212
|
+
- JSONPath: objects iterate property names / values; arrays iterate members; functions emit return value; primitives emitted directly; property-names mode concatenates keys.
|
|
213
|
+
- XPath: element nodes traverse children; text nodes emit text; scalars emit value via `valueOf('.')`.
|
|
214
|
+
|
|
215
|
+
## Joiners
|
|
216
|
+
|
|
217
|
+
### `StringJoiningTransformer`
|
|
218
|
+
- Builds a string; supports HTML/XML element creation (`element`, `attribute`, `text`). Maintains object/array state for structured emission when in JavaScript/JSON modes.
|
|
219
|
+
|
|
220
|
+
### `DOMJoiningTransformer`
|
|
221
|
+
- Builds a `DocumentFragment` or `Element` tree; `element`/`attribute` create real nodes; `text` appends text nodes.
|
|
222
|
+
|
|
223
|
+
### `JSONJoiningTransformer`
|
|
224
|
+
- Builds real JS values; `object`/`array` manage scope; primitives appended directly. `attribute` no-op; `text` no-op; `plainText` maps to string append.
|
|
225
|
+
|
|
226
|
+
Common joiner methods summary:
|
|
227
|
+
- `append(value)`
|
|
228
|
+
- `get()`
|
|
229
|
+
- `object(seed?, cb?, usePropertySets?, propSets?)`
|
|
230
|
+
- `array(seed?, cb?)`
|
|
231
|
+
- `element(name, attrs?, children?, cb?)`
|
|
232
|
+
- `attribute(name, value, avoidEscape?)`
|
|
233
|
+
- `text(str)` vs `string(str, cb?)` vs `plainText(str)`
|
|
234
|
+
- `number()`, `boolean()`, `null()`, `undefined()` (JS mode), `nonfiniteNumber()`, `function(fn)`
|
|
235
|
+
|
|
236
|
+
## Error handling
|
|
237
|
+
|
|
238
|
+
- Equal priority templates: either last wins (default) or error if `errorOnEqualPriority=true`.
|
|
239
|
+
- Missing `success` callback on `JTLT` transform: throws TypeError.
|
|
240
|
+
- Missing data and ajaxData: throws.
|
|
241
|
+
- XPath v1 without native evaluator: throws "Native XPath unavailable".
|
|
242
|
+
- `propValue` outside object state, `propOnly` misuse, attribute after tag closed: throw.
|
|
243
|
+
|
|
244
|
+
## Performance notes
|
|
245
|
+
|
|
246
|
+
- Prefer variables and keys for repeated lookups.
|
|
247
|
+
- Sorting with multiple specs incurs multiple value extractions; cache via variables when repeated.
|
|
248
|
+
- JSONPath recursive descent (`..`) more expensive; target precise paths when possible.
|
|
249
|
+
|
|
250
|
+
## Examples
|
|
251
|
+
|
|
252
|
+
See `README.md` for FLWOR-style and join patterns.
|
|
253
|
+
|
|
254
|
+
## Roadmap (selected)
|
|
255
|
+
|
|
256
|
+
- Namespace support for XPath.
|
|
257
|
+
- Copy helpers (deep/shallow) parity with XSLT.
|
|
258
|
+
- Streaming / async query execution.
|
|
259
|
+
- Schema-aware template targeting.
|
|
260
|
+
|
|
261
|
+
## Versioning
|
|
262
|
+
|
|
263
|
+
Experimental features (XPath) are subject to change until stabilized; check changelog before relying in production.
|
package/docs/API.md
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# API (Concise Overview)
|
|
2
|
+
|
|
3
|
+
For the full reference (engines, contexts, joiners, sorting, keys, variables,
|
|
4
|
+
property sets, defaults, roadmap), see `docs/API.expanded.md`.
|
|
5
|
+
|
|
6
|
+
## Facade: JTLT
|
|
7
|
+
|
|
8
|
+
```js
|
|
9
|
+
import JTLT from 'jtlt';
|
|
10
|
+
new JTLT({
|
|
11
|
+
data: {title: 'Hi'},
|
|
12
|
+
templates: [
|
|
13
|
+
{path: '$.title', template (v) {
|
|
14
|
+
this.string('<h1>', () => this.text(v));
|
|
15
|
+
this.string('</h1>');
|
|
16
|
+
}}
|
|
17
|
+
],
|
|
18
|
+
outputType: 'string',
|
|
19
|
+
success: (out) => out
|
|
20
|
+
}).transform('');
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Engines
|
|
24
|
+
|
|
25
|
+
- JSONPathTransformer: on JSON with JSONPath selectors; resolves
|
|
26
|
+
priority and falls back to defaults when no template matches.
|
|
27
|
+
- XPathTransformer (experimental): on XML/HTML DOM. Choose
|
|
28
|
+
`engineType: 'xpath'` on JTLT and set `xpathVersion: 1 | 2`.
|
|
29
|
+
|
|
30
|
+
## Context basics
|
|
31
|
+
|
|
32
|
+
`applyTemplates(select?, mode?)`, `forEach(select, cb)`, `valueOf(path?)`,
|
|
33
|
+
`variable(name, select)`, `key(name, match, use)`, `getKey(name, value)`.
|
|
34
|
+
JSONPath variables store values; XPath variables store arrays of nodes.
|
|
35
|
+
|
|
36
|
+
## Joiners
|
|
37
|
+
|
|
38
|
+
StringJoiningTransformer, DOMJoiningTransformer, JSONJoiningTransformer with
|
|
39
|
+
helpers: `string`, `text`, `element`, `attribute`, `object`, `array`,
|
|
40
|
+
`number`, `boolean`, `plainText`, `append`, `get`.
|
|
41
|
+
|
|
42
|
+
## Sorting
|
|
43
|
+
|
|
44
|
+
Path string (ascending text), comparator function, object spec
|
|
45
|
+
`{select, type, order}`, or array of specs.
|
|
46
|
+
|
|
47
|
+
## Keys
|
|
48
|
+
|
|
49
|
+
`key(name, match, use)` builds an index; `getKey(name, value)` returns the
|
|
50
|
+
match or the context sentinel if missing.
|
|
51
|
+
|
|
52
|
+
## Variables & valueOf
|
|
53
|
+
|
|
54
|
+
`variable(name, select)` caches a selection. `valueOf(path)` returns the first
|
|
55
|
+
match or current node when no path is given.
|
|
56
|
+
|
|
57
|
+
## Property sets
|
|
58
|
+
|
|
59
|
+
Register with `propertySet(name, obj, extendNames?)`. Inside `object()` set
|
|
60
|
+
`propSets = ['name']` to activate.
|
|
61
|
+
|
|
62
|
+
## Defaults
|
|
63
|
+
|
|
64
|
+
- JSONPath: objects traverse properties; arrays iterate items; primitives
|
|
65
|
+
emit; functions call and emit return.
|
|
66
|
+
- XPath: elements traverse children; text emits value; scalars use
|
|
67
|
+
`valueOf('.')`.
|
|
68
|
+
|
|
69
|
+
See `API.expanded.md` for details and examples.
|
package/eslint.config.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import ashNazg from 'eslint-config-ash-nazg';
|
|
2
|
+
|
|
3
|
+
export default [
|
|
4
|
+
{
|
|
5
|
+
ignores: [
|
|
6
|
+
'dist'
|
|
7
|
+
]
|
|
8
|
+
},
|
|
9
|
+
...ashNazg(['sauron']),
|
|
10
|
+
{
|
|
11
|
+
rules: {
|
|
12
|
+
// Temporary only:
|
|
13
|
+
'sonarjs/public-static-readonly': 'off', // Until ash-nazg disables
|
|
14
|
+
'jsdoc/check-types': 0,
|
|
15
|
+
'jsdoc/reject-any-type': 0,
|
|
16
|
+
'jsdoc/reject-function-type': 0,
|
|
17
|
+
'no-unused-vars': 0,
|
|
18
|
+
'promise/prefer-await-to-callbacks': 0
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
files: ['**/*.md/*.js'],
|
|
23
|
+
rules: {
|
|
24
|
+
'import/unambiguous': 'off',
|
|
25
|
+
'import/no-unresolved': 'off',
|
|
26
|
+
'no-console': 'off',
|
|
27
|
+
'no-undef': 'off'
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
];
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "jtlt",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"author": "Brett Zamir",
|
|
6
|
+
"contributors": [],
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"main": "src/index.js",
|
|
9
|
+
"engines": {
|
|
10
|
+
"node": ">=22.16.0"
|
|
11
|
+
},
|
|
12
|
+
"homepage": "https://github.com/s3u/JSONPath/",
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "https://github.com/brettz9/jtlt.git"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"jamilih": "0.61.4",
|
|
19
|
+
"jhtml": "0.7.1",
|
|
20
|
+
"jsdom": "27.1.0",
|
|
21
|
+
"jsonpath-plus": "10.3.0",
|
|
22
|
+
"lodash": "^4.17.21",
|
|
23
|
+
"object-assign": "4.x",
|
|
24
|
+
"simple-get-json": "10.0.0",
|
|
25
|
+
"xpath2.js": "1.0.0-alpha-6"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"@types/chai": "^5.2.3",
|
|
29
|
+
"@types/jsdom": "^27.0.0",
|
|
30
|
+
"@types/mocha": "^10.0.10",
|
|
31
|
+
"c8": "^10.1.3",
|
|
32
|
+
"chai": "^6.2.0",
|
|
33
|
+
"eslint": "^9.39.1",
|
|
34
|
+
"eslint-config-ash-nazg": "^39.7.1",
|
|
35
|
+
"mocha": "^11.7.5",
|
|
36
|
+
"typescript": "^5.9.3"
|
|
37
|
+
},
|
|
38
|
+
"bugs": "https://github.com/brettz9/jtlt/issues",
|
|
39
|
+
"description": "Uses an approach similar to [XSLT](https://www.w3.org/Style/XSL/) for declarative, linear declaration of templates, but with JSON or JavaScript object data sources. As with XSLT, can be transformed into different formats (e.g., HTML strings, JSON, DOM objects, etc.).",
|
|
40
|
+
"keywords": [
|
|
41
|
+
"xsl",
|
|
42
|
+
"xslt",
|
|
43
|
+
"json",
|
|
44
|
+
"javascript"
|
|
45
|
+
],
|
|
46
|
+
"scripts": {
|
|
47
|
+
"tsc": "tsc",
|
|
48
|
+
"build": "tsc -p tsconfig-prod.json",
|
|
49
|
+
"lint": "eslint .",
|
|
50
|
+
"mocha": "mocha",
|
|
51
|
+
"test": "c8 npm run mocha"
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
// Todo: Allow swapping of joining transformer types in
|
|
2
|
+
// mid-transformation (e.g., building strings with
|
|
3
|
+
// string transformer but adding as text node in a DOM transformer)
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Base class for joining transformers.
|
|
7
|
+
*
|
|
8
|
+
* A "joining transformer" is the sink that receives template outputs and
|
|
9
|
+
* accumulates them into a particular representation (string, DOM, JSON).
|
|
10
|
+
* Subclasses implement a consistent set of methods (string, number, object,
|
|
11
|
+
* array, element, text, etc.) but may interpret them differently according
|
|
12
|
+
* to their target representation.
|
|
13
|
+
*
|
|
14
|
+
* Common patterns supported by all joiners:
|
|
15
|
+
* - append(): central method that either concatenates, pushes, or assigns
|
|
16
|
+
* based on the current state.
|
|
17
|
+
* - get(): returns the accumulated result.
|
|
18
|
+
* - config(): temporarily tweak a config flag for the duration of a callback.
|
|
19
|
+
*/
|
|
20
|
+
class AbstractJoiningTransformer {
|
|
21
|
+
/**
|
|
22
|
+
* @param {object} [cfg] - Configuration object
|
|
23
|
+
*/
|
|
24
|
+
constructor (cfg) {
|
|
25
|
+
// Todo: Might set some reasonable defaults across all classes
|
|
26
|
+
this.setConfig(cfg);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @param {any} [cfg] - Configuration object
|
|
31
|
+
* @returns {void}
|
|
32
|
+
*/
|
|
33
|
+
setConfig (cfg) {
|
|
34
|
+
this._cfg = cfg;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* @param {string} type - Type name
|
|
39
|
+
* @param {string} embedType - Embed type name
|
|
40
|
+
* @returns {void}
|
|
41
|
+
*/
|
|
42
|
+
_requireSameChildren (type, embedType) {
|
|
43
|
+
if (this._cfg && /** @type {any} */ (this._cfg)[type] &&
|
|
44
|
+
/** @type {any} */ (this._cfg)[type].requireSameChildren) {
|
|
45
|
+
throw new Error(
|
|
46
|
+
'Cannot embed ' + embedType + ' children for a ' + type +
|
|
47
|
+
' joining transformer.'
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* @param {string} prop - Configuration property name
|
|
54
|
+
* @param {*} val - Configuration property value
|
|
55
|
+
* @param {Function} [cb] - Callback function
|
|
56
|
+
* @returns {void}
|
|
57
|
+
*/
|
|
58
|
+
config (prop, val, cb) {
|
|
59
|
+
const oldCfgProp = this._cfg &&
|
|
60
|
+
/** @type {any} */ (this._cfg)[prop];
|
|
61
|
+
if (this._cfg) {
|
|
62
|
+
/** @type {any} */ (this._cfg)[prop] = val;
|
|
63
|
+
}
|
|
64
|
+
if (cb) {
|
|
65
|
+
cb.call(this);
|
|
66
|
+
if (this._cfg) {
|
|
67
|
+
/** @type {any} */ (this._cfg)[prop] = oldCfgProp;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export default AbstractJoiningTransformer;
|