jtlt 0.24.0 → 0.24.2
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/CHANGES.md +9 -0
- package/demo/codemirror.esm.js +3 -1
- package/demo/vendor/simple-get-json/dist/index-es.js +197 -76
- package/dist/AbstractJoiningTransformer.d.ts.map +1 -1
- package/dist/DOMJoiningTransformer.d.ts.map +1 -1
- package/dist/JSONJoiningTransformer.d.ts.map +1 -1
- package/dist/JSONPathTransformer.d.ts.map +1 -1
- package/dist/JSONPathTransformerContext.d.ts.map +1 -1
- package/dist/StringJoiningTransformer.d.ts.map +1 -1
- package/dist/XPathTransformer.d.ts.map +1 -1
- package/dist/XPathTransformerContext.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/indexedDB.d.ts.map +1 -1
- package/dist/jsonTemplate.d.ts.map +1 -1
- package/package.json +19 -19
- package/pnpm-workspace.yaml +5 -1
- package/src/AbstractJoiningTransformer.js +15 -15
- package/src/DOMJoiningTransformer.js +13 -11
- package/src/JSONJoiningTransformer.js +21 -21
- package/src/JSONPathTransformer.js +3 -4
- package/src/JSONPathTransformerContext.js +43 -64
- package/src/StringJoiningTransformer.js +9 -7
- package/src/XPathTransformer.js +3 -4
- package/src/XPathTransformerContext.js +79 -91
- package/src/index.js +1 -0
- package/src/indexedDB.js +5 -6
- package/src/jsonTemplate.js +58 -53
- package/tsconfig-prod.json +1 -7
|
@@ -101,7 +101,7 @@ class XPathTransformerContext {
|
|
|
101
101
|
}
|
|
102
102
|
}
|
|
103
103
|
};
|
|
104
|
-
/* c8 ignore stop */
|
|
104
|
+
/* c8 ignore stop -- See above */
|
|
105
105
|
|
|
106
106
|
/**
|
|
107
107
|
* @param {XPathTransformerContextConfig} config
|
|
@@ -301,7 +301,7 @@ class XPathTransformerContext {
|
|
|
301
301
|
? globalThis.XPathResult.ANY_TYPE
|
|
302
302
|
: 0
|
|
303
303
|
);
|
|
304
|
-
/* c8 ignore stop */
|
|
304
|
+
/* c8 ignore stop -- See above */
|
|
305
305
|
const resultObj = docTyped.evaluate(
|
|
306
306
|
expr, contextNode, resolver, type, null
|
|
307
307
|
);
|
|
@@ -336,14 +336,14 @@ class XPathTransformerContext {
|
|
|
336
336
|
n = resultObj.iterateNext();
|
|
337
337
|
}
|
|
338
338
|
return nodes;
|
|
339
|
-
/* c8 ignore stop */
|
|
339
|
+
/* c8 ignore stop -- See above */
|
|
340
340
|
}
|
|
341
341
|
/* c8 ignore start -- Default fallback for unsupported XPathResult
|
|
342
342
|
* types; environment-dependent and not hit under jsdom. */
|
|
343
343
|
default:
|
|
344
344
|
// Fallback: return original context for unsupported types
|
|
345
345
|
return this._contextNode;
|
|
346
|
-
/* c8 ignore stop */
|
|
346
|
+
/* c8 ignore stop -- See above */
|
|
347
347
|
}
|
|
348
348
|
}
|
|
349
349
|
if (version === 2) {
|
|
@@ -542,7 +542,7 @@ class XPathTransformerContext {
|
|
|
542
542
|
} else {
|
|
543
543
|
templateObj = DTR.transformScalars;
|
|
544
544
|
}
|
|
545
|
-
/* c8 ignore stop */
|
|
545
|
+
/* c8 ignore stop -- See above */
|
|
546
546
|
} else {
|
|
547
547
|
// Sort by priority (numeric or specificity resolver)
|
|
548
548
|
pathMatchedTemplates.sort((a, b) => {
|
|
@@ -632,7 +632,7 @@ class XPathTransformerContext {
|
|
|
632
632
|
'the XPath engine; compile with compileJSONTemplate() first.'
|
|
633
633
|
);
|
|
634
634
|
}
|
|
635
|
-
/* c8 ignore stop */
|
|
635
|
+
/* c8 ignore stop -- See above */
|
|
636
636
|
/**
|
|
637
637
|
* The template may return synchronously or return a Promise (e.g. from
|
|
638
638
|
* `await this.indexedDB(...)`), which is awaited unless `config.sync`.
|
|
@@ -674,7 +674,7 @@ class XPathTransformerContext {
|
|
|
674
674
|
// @ts-expect-error -- _openTagState: StringJoiningTransformer
|
|
675
675
|
joiner._openTagState = false;
|
|
676
676
|
}
|
|
677
|
-
/* c8 ignore stop */
|
|
677
|
+
/* c8 ignore stop -- See above */
|
|
678
678
|
joiner.append(resolvedRet);
|
|
679
679
|
}
|
|
680
680
|
this._contextNode = node;
|
|
@@ -1001,20 +1001,22 @@ class XPathTransformerContext {
|
|
|
1001
1001
|
currentGroup.push(node);
|
|
1002
1002
|
const endMatch = evalInContext(groupEndingWith, node);
|
|
1003
1003
|
|
|
1004
|
-
if (endMatch) {
|
|
1005
|
-
|
|
1006
|
-
const prevContext = this._contextNode;
|
|
1007
|
-
try {
|
|
1008
|
-
this._contextNode = currentGroup[0];
|
|
1009
|
-
/** @type {any} */ (this)._currentGroup = currentGroup;
|
|
1010
|
-
cb.call(this, null, currentGroup, this);
|
|
1011
|
-
} finally {
|
|
1012
|
-
this._params = prevParams;
|
|
1013
|
-
this._contextNode = prevContext;
|
|
1014
|
-
delete /** @type {any} */ (this)._currentGroup;
|
|
1015
|
-
}
|
|
1016
|
-
currentGroup = [];
|
|
1004
|
+
if (!endMatch) {
|
|
1005
|
+
continue;
|
|
1017
1006
|
}
|
|
1007
|
+
|
|
1008
|
+
const prevParams = this._params;
|
|
1009
|
+
const prevContext = this._contextNode;
|
|
1010
|
+
try {
|
|
1011
|
+
this._contextNode = currentGroup[0];
|
|
1012
|
+
/** @type {any} */ (this)._currentGroup = currentGroup;
|
|
1013
|
+
cb.call(this, null, currentGroup, this);
|
|
1014
|
+
} finally {
|
|
1015
|
+
this._params = prevParams;
|
|
1016
|
+
this._contextNode = prevContext;
|
|
1017
|
+
delete /** @type {any} */ (this)._currentGroup;
|
|
1018
|
+
}
|
|
1019
|
+
currentGroup = [];
|
|
1018
1020
|
}
|
|
1019
1021
|
|
|
1020
1022
|
// Process last group if not ended
|
|
@@ -1225,7 +1227,7 @@ class XPathTransformerContext {
|
|
|
1225
1227
|
// Fall through to normal XPath evaluation
|
|
1226
1228
|
// This allows fontoxpath registered functions to work natively
|
|
1227
1229
|
}
|
|
1228
|
-
/* c8 ignore stop */
|
|
1230
|
+
/* c8 ignore stop -- See above */
|
|
1229
1231
|
}
|
|
1230
1232
|
|
|
1231
1233
|
// Check for format-number() function call
|
|
@@ -1293,11 +1295,11 @@ class XPathTransformerContext {
|
|
|
1293
1295
|
const resResult = this._evalXPath(selectStr, true);
|
|
1294
1296
|
const res = /** @type {Node[]} */ (resResult);
|
|
1295
1297
|
const first = res[0];
|
|
1296
|
-
/* c8 ignore start */
|
|
1298
|
+
/* c8 ignore start -- Ok? */
|
|
1297
1299
|
val = first && first.nodeType
|
|
1298
1300
|
? first.textContent
|
|
1299
1301
|
: first;
|
|
1300
|
-
/* c8 ignore stop */
|
|
1302
|
+
/* c8 ignore stop -- See above */
|
|
1301
1303
|
}
|
|
1302
1304
|
} else if (!selectStr || selectStr === '.') {
|
|
1303
1305
|
if (this._contextNode.nodeType === 3) {
|
|
@@ -1345,9 +1347,9 @@ class XPathTransformerContext {
|
|
|
1345
1347
|
if (select) {
|
|
1346
1348
|
try {
|
|
1347
1349
|
const res = this.get(select, true);
|
|
1348
|
-
nodes = Array.isArray(res) ? res : /* c8 ignore next */ [];
|
|
1349
|
-
} catch { /* c8 ignore next */
|
|
1350
|
-
nodes = /* c8 ignore next */ [];
|
|
1350
|
+
nodes = Array.isArray(res) ? res : /* c8 ignore next -- Ok? */ [];
|
|
1351
|
+
} catch { /* c8 ignore next -- Should not err? */
|
|
1352
|
+
nodes = /* c8 ignore next -- Should not err? */ [];
|
|
1351
1353
|
}
|
|
1352
1354
|
} else {
|
|
1353
1355
|
nodes = [this._contextNode];
|
|
@@ -1358,13 +1360,13 @@ class XPathTransformerContext {
|
|
|
1358
1360
|
let deep;
|
|
1359
1361
|
try {
|
|
1360
1362
|
deep = /** @type {Node} */ (n.cloneNode(true));
|
|
1361
|
-
} catch { /* c8 ignore start */
|
|
1363
|
+
} catch { /* c8 ignore start -- Should not err? */
|
|
1362
1364
|
deep = /** @type {Node} */ (n.cloneNode(false));
|
|
1363
|
-
} /* c8 ignore stop */
|
|
1365
|
+
} /* c8 ignore stop -- See above */
|
|
1364
1366
|
this._getJoiningTransformer().append(/** @type {any} */ (deep));
|
|
1365
|
-
} else { /* c8 ignore start */
|
|
1367
|
+
} else { /* c8 ignore start -- Ok? */
|
|
1366
1368
|
this._getJoiningTransformer().append(/** @type {any} */ (n));
|
|
1367
|
-
} /* c8 ignore stop */
|
|
1369
|
+
} /* c8 ignore stop -- See above */
|
|
1368
1370
|
}
|
|
1369
1371
|
} else if (select) { // Scalar path
|
|
1370
1372
|
const scalar = this._evalXPath(select, false);
|
|
@@ -1378,7 +1380,7 @@ class XPathTransformerContext {
|
|
|
1378
1380
|
) {
|
|
1379
1381
|
const node = /** @type {Node} */ (scalar);
|
|
1380
1382
|
let txt = /** @type {any} */ (node.textContent);
|
|
1381
|
-
if (/* c8 ignore start */
|
|
1383
|
+
if (/* c8 ignore start -- Ok? */
|
|
1382
1384
|
(txt === null || typeof txt === 'undefined') &&
|
|
1383
1385
|
/** @type {any} */ (node).nodeType === 9 // Document
|
|
1384
1386
|
) {
|
|
@@ -1387,9 +1389,9 @@ class XPathTransformerContext {
|
|
|
1387
1389
|
/** @type {any} */ (node)
|
|
1388
1390
|
).documentElement;
|
|
1389
1391
|
txt = /** @type {any} */ (docEl && docEl.textContent) || '';
|
|
1390
|
-
} /* c8 ignore stop */
|
|
1392
|
+
} /* c8 ignore stop -- See above */
|
|
1391
1393
|
this._getJoiningTransformer().append(
|
|
1392
|
-
/** @type {any} */ (txt || /* c8 ignore next */ '')
|
|
1394
|
+
/** @type {any} */ (txt || /* c8 ignore next -- Ok? */ '')
|
|
1393
1395
|
);
|
|
1394
1396
|
} else {
|
|
1395
1397
|
this._getJoiningTransformer().append(/** @type {any} */ (scalar));
|
|
@@ -1410,12 +1412,12 @@ class XPathTransformerContext {
|
|
|
1410
1412
|
if (target && typeof target === 'object' && 'nodeType' in target) {
|
|
1411
1413
|
try {
|
|
1412
1414
|
clone = /** @type {Node} */ (target.cloneNode(false));
|
|
1413
|
-
} catch { /* c8 ignore start */
|
|
1415
|
+
} catch { /* c8 ignore start -- Should not err? */
|
|
1414
1416
|
clone = target;
|
|
1415
|
-
} /* c8 ignore stop */
|
|
1416
|
-
} else { /* c8 ignore start */
|
|
1417
|
+
} /* c8 ignore stop -- See above */
|
|
1418
|
+
} else { /* c8 ignore start -- Ok? */
|
|
1417
1419
|
clone = target;
|
|
1418
|
-
} /* c8 ignore stop */
|
|
1420
|
+
} /* c8 ignore stop -- See above */
|
|
1419
1421
|
this._getJoiningTransformer().append(/** @type {any} */ (clone));
|
|
1420
1422
|
return this;
|
|
1421
1423
|
}
|
|
@@ -1463,10 +1465,9 @@ class XPathTransformerContext {
|
|
|
1463
1465
|
if (this._params && Object.hasOwn(this._params, name)) {
|
|
1464
1466
|
return {has: true, value: this._params[name]};
|
|
1465
1467
|
}
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
return {has: false, value: undefined};
|
|
1468
|
+
return Object.hasOwn(this._runtimeParams, name)
|
|
1469
|
+
? {has: true, value: this._runtimeParams[name]}
|
|
1470
|
+
: {has: false, value: undefined};
|
|
1470
1471
|
}
|
|
1471
1472
|
|
|
1472
1473
|
/**
|
|
@@ -1610,15 +1611,18 @@ class XPathTransformerContext {
|
|
|
1610
1611
|
while (node) {
|
|
1611
1612
|
positions.unshift(this._calculatePosition(count, undefined));
|
|
1612
1613
|
node = node.parentNode;
|
|
1613
|
-
if (from) {
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1614
|
+
if (!from) {
|
|
1615
|
+
continue;
|
|
1616
|
+
}
|
|
1617
|
+
|
|
1618
|
+
const fromResult = /** @type {any} */ (
|
|
1619
|
+
this._evalXPath(from, node)
|
|
1620
|
+
);
|
|
1621
|
+
if (fromResult && fromResult.length > 0) {
|
|
1622
|
+
break;
|
|
1620
1623
|
}
|
|
1621
1624
|
}
|
|
1625
|
+
|
|
1622
1626
|
value = positions.join('.');
|
|
1623
1627
|
|
|
1624
1628
|
break;
|
|
@@ -1993,8 +1997,7 @@ class XPathTransformerContext {
|
|
|
1993
1997
|
*/
|
|
1994
1998
|
object (objOrCb, cbOrUsePropertySets, usePropertySetsOrPropSets, propSets) {
|
|
1995
1999
|
const jt = this._getJoiningTransformer();
|
|
1996
|
-
// Union of transformers creates intersection types
|
|
1997
|
-
// @ts-expect-error
|
|
2000
|
+
// @ts-expect-error -- Union of transformers creates intersection types
|
|
1998
2001
|
jt.object(objOrCb, cbOrUsePropertySets, usePropertySetsOrPropSets,
|
|
1999
2002
|
propSets);
|
|
2000
2003
|
return this;
|
|
@@ -2026,8 +2029,7 @@ class XPathTransformerContext {
|
|
|
2026
2029
|
*/
|
|
2027
2030
|
array (arrOrCb, cb) {
|
|
2028
2031
|
const jt = this._getJoiningTransformer();
|
|
2029
|
-
// Union of transformers creates intersection types
|
|
2030
|
-
// @ts-expect-error
|
|
2032
|
+
// @ts-expect-error -- Union of transformers creates intersection types
|
|
2031
2033
|
jt.array(arrOrCb, cb);
|
|
2032
2034
|
return this;
|
|
2033
2035
|
}
|
|
@@ -2142,7 +2144,7 @@ class XPathTransformerContext {
|
|
|
2142
2144
|
`Function '${name}' must have either 'body' or 'sequence' attribute`
|
|
2143
2145
|
);
|
|
2144
2146
|
}
|
|
2145
|
-
/* c8 ignore stop */
|
|
2147
|
+
/* c8 ignore stop -- See above */
|
|
2146
2148
|
|
|
2147
2149
|
// If sequence is provided, create a body function that evaluates it
|
|
2148
2150
|
const actualBody = sequence
|
|
@@ -2170,7 +2172,8 @@ class XPathTransformerContext {
|
|
|
2170
2172
|
});
|
|
2171
2173
|
|
|
2172
2174
|
// Evaluate the XPath expression with bound variables
|
|
2173
|
-
|
|
2175
|
+
// eslint-disable-next-line @stylistic/max-len -- Long
|
|
2176
|
+
const version = this._config.xpathVersion /* c8 ignore next -- Ok? */ ?? 1;
|
|
2174
2177
|
// eslint-disable-next-line sonarjs/no-floating-point-equality -- Safe
|
|
2175
2178
|
if (version === 3.1) {
|
|
2176
2179
|
// Use fontoxpath for XPath 3.1
|
|
@@ -2178,10 +2181,7 @@ class XPathTransformerContext {
|
|
|
2178
2181
|
/** @param {string} prefix */
|
|
2179
2182
|
const namespaceResolver = (prefix) => {
|
|
2180
2183
|
// Map common prefixes to URN namespaces
|
|
2181
|
-
|
|
2182
|
-
return `urn:${prefix}`;
|
|
2183
|
-
}
|
|
2184
|
-
return null;
|
|
2184
|
+
return prefix ? `urn:${prefix}` : null;
|
|
2185
2185
|
};
|
|
2186
2186
|
// // eslint-disable-next-line import/no-named-as-default-member -- OK
|
|
2187
2187
|
const result = fontoxpath.evaluateXPath(
|
|
@@ -2259,7 +2259,7 @@ class XPathTransformerContext {
|
|
|
2259
2259
|
if (!actualBody) {
|
|
2260
2260
|
throw new Error(`Function body not defined for ${name}`);
|
|
2261
2261
|
}
|
|
2262
|
-
/* c8 ignore stop */
|
|
2262
|
+
/* c8 ignore stop -- See above */
|
|
2263
2263
|
// For sequence functions, unwrap/wrap arrays as needed
|
|
2264
2264
|
// For regular body functions, pass through as-is
|
|
2265
2265
|
if (sequence) {
|
|
@@ -2274,11 +2274,10 @@ class XPathTransformerContext {
|
|
|
2274
2274
|
const result = actualBody(...unwrappedArgs);
|
|
2275
2275
|
// Fontoxpath expects sequences (item()*) to be arrays
|
|
2276
2276
|
// But scalar types (xs:integer, xs:string) should be scalars
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
/* c8 ignore stop */
|
|
2277
|
+
return returnsSequence && !Array.isArray(result)
|
|
2278
|
+
? [result]
|
|
2279
|
+
: result;
|
|
2280
|
+
/* c8 ignore stop -- See above */
|
|
2282
2281
|
}
|
|
2283
2282
|
// Regular body function - pass through
|
|
2284
2283
|
return actualBody(...args);
|
|
@@ -2290,7 +2289,7 @@ class XPathTransformerContext {
|
|
|
2290
2289
|
// Ignore fontoxpath registration errors (e.g., if duplicate)
|
|
2291
2290
|
// Function still available via invokeFunctionByArity
|
|
2292
2291
|
}
|
|
2293
|
-
/* c8 ignore stop */
|
|
2292
|
+
/* c8 ignore stop -- See above */
|
|
2294
2293
|
}
|
|
2295
2294
|
|
|
2296
2295
|
return this;
|
|
@@ -2374,8 +2373,7 @@ class XPathTransformerContext {
|
|
|
2374
2373
|
const jt = this._getJoiningTransformer();
|
|
2375
2374
|
// Only StringJoiningTransformer supports the third parameter
|
|
2376
2375
|
if (typeof avoid !== 'undefined') {
|
|
2377
|
-
// Union of transformers creates intersection types
|
|
2378
|
-
// @ts-expect-error
|
|
2376
|
+
// @ts-expect-error -- Union of transformers creates intersection types
|
|
2379
2377
|
jt.attribute(name, /** @type {string} */ (val), avoid);
|
|
2380
2378
|
} else {
|
|
2381
2379
|
jt.attribute(name, /** @type {string} */ (val));
|
|
@@ -2530,10 +2528,7 @@ class XPathTransformerContext {
|
|
|
2530
2528
|
if (Array.isArray(val)) {
|
|
2531
2529
|
return val.length > 0;
|
|
2532
2530
|
}
|
|
2533
|
-
|
|
2534
|
-
return true;
|
|
2535
|
-
}
|
|
2536
|
-
return Boolean(val);
|
|
2531
|
+
return val && typeof val === 'object' ? true : Boolean(val);
|
|
2537
2532
|
}
|
|
2538
2533
|
|
|
2539
2534
|
/**
|
|
@@ -2588,16 +2583,15 @@ class XPathTransformerContext {
|
|
|
2588
2583
|
if (!passes && (/[\/@*]/v).test(select)) {
|
|
2589
2584
|
try {
|
|
2590
2585
|
const nodes = this.get(select, true);
|
|
2591
|
-
// eslint-disable-next-line unicorn/prefer-ternary -- for coverage
|
|
2592
2586
|
if (Array.isArray(nodes)) {
|
|
2593
2587
|
passes = nodes.length > 0;
|
|
2594
2588
|
// Defensive for non-array nodes, but _evalXPath with asNodes=true
|
|
2595
2589
|
// always returns arrays in both v1 and v2.
|
|
2596
|
-
/* c8 ignore start */
|
|
2590
|
+
/* c8 ignore start -- Ok? */
|
|
2597
2591
|
} else {
|
|
2598
2592
|
passes = Boolean(nodes);
|
|
2599
2593
|
}
|
|
2600
|
-
/* c8 ignore stop */
|
|
2594
|
+
/* c8 ignore stop -- See above */
|
|
2601
2595
|
} catch {
|
|
2602
2596
|
passes = false;
|
|
2603
2597
|
}
|
|
@@ -2623,10 +2617,9 @@ class XPathTransformerContext {
|
|
|
2623
2617
|
return null;
|
|
2624
2618
|
}
|
|
2625
2619
|
const right = this._parseLiteral(m.groups.right.trim());
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
return {left: m.groups.left, op: m.groups.op, right: right.value};
|
|
2620
|
+
return !right
|
|
2621
|
+
? null
|
|
2622
|
+
: {left: m.groups.left, op: m.groups.op, right: right.value};
|
|
2630
2623
|
}
|
|
2631
2624
|
|
|
2632
2625
|
/**
|
|
@@ -2657,10 +2650,7 @@ class XPathTransformerContext {
|
|
|
2657
2650
|
if (str === 'null') {
|
|
2658
2651
|
return {value: null};
|
|
2659
2652
|
}
|
|
2660
|
-
|
|
2661
|
-
return {value: undefined};
|
|
2662
|
-
}
|
|
2663
|
-
return null;
|
|
2653
|
+
return str === 'undefined' ? {value: undefined} : null;
|
|
2664
2654
|
}
|
|
2665
2655
|
|
|
2666
2656
|
/**
|
|
@@ -2673,10 +2663,9 @@ class XPathTransformerContext {
|
|
|
2673
2663
|
_resolveComparand (ref) {
|
|
2674
2664
|
const paramRef = ref.match(/^\$(?<name>[\w\-]+)$/v);
|
|
2675
2665
|
/* c8 ignore next 3 -- `_parseComparison` only yields a `$name` left side */
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
return this._lookupParam(paramRef.groups.name).value;
|
|
2666
|
+
return !paramRef || !paramRef.groups
|
|
2667
|
+
? undefined
|
|
2668
|
+
: this._lookupParam(paramRef.groups.name).value;
|
|
2680
2669
|
}
|
|
2681
2670
|
|
|
2682
2671
|
/**
|
|
@@ -2817,12 +2806,11 @@ class XPathTransformerContext {
|
|
|
2817
2806
|
* @returns {string} - Captured group or empty string
|
|
2818
2807
|
*/
|
|
2819
2808
|
const getRegexGroup = (groupNumber) => {
|
|
2820
|
-
|
|
2809
|
+
return !currentCapturedGroups ||
|
|
2821
2810
|
groupNumber < 0 ||
|
|
2822
|
-
groupNumber >= currentCapturedGroups.length
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
return currentCapturedGroups[groupNumber] || '';
|
|
2811
|
+
groupNumber >= currentCapturedGroups.length
|
|
2812
|
+
? ''
|
|
2813
|
+
: currentCapturedGroups[groupNumber] || '';
|
|
2826
2814
|
};
|
|
2827
2815
|
|
|
2828
2816
|
// Save previous context to restore later
|
package/src/index.js
CHANGED
|
@@ -678,6 +678,7 @@ class JTLT {
|
|
|
678
678
|
: null
|
|
679
679
|
);
|
|
680
680
|
this.config.templates = query
|
|
681
|
+
// eslint-disable-next-line unicorn/prefer-minimal-ternary -- TS
|
|
681
682
|
? this.config.engineType === 'xpath'
|
|
682
683
|
? /** @type {XPathTemplateObject<joiningTypes>[]} */ ([
|
|
683
684
|
{name: 'root', path: '//*', template: query}
|
package/src/indexedDB.js
CHANGED
|
@@ -147,7 +147,7 @@ async function readAllRecords (target, range, direction, count) {
|
|
|
147
147
|
key: cursor.key, primaryKey: cursor.primaryKey, value: cursor.value
|
|
148
148
|
}), false)
|
|
149
149
|
);
|
|
150
|
-
/* c8 ignore stop */
|
|
150
|
+
/* c8 ignore stop -- See above */
|
|
151
151
|
}
|
|
152
152
|
|
|
153
153
|
/**
|
|
@@ -229,10 +229,9 @@ export async function queryIndexedDB (dbName, storeName, options = {}) {
|
|
|
229
229
|
|
|
230
230
|
// Forward iteration has bulk APIs. For a store query the primary key and
|
|
231
231
|
// the query key are the same, so `getAllKeys` serves both.
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
return target.getAllKeys(range, count);
|
|
232
|
+
return resultType === 'value'
|
|
233
|
+
? target.getAll(range, count)
|
|
234
|
+
: target.getAllKeys(range, count);
|
|
236
235
|
}
|
|
237
236
|
|
|
238
237
|
/**
|
|
@@ -502,7 +501,7 @@ export async function evaluateXPathWithIndexedDB (selectStr, contextNode) {
|
|
|
502
501
|
} catch {
|
|
503
502
|
// Ignore: only the collected request list matters from this pass.
|
|
504
503
|
}
|
|
505
|
-
/* c8 ignore stop */
|
|
504
|
+
/* c8 ignore stop -- See above */
|
|
506
505
|
|
|
507
506
|
// Phase 2: fetch each distinct query and cache the records.
|
|
508
507
|
const fetched = new Set();
|
package/src/jsonTemplate.js
CHANGED
|
@@ -89,10 +89,7 @@ function classify (node) {
|
|
|
89
89
|
if (typeof head === 'string') {
|
|
90
90
|
return 'element';
|
|
91
91
|
}
|
|
92
|
-
|
|
93
|
-
return 'operation';
|
|
94
|
-
}
|
|
95
|
-
return null;
|
|
92
|
+
return isPlainObject(head) ? 'operation' : null;
|
|
96
93
|
}
|
|
97
94
|
|
|
98
95
|
/**
|
|
@@ -287,22 +284,20 @@ function validateOperationHead (head) {
|
|
|
287
284
|
return `Unrecognized operation-node key \`${keys[0]}\`.`;
|
|
288
285
|
}
|
|
289
286
|
const [extKey] = keys;
|
|
290
|
-
|
|
291
|
-
|
|
287
|
+
return !isPlainObject(head[extKey])
|
|
288
|
+
? `\`${extKey}\` (an extension call) requires an object value, ` +
|
|
292
289
|
`e.g. \`{${extKey}: {select: '$.path'}}\` — matching ` +
|
|
293
290
|
'`$indexedDB`\'s own convention. Its contents are entirely up to ' +
|
|
294
291
|
'the extension itself (e.g. a `select` it resolves via `this.get' +
|
|
295
292
|
'(...)`, literal fields like `db`/`store`, …) — not interpreted ' +
|
|
296
|
-
'here.'
|
|
297
|
-
|
|
298
|
-
return null;
|
|
293
|
+
'here.'
|
|
294
|
+
: null;
|
|
299
295
|
}
|
|
300
|
-
|
|
301
|
-
|
|
296
|
+
return Object.hasOwn(head, '$text') && keys.length > 1
|
|
297
|
+
? '`$text` combined with any other key (e.g. `$select`) is not ' +
|
|
302
298
|
'valid jamilih (jamilih rejects the unrecognized companion alongside ' +
|
|
303
|
-
'its own reserved `$text`); use `$jtltText` for the combined form.'
|
|
304
|
-
|
|
305
|
-
return null;
|
|
299
|
+
'its own reserved `$text`); use `$jtltText` for the combined form.'
|
|
300
|
+
: null;
|
|
306
301
|
}
|
|
307
302
|
|
|
308
303
|
/**
|
|
@@ -392,21 +387,24 @@ function validateNode (node, format, errors) {
|
|
|
392
387
|
}
|
|
393
388
|
return;
|
|
394
389
|
}
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
390
|
+
|
|
391
|
+
if (!Object.hasOwn(head, '$indexedDB')) {
|
|
392
|
+
return;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
// Unlike `$if`/`$forEach`, `$indexedDB`'s children are optional — a
|
|
396
|
+
// bare prefetch (binding via `$as` for later use, or discarding the
|
|
397
|
+
// rows entirely) with no immediate consumer is a legitimate leaf use.
|
|
398
|
+
const [, childNodes] = arr;
|
|
399
|
+
if (childNodes !== undefined && !Array.isArray(childNodes)) {
|
|
400
|
+
errors.push(
|
|
401
|
+
"`$indexedDB`'s children, when given, must be a node array."
|
|
402
|
+
);
|
|
403
|
+
return;
|
|
404
|
+
}
|
|
405
|
+
const idbChildren = childNodes || [];
|
|
406
|
+
for (const child of idbChildren) {
|
|
407
|
+
validateNode(child, format, errors);
|
|
410
408
|
}
|
|
411
409
|
}
|
|
412
410
|
|
|
@@ -463,26 +461,28 @@ function collectReads (node, targets, errors) {
|
|
|
463
461
|
}
|
|
464
462
|
return;
|
|
465
463
|
}
|
|
466
|
-
if (Object.hasOwn(head, '$indexedDB')) {
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
)
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
464
|
+
if (!Object.hasOwn(head, '$indexedDB')) {
|
|
465
|
+
return;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
const spec = /** @type {any} */ (head.$indexedDB);
|
|
469
|
+
if (
|
|
470
|
+
!isPlainObject(spec) ||
|
|
471
|
+
typeof spec.db !== 'string' || spec.db.length === 0 ||
|
|
472
|
+
typeof spec.store !== 'string' || spec.store.length === 0
|
|
473
|
+
) {
|
|
474
|
+
errors.push(
|
|
475
|
+
'`$indexedDB` target could not be resolved statically — `db` and ' +
|
|
476
|
+
'`store` must both be non-empty string literals: ' +
|
|
477
|
+
JSON.stringify(head)
|
|
478
|
+
);
|
|
479
|
+
} else {
|
|
480
|
+
targets.push({db: spec.db, store: spec.store});
|
|
481
|
+
}
|
|
482
|
+
const [, childNodes] = arr;
|
|
483
|
+
const idbChildren = /** @type {unknown[]} */ (childNodes ?? []);
|
|
484
|
+
for (const child of idbChildren) {
|
|
485
|
+
collectReads(child, targets, errors);
|
|
486
486
|
}
|
|
487
487
|
}
|
|
488
488
|
|
|
@@ -512,13 +512,18 @@ export function extractReads (nodes) {
|
|
|
512
512
|
for (const node of nodes) {
|
|
513
513
|
collectReads(node, targets, errors);
|
|
514
514
|
}
|
|
515
|
-
|
|
515
|
+
/** @type {Map<string, Set<string>>} */
|
|
516
|
+
const seenStores = new Map();
|
|
516
517
|
const reads = targets.filter(({db, store}) => {
|
|
517
|
-
|
|
518
|
-
if (
|
|
518
|
+
let stores = seenStores.get(db);
|
|
519
|
+
if (!stores) {
|
|
520
|
+
stores = new Set();
|
|
521
|
+
seenStores.set(db, stores);
|
|
522
|
+
}
|
|
523
|
+
if (stores.has(store)) {
|
|
519
524
|
return false;
|
|
520
525
|
}
|
|
521
|
-
|
|
526
|
+
stores.add(store);
|
|
522
527
|
return true;
|
|
523
528
|
});
|
|
524
529
|
return {reads, errors};
|
package/tsconfig-prod.json
CHANGED
|
@@ -1,16 +1,10 @@
|
|
|
1
1
|
{
|
|
2
|
+
"extends": "./tsconfig.json",
|
|
2
3
|
"compilerOptions": {
|
|
3
|
-
"lib": ["ESNext", "DOM"],
|
|
4
|
-
"skipLibCheck": true,
|
|
5
|
-
"moduleResolution": "nodenext",
|
|
6
|
-
"module": "NodeNext",
|
|
7
|
-
"allowJs": true,
|
|
8
|
-
"checkJs": true,
|
|
9
4
|
"noEmit": false,
|
|
10
5
|
"declaration": true,
|
|
11
6
|
"declarationMap": true,
|
|
12
7
|
"emitDeclarationOnly": true,
|
|
13
|
-
"strict": true,
|
|
14
8
|
"target": "es2024",
|
|
15
9
|
"rootDir": "src",
|
|
16
10
|
"outDir": "dist"
|