@barefootjs/jinja 0.18.5 → 0.19.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/dist/adapter/index.js +74 -6
- package/dist/adapter/jinja-adapter.d.ts +41 -0
- package/dist/adapter/jinja-adapter.d.ts.map +1 -1
- package/dist/adapter/lib/static-value.d.ts +15 -0
- package/dist/adapter/lib/static-value.d.ts.map +1 -0
- package/dist/adapter/props/prop-classes.d.ts +3 -2
- package/dist/adapter/props/prop-classes.d.ts.map +1 -1
- package/dist/build.js +74 -6
- package/dist/conformance-pins.d.ts.map +1 -1
- package/dist/index.js +75 -12
- package/dist/render-divergences.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/__tests__/jinja-adapter-unit.test.ts +120 -0
- package/src/__tests__/jinja-adapter.test.ts +13 -0
- package/src/adapter/jinja-adapter.ts +102 -5
- package/src/adapter/lib/static-value.ts +41 -0
- package/src/adapter/props/prop-classes.ts +4 -3
- package/src/conformance-pins.ts +24 -25
- package/src/render-divergences.ts +6 -1
- package/src/test-render.ts +13 -142
package/dist/adapter/index.js
CHANGED
|
@@ -187308,7 +187308,13 @@ import {
|
|
|
187308
187308
|
prepareLoweringMatchers,
|
|
187309
187309
|
queryHrefArgs,
|
|
187310
187310
|
isValidHelperId,
|
|
187311
|
-
sortComparatorFromArrow as sortComparatorFromArrow2
|
|
187311
|
+
sortComparatorFromArrow as sortComparatorFromArrow2,
|
|
187312
|
+
isDangerousInnerHtmlAttr,
|
|
187313
|
+
resolveDangerousInnerHtml,
|
|
187314
|
+
dangerousInnerHtmlMetacharViolation,
|
|
187315
|
+
dangerousInnerHtmlDiagnostic,
|
|
187316
|
+
resolveStaticLoopSource,
|
|
187317
|
+
collectLoopBoundNames
|
|
187312
187318
|
} from "@barefootjs/jsx";
|
|
187313
187319
|
|
|
187314
187320
|
// src/adapter/boolean-result.ts
|
|
@@ -187699,6 +187705,39 @@ function renderFlatMethod(recv, depth, emit) {
|
|
|
187699
187705
|
return `bf.flat(${recv}, ${d})`;
|
|
187700
187706
|
}
|
|
187701
187707
|
|
|
187708
|
+
// src/adapter/lib/static-value.ts
|
|
187709
|
+
function staticValueToJinja(value) {
|
|
187710
|
+
if (value === null || value === undefined)
|
|
187711
|
+
return "none";
|
|
187712
|
+
if (typeof value === "boolean")
|
|
187713
|
+
return value ? "true" : "false";
|
|
187714
|
+
if (typeof value === "number")
|
|
187715
|
+
return String(value);
|
|
187716
|
+
if (typeof value === "string")
|
|
187717
|
+
return `'${escapeJinjaSingleQuoted(value)}'`;
|
|
187718
|
+
if (Array.isArray(value)) {
|
|
187719
|
+
const items = [];
|
|
187720
|
+
for (const el of value) {
|
|
187721
|
+
const serialized = staticValueToJinja(el);
|
|
187722
|
+
if (serialized === null)
|
|
187723
|
+
return null;
|
|
187724
|
+
items.push(serialized);
|
|
187725
|
+
}
|
|
187726
|
+
return `[${items.join(", ")}]`;
|
|
187727
|
+
}
|
|
187728
|
+
if (typeof value === "object") {
|
|
187729
|
+
const entries = [];
|
|
187730
|
+
for (const [key, val] of Object.entries(value)) {
|
|
187731
|
+
const serialized = staticValueToJinja(val);
|
|
187732
|
+
if (serialized === null)
|
|
187733
|
+
return null;
|
|
187734
|
+
entries.push(`${jinjaHashKey(key)}: ${serialized}`);
|
|
187735
|
+
}
|
|
187736
|
+
return `{${entries.join(", ")}}`;
|
|
187737
|
+
}
|
|
187738
|
+
return null;
|
|
187739
|
+
}
|
|
187740
|
+
|
|
187702
187741
|
// src/adapter/expr/emitters.ts
|
|
187703
187742
|
import {
|
|
187704
187743
|
groupBinaryOperand,
|
|
@@ -188244,7 +188283,7 @@ function collectBooleanTypedProps(ir) {
|
|
|
188244
188283
|
return new Set(ir.metadata.propsParams.filter((prop) => prop.type?.primitive === "boolean" || prop.type?.raw === "boolean").map((prop) => prop.name));
|
|
188245
188284
|
}
|
|
188246
188285
|
function collectNullableOptionalProps(ir) {
|
|
188247
|
-
return new Set(ir.metadata.propsParams.filter((p) => p.defaultValue === undefined && !p.isRest && p.type?.kind !== "primitive").map((p) => p.name));
|
|
188286
|
+
return new Set(ir.metadata.propsParams.filter((p) => p.defaultValue === undefined && !p.isRest && (p.type?.kind !== "primitive" || p.optional)).map((p) => p.name));
|
|
188248
188287
|
}
|
|
188249
188288
|
function collectStringValueNames(ir) {
|
|
188250
188289
|
const names = new Set;
|
|
@@ -188281,6 +188320,7 @@ class JinjaAdapter extends BaseAdapter {
|
|
|
188281
188320
|
_searchParamsLocals = new Set;
|
|
188282
188321
|
_loweringMatchers = [];
|
|
188283
188322
|
localConstants = [];
|
|
188323
|
+
staticLoopSourceBoundNames = new Set;
|
|
188284
188324
|
nullableOptionalProps = new Set;
|
|
188285
188325
|
constructor(options = {}) {
|
|
188286
188326
|
super();
|
|
@@ -188296,6 +188336,7 @@ class JinjaAdapter extends BaseAdapter {
|
|
|
188296
188336
|
this.propsParams = ir.metadata.propsParams.map((p) => ({ name: p.name }));
|
|
188297
188337
|
this.booleanTypedProps = collectBooleanTypedProps(ir);
|
|
188298
188338
|
this.localConstants = ir.metadata.localConstants ?? [];
|
|
188339
|
+
this.staticLoopSourceBoundNames = collectLoopBoundNames(ir);
|
|
188299
188340
|
this.nullableOptionalProps = collectNullableOptionalProps(ir);
|
|
188300
188341
|
this.stringValueNames = collectStringValueNames(ir);
|
|
188301
188342
|
this.moduleStringConsts = collectModuleStringConsts(ir.metadata.localConstants);
|
|
@@ -188417,7 +188458,8 @@ class JinjaAdapter extends BaseAdapter {
|
|
|
188417
188458
|
renderElement(element) {
|
|
188418
188459
|
const tag = element.tag;
|
|
188419
188460
|
const attrs = this.renderAttributes(element);
|
|
188420
|
-
const
|
|
188461
|
+
const dangerousHtml = this.renderDangerousInnerHtml(element);
|
|
188462
|
+
const children = dangerousHtml !== null ? dangerousHtml : this.renderChildren(element.children);
|
|
188421
188463
|
let hydrationAttrs = "";
|
|
188422
188464
|
if (element.needsScope) {
|
|
188423
188465
|
hydrationAttrs += ` ${this.renderScopeMarker("")}`;
|
|
@@ -188452,6 +188494,22 @@ class JinjaAdapter extends BaseAdapter {
|
|
|
188452
188494
|
}
|
|
188453
188495
|
return `<${tag}${attrs}${hydrationAttrs}>${children}</${tag}>`;
|
|
188454
188496
|
}
|
|
188497
|
+
renderDangerousInnerHtml(element) {
|
|
188498
|
+
const resolution = resolveDangerousInnerHtml(element);
|
|
188499
|
+
if (!resolution)
|
|
188500
|
+
return null;
|
|
188501
|
+
if (resolution.kind === "dynamic") {
|
|
188502
|
+
this.errors.push(dangerousInnerHtmlDiagnostic(resolution.expr, resolution.loc));
|
|
188503
|
+
return "";
|
|
188504
|
+
}
|
|
188505
|
+
const violation = dangerousInnerHtmlMetacharViolation(resolution.html, this.name);
|
|
188506
|
+
if (violation) {
|
|
188507
|
+
const attr = element.attrs.find(isDangerousInnerHtmlAttr);
|
|
188508
|
+
this.errors.push(dangerousInnerHtmlDiagnostic(`{ __html: ${JSON.stringify(resolution.html)} }`, attr.loc, violation));
|
|
188509
|
+
return "";
|
|
188510
|
+
}
|
|
188511
|
+
return resolution.html;
|
|
188512
|
+
}
|
|
188455
188513
|
renderExpression(expr) {
|
|
188456
188514
|
if (expr.clientOnly) {
|
|
188457
188515
|
if (expr.slotId) {
|
|
@@ -188459,7 +188517,7 @@ class JinjaAdapter extends BaseAdapter {
|
|
|
188459
188517
|
}
|
|
188460
188518
|
return "";
|
|
188461
188519
|
}
|
|
188462
|
-
const jinjaExpr = `bf.string(${this.convertExpressionToJinja(expr.expr)})`;
|
|
188520
|
+
const jinjaExpr = `bf.string(${this.convertExpressionToJinja(expr.expr, expr.parsed)})`;
|
|
188463
188521
|
if (expr.slotId) {
|
|
188464
188522
|
return `{{ bf.text_start("${expr.slotId}") | safe }}{{ ${jinjaExpr} }}{{ bf.text_end() | safe }}`;
|
|
188465
188523
|
}
|
|
@@ -188551,8 +188609,12 @@ ${whenTrue}
|
|
|
188551
188609
|
}
|
|
188552
188610
|
});
|
|
188553
188611
|
}
|
|
188612
|
+
const staticItems = resolveStaticLoopSource(loop.arrayParsed, this.localConstants, {
|
|
188613
|
+
isNameShadowed: (name) => this.staticLoopSourceBoundNames.has(name)
|
|
188614
|
+
});
|
|
188615
|
+
const staticArray = staticItems !== null ? staticValueToJinja(staticItems) : null;
|
|
188554
188616
|
const arrayName = loop.array.trim();
|
|
188555
|
-
if (/^[A-Za-z_$][\w$]*$/.test(arrayName)) {
|
|
188617
|
+
if (staticArray === null && /^[A-Za-z_$][\w$]*$/.test(arrayName)) {
|
|
188556
188618
|
const arrayConst = (this.localConstants ?? []).find((c) => c.name === arrayName);
|
|
188557
188619
|
if (arrayConst && !arrayConst.isModule && this._resolveLiteralConst(arrayName) === null) {
|
|
188558
188620
|
this.errors.push({
|
|
@@ -188566,7 +188628,7 @@ ${whenTrue}
|
|
|
188566
188628
|
});
|
|
188567
188629
|
}
|
|
188568
188630
|
}
|
|
188569
|
-
const rawArray = this.convertExpressionToJinja(loop.array);
|
|
188631
|
+
const rawArray = staticArray ?? this.convertExpressionToJinja(loop.array);
|
|
188570
188632
|
let array = rawArray;
|
|
188571
188633
|
if (loop.sortComparator) {
|
|
188572
188634
|
const sort = loop.sortComparator;
|
|
@@ -188878,6 +188940,8 @@ ${name}="{{ bf.string(${val}) }}"
|
|
|
188878
188940
|
for (const attr of element.attrs) {
|
|
188879
188941
|
if (attr.clientOnly)
|
|
188880
188942
|
continue;
|
|
188943
|
+
if (isDangerousInnerHtmlAttr(attr))
|
|
188944
|
+
continue;
|
|
188881
188945
|
let attrName;
|
|
188882
188946
|
if (attr.name === "className")
|
|
188883
188947
|
attrName = "class";
|
|
@@ -189077,6 +189141,8 @@ Options:
|
|
|
189077
189141
|
return isBooleanResultExpr(expr) || isAriaBooleanAttr(name) || this.isBooleanTypedPropRef(expr);
|
|
189078
189142
|
}
|
|
189079
189143
|
_resolveLiteralConst(name) {
|
|
189144
|
+
if (this.staticLoopSourceBoundNames.has(name))
|
|
189145
|
+
return null;
|
|
189080
189146
|
const c = (this.localConstants ?? []).find((lc) => lc.name === name);
|
|
189081
189147
|
if (c?.value === undefined)
|
|
189082
189148
|
return null;
|
|
@@ -189089,6 +189155,8 @@ Options:
|
|
|
189089
189155
|
return null;
|
|
189090
189156
|
}
|
|
189091
189157
|
_resolveStaticRecordLiteral(objectName, key) {
|
|
189158
|
+
if (this.staticLoopSourceBoundNames.has(objectName))
|
|
189159
|
+
return null;
|
|
189092
189160
|
const hit = lookupStaticRecordLiteral(objectName, key, this.localConstants);
|
|
189093
189161
|
if (!hit)
|
|
189094
189162
|
return null;
|
|
@@ -168,6 +168,16 @@ export declare class JinjaAdapter extends BaseAdapter implements IRNodeEmitter<J
|
|
|
168
168
|
* const (`const sizeAttrs = size ? {…} : {}`) to its initializer text.
|
|
169
169
|
*/
|
|
170
170
|
private localConstants;
|
|
171
|
+
/**
|
|
172
|
+
* Every name a `.map()`/`.filter()` loop callback binds as its item/index
|
|
173
|
+
* parameter anywhere in the component (#2208 fable review). A static
|
|
174
|
+
* loop-SOURCE name (e.g. a function-scope `const items = [...]`) must
|
|
175
|
+
* never resolve through `resolveStaticLoopSource` at a use site where a
|
|
176
|
+
* DIFFERENT, enclosing loop's own callback param shadows it — same
|
|
177
|
+
* shadowing hazard, and same coarse-but-safe mitigation, as #2212's
|
|
178
|
+
* `collectLoopBoundNames` use in `collectStringValueNames`.
|
|
179
|
+
*/
|
|
180
|
+
private staticLoopSourceBoundNames;
|
|
171
181
|
/**
|
|
172
182
|
* Optional, no-default props that are `None` when the caller omits them.
|
|
173
183
|
* Their bare-reference attribute emission is guarded with a Jinja
|
|
@@ -219,6 +229,13 @@ export declare class JinjaAdapter extends BaseAdapter implements IRNodeEmitter<J
|
|
|
219
229
|
private providerObjectLiteralJinja;
|
|
220
230
|
emitAsync(node: IRAsync, _ctx: JinjaRenderCtx, _emit: EmitIRNode<JinjaRenderCtx>): string;
|
|
221
231
|
renderElement(element: IRElement): string;
|
|
232
|
+
/**
|
|
233
|
+
* `dangerouslySetInnerHTML={{ __html: '...' }}` (#2207) — see the Blade
|
|
234
|
+
* adapter's identical helper for the full rationale. `null` means the
|
|
235
|
+
* attribute is absent (caller falls through to normal `renderChildren`);
|
|
236
|
+
* a non-`null` string (possibly `''`) replaces the children outright.
|
|
237
|
+
*/
|
|
238
|
+
private renderDangerousInnerHtml;
|
|
222
239
|
renderExpression(expr: IRExpression): string;
|
|
223
240
|
renderConditional(cond: IRConditional): string;
|
|
224
241
|
private renderNodeOrNull;
|
|
@@ -390,8 +407,32 @@ export declare class JinjaAdapter extends BaseAdapter implements IRNodeEmitter<J
|
|
|
390
407
|
* single-quoted string literal (`const totalPages = 5`, #1897
|
|
391
408
|
* pagination) — function-scope consts never reach the per-render
|
|
392
409
|
* context, so a bare reference would resolve to Undefined.
|
|
410
|
+
*
|
|
411
|
+
* The lookup is a flat name match with no notion of AST scope, so a
|
|
412
|
+
* name that any loop callback binds as its item/index param never
|
|
413
|
+
* inlines (#2221) — the occurrence may be the loop's own (shadowing)
|
|
414
|
+
* binding, and substituting the outer const's value there renders every
|
|
415
|
+
* iteration with the same hard-coded literal. Coarse (a genuinely
|
|
416
|
+
* non-shadowed same-named const elsewhere in the component also stops
|
|
417
|
+
* inlining, falling back to the bare identifier) but safe — the same
|
|
418
|
+
* trade-off as #2212's `collectLoopBoundNames` use in
|
|
419
|
+
* `collectStringValueNames`.
|
|
393
420
|
*/
|
|
394
421
|
private _resolveLiteralConst;
|
|
422
|
+
/**
|
|
423
|
+
* Resolve `IDENT.key` where `IDENT` is a module-scope object-literal const
|
|
424
|
+
* (`variantClasses.ghost`, #1896/#1897) to the looked-up scalar.
|
|
425
|
+
*
|
|
426
|
+
* The lookup is a flat name match on `objectName` with no notion of AST
|
|
427
|
+
* scope, so an enclosing loop callback's own param of the same name
|
|
428
|
+
* (`.map((cfg) => <li>{cfg.x}</li>)` shadowing a module `const cfg = {…}`)
|
|
429
|
+
* still resolved to the OUTER const's member value at every iteration
|
|
430
|
+
* (#2237) — the sibling hazard to #2221's `_resolveLiteralConst`. Same
|
|
431
|
+
* coarse-but-safe `staticLoopSourceBoundNames` guard: any name a loop
|
|
432
|
+
* binds anywhere in the component never inlines, falling back to the bare
|
|
433
|
+
* `cfg['x']` member expression (which a Jinja for-loop binds correctly
|
|
434
|
+
* at the shadowed occurrences).
|
|
435
|
+
*/
|
|
395
436
|
private _resolveStaticRecordLiteral;
|
|
396
437
|
private _resolveModuleStringConst;
|
|
397
438
|
private _recordExprBF101;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jinja-adapter.d.ts","sourceRoot":"","sources":["../../src/adapter/jinja-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwFG;AAEH,OAAO,KAAK,EACV,WAAW,EACX,MAAM,EACN,SAAS,EACT,MAAM,EACN,YAAY,EACZ,aAAa,EACb,MAAM,EACN,WAAW,EACX,UAAU,EACV,MAAM,EACN,aAAa,EACb,UAAU,EACV,OAAO,EAKP,yBAAyB,EAE1B,MAAM,iBAAiB,CAAA;AACxB,OAAO,EACL,WAAW,EACX,KAAK,aAAa,EAClB,KAAK,sBAAsB,EAE3B,KAAK,aAAa,EAClB,KAAK,UAAU,
|
|
1
|
+
{"version":3,"file":"jinja-adapter.d.ts","sourceRoot":"","sources":["../../src/adapter/jinja-adapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Serialize a compile-time-evaluated JS value (`@barefootjs/jsx`'s
|
|
3
|
+
* `evaluateStaticLiteral`/`resolveStaticLoopSource`, #2208) into a native
|
|
4
|
+
* Jinja2 literal. Used to inline a fully-static loop source (an inline
|
|
5
|
+
* array literal, or a function-scope local const with a static
|
|
6
|
+
* initializer) directly in a `{% for %}` header, rather than requiring a
|
|
7
|
+
* bound template variable.
|
|
8
|
+
*
|
|
9
|
+
* Returns `null` for a value this adapter can't represent as a literal
|
|
10
|
+
* (e.g. `undefined` reads for a missing object key are still representable
|
|
11
|
+
* as `none`, but anything else falls back to the caller's existing BF101
|
|
12
|
+
* refusal instead of guessing).
|
|
13
|
+
*/
|
|
14
|
+
export declare function staticValueToJinja(value: unknown): string | null;
|
|
15
|
+
//# sourceMappingURL=static-value.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"static-value.d.ts","sourceRoot":"","sources":["../../../src/adapter/lib/static-value.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAwBhE"}
|
|
@@ -14,8 +14,9 @@ import type { ComponentIR } from '@barefootjs/jsx';
|
|
|
14
14
|
*/
|
|
15
15
|
export declare function collectBooleanTypedProps(ir: ComponentIR): Set<string>;
|
|
16
16
|
/**
|
|
17
|
-
* Bare references to
|
|
18
|
-
* textarea's `rows`) are
|
|
17
|
+
* Bare references to presence-uncertain no-default props (non-primitive
|
|
18
|
+
* typed OR declared optional, #2259 — e.g. textarea's `rows`) are
|
|
19
|
+
* `None` when omitted → guarded with
|
|
19
20
|
* `is defined and is not none` in `emitExpression`. See the
|
|
20
21
|
* `nullableOptionalProps` field docstring in `jinja-adapter.ts`.
|
|
21
22
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prop-classes.d.ts","sourceRoot":"","sources":["../../../src/adapter/props/prop-classes.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAGlD;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,EAAE,EAAE,WAAW,GAAG,GAAG,CAAC,MAAM,CAAC,CAMrE;AAED
|
|
1
|
+
{"version":3,"file":"prop-classes.d.ts","sourceRoot":"","sources":["../../../src/adapter/props/prop-classes.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAGlD;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,EAAE,EAAE,WAAW,GAAG,GAAG,CAAC,MAAM,CAAC,CAMrE;AAED;;;;;;GAMG;AACH,wBAAgB,4BAA4B,CAAC,EAAE,EAAE,WAAW,GAAG,GAAG,CAAC,MAAM,CAAC,CAWzE;AAED;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CAAC,EAAE,EAAE,WAAW,GAAG,GAAG,CAAC,MAAM,CAAC,CAWpE"}
|
package/dist/build.js
CHANGED
|
@@ -187308,7 +187308,13 @@ import {
|
|
|
187308
187308
|
prepareLoweringMatchers,
|
|
187309
187309
|
queryHrefArgs,
|
|
187310
187310
|
isValidHelperId,
|
|
187311
|
-
sortComparatorFromArrow as sortComparatorFromArrow2
|
|
187311
|
+
sortComparatorFromArrow as sortComparatorFromArrow2,
|
|
187312
|
+
isDangerousInnerHtmlAttr,
|
|
187313
|
+
resolveDangerousInnerHtml,
|
|
187314
|
+
dangerousInnerHtmlMetacharViolation,
|
|
187315
|
+
dangerousInnerHtmlDiagnostic,
|
|
187316
|
+
resolveStaticLoopSource,
|
|
187317
|
+
collectLoopBoundNames
|
|
187312
187318
|
} from "@barefootjs/jsx";
|
|
187313
187319
|
|
|
187314
187320
|
// src/adapter/boolean-result.ts
|
|
@@ -187699,6 +187705,39 @@ function renderFlatMethod(recv, depth, emit) {
|
|
|
187699
187705
|
return `bf.flat(${recv}, ${d})`;
|
|
187700
187706
|
}
|
|
187701
187707
|
|
|
187708
|
+
// src/adapter/lib/static-value.ts
|
|
187709
|
+
function staticValueToJinja(value) {
|
|
187710
|
+
if (value === null || value === undefined)
|
|
187711
|
+
return "none";
|
|
187712
|
+
if (typeof value === "boolean")
|
|
187713
|
+
return value ? "true" : "false";
|
|
187714
|
+
if (typeof value === "number")
|
|
187715
|
+
return String(value);
|
|
187716
|
+
if (typeof value === "string")
|
|
187717
|
+
return `'${escapeJinjaSingleQuoted(value)}'`;
|
|
187718
|
+
if (Array.isArray(value)) {
|
|
187719
|
+
const items = [];
|
|
187720
|
+
for (const el of value) {
|
|
187721
|
+
const serialized = staticValueToJinja(el);
|
|
187722
|
+
if (serialized === null)
|
|
187723
|
+
return null;
|
|
187724
|
+
items.push(serialized);
|
|
187725
|
+
}
|
|
187726
|
+
return `[${items.join(", ")}]`;
|
|
187727
|
+
}
|
|
187728
|
+
if (typeof value === "object") {
|
|
187729
|
+
const entries = [];
|
|
187730
|
+
for (const [key, val] of Object.entries(value)) {
|
|
187731
|
+
const serialized = staticValueToJinja(val);
|
|
187732
|
+
if (serialized === null)
|
|
187733
|
+
return null;
|
|
187734
|
+
entries.push(`${jinjaHashKey(key)}: ${serialized}`);
|
|
187735
|
+
}
|
|
187736
|
+
return `{${entries.join(", ")}}`;
|
|
187737
|
+
}
|
|
187738
|
+
return null;
|
|
187739
|
+
}
|
|
187740
|
+
|
|
187702
187741
|
// src/adapter/expr/emitters.ts
|
|
187703
187742
|
import {
|
|
187704
187743
|
groupBinaryOperand,
|
|
@@ -188244,7 +188283,7 @@ function collectBooleanTypedProps(ir) {
|
|
|
188244
188283
|
return new Set(ir.metadata.propsParams.filter((prop) => prop.type?.primitive === "boolean" || prop.type?.raw === "boolean").map((prop) => prop.name));
|
|
188245
188284
|
}
|
|
188246
188285
|
function collectNullableOptionalProps(ir) {
|
|
188247
|
-
return new Set(ir.metadata.propsParams.filter((p) => p.defaultValue === undefined && !p.isRest && p.type?.kind !== "primitive").map((p) => p.name));
|
|
188286
|
+
return new Set(ir.metadata.propsParams.filter((p) => p.defaultValue === undefined && !p.isRest && (p.type?.kind !== "primitive" || p.optional)).map((p) => p.name));
|
|
188248
188287
|
}
|
|
188249
188288
|
function collectStringValueNames(ir) {
|
|
188250
188289
|
const names = new Set;
|
|
@@ -188281,6 +188320,7 @@ class JinjaAdapter extends BaseAdapter {
|
|
|
188281
188320
|
_searchParamsLocals = new Set;
|
|
188282
188321
|
_loweringMatchers = [];
|
|
188283
188322
|
localConstants = [];
|
|
188323
|
+
staticLoopSourceBoundNames = new Set;
|
|
188284
188324
|
nullableOptionalProps = new Set;
|
|
188285
188325
|
constructor(options = {}) {
|
|
188286
188326
|
super();
|
|
@@ -188296,6 +188336,7 @@ class JinjaAdapter extends BaseAdapter {
|
|
|
188296
188336
|
this.propsParams = ir.metadata.propsParams.map((p) => ({ name: p.name }));
|
|
188297
188337
|
this.booleanTypedProps = collectBooleanTypedProps(ir);
|
|
188298
188338
|
this.localConstants = ir.metadata.localConstants ?? [];
|
|
188339
|
+
this.staticLoopSourceBoundNames = collectLoopBoundNames(ir);
|
|
188299
188340
|
this.nullableOptionalProps = collectNullableOptionalProps(ir);
|
|
188300
188341
|
this.stringValueNames = collectStringValueNames(ir);
|
|
188301
188342
|
this.moduleStringConsts = collectModuleStringConsts(ir.metadata.localConstants);
|
|
@@ -188417,7 +188458,8 @@ class JinjaAdapter extends BaseAdapter {
|
|
|
188417
188458
|
renderElement(element) {
|
|
188418
188459
|
const tag = element.tag;
|
|
188419
188460
|
const attrs = this.renderAttributes(element);
|
|
188420
|
-
const
|
|
188461
|
+
const dangerousHtml = this.renderDangerousInnerHtml(element);
|
|
188462
|
+
const children = dangerousHtml !== null ? dangerousHtml : this.renderChildren(element.children);
|
|
188421
188463
|
let hydrationAttrs = "";
|
|
188422
188464
|
if (element.needsScope) {
|
|
188423
188465
|
hydrationAttrs += ` ${this.renderScopeMarker("")}`;
|
|
@@ -188452,6 +188494,22 @@ class JinjaAdapter extends BaseAdapter {
|
|
|
188452
188494
|
}
|
|
188453
188495
|
return `<${tag}${attrs}${hydrationAttrs}>${children}</${tag}>`;
|
|
188454
188496
|
}
|
|
188497
|
+
renderDangerousInnerHtml(element) {
|
|
188498
|
+
const resolution = resolveDangerousInnerHtml(element);
|
|
188499
|
+
if (!resolution)
|
|
188500
|
+
return null;
|
|
188501
|
+
if (resolution.kind === "dynamic") {
|
|
188502
|
+
this.errors.push(dangerousInnerHtmlDiagnostic(resolution.expr, resolution.loc));
|
|
188503
|
+
return "";
|
|
188504
|
+
}
|
|
188505
|
+
const violation = dangerousInnerHtmlMetacharViolation(resolution.html, this.name);
|
|
188506
|
+
if (violation) {
|
|
188507
|
+
const attr = element.attrs.find(isDangerousInnerHtmlAttr);
|
|
188508
|
+
this.errors.push(dangerousInnerHtmlDiagnostic(`{ __html: ${JSON.stringify(resolution.html)} }`, attr.loc, violation));
|
|
188509
|
+
return "";
|
|
188510
|
+
}
|
|
188511
|
+
return resolution.html;
|
|
188512
|
+
}
|
|
188455
188513
|
renderExpression(expr) {
|
|
188456
188514
|
if (expr.clientOnly) {
|
|
188457
188515
|
if (expr.slotId) {
|
|
@@ -188459,7 +188517,7 @@ class JinjaAdapter extends BaseAdapter {
|
|
|
188459
188517
|
}
|
|
188460
188518
|
return "";
|
|
188461
188519
|
}
|
|
188462
|
-
const jinjaExpr = `bf.string(${this.convertExpressionToJinja(expr.expr)})`;
|
|
188520
|
+
const jinjaExpr = `bf.string(${this.convertExpressionToJinja(expr.expr, expr.parsed)})`;
|
|
188463
188521
|
if (expr.slotId) {
|
|
188464
188522
|
return `{{ bf.text_start("${expr.slotId}") | safe }}{{ ${jinjaExpr} }}{{ bf.text_end() | safe }}`;
|
|
188465
188523
|
}
|
|
@@ -188551,8 +188609,12 @@ ${whenTrue}
|
|
|
188551
188609
|
}
|
|
188552
188610
|
});
|
|
188553
188611
|
}
|
|
188612
|
+
const staticItems = resolveStaticLoopSource(loop.arrayParsed, this.localConstants, {
|
|
188613
|
+
isNameShadowed: (name) => this.staticLoopSourceBoundNames.has(name)
|
|
188614
|
+
});
|
|
188615
|
+
const staticArray = staticItems !== null ? staticValueToJinja(staticItems) : null;
|
|
188554
188616
|
const arrayName = loop.array.trim();
|
|
188555
|
-
if (/^[A-Za-z_$][\w$]*$/.test(arrayName)) {
|
|
188617
|
+
if (staticArray === null && /^[A-Za-z_$][\w$]*$/.test(arrayName)) {
|
|
188556
188618
|
const arrayConst = (this.localConstants ?? []).find((c) => c.name === arrayName);
|
|
188557
188619
|
if (arrayConst && !arrayConst.isModule && this._resolveLiteralConst(arrayName) === null) {
|
|
188558
188620
|
this.errors.push({
|
|
@@ -188566,7 +188628,7 @@ ${whenTrue}
|
|
|
188566
188628
|
});
|
|
188567
188629
|
}
|
|
188568
188630
|
}
|
|
188569
|
-
const rawArray = this.convertExpressionToJinja(loop.array);
|
|
188631
|
+
const rawArray = staticArray ?? this.convertExpressionToJinja(loop.array);
|
|
188570
188632
|
let array = rawArray;
|
|
188571
188633
|
if (loop.sortComparator) {
|
|
188572
188634
|
const sort = loop.sortComparator;
|
|
@@ -188878,6 +188940,8 @@ ${name}="{{ bf.string(${val}) }}"
|
|
|
188878
188940
|
for (const attr of element.attrs) {
|
|
188879
188941
|
if (attr.clientOnly)
|
|
188880
188942
|
continue;
|
|
188943
|
+
if (isDangerousInnerHtmlAttr(attr))
|
|
188944
|
+
continue;
|
|
188881
188945
|
let attrName;
|
|
188882
188946
|
if (attr.name === "className")
|
|
188883
188947
|
attrName = "class";
|
|
@@ -189077,6 +189141,8 @@ Options:
|
|
|
189077
189141
|
return isBooleanResultExpr(expr) || isAriaBooleanAttr(name) || this.isBooleanTypedPropRef(expr);
|
|
189078
189142
|
}
|
|
189079
189143
|
_resolveLiteralConst(name) {
|
|
189144
|
+
if (this.staticLoopSourceBoundNames.has(name))
|
|
189145
|
+
return null;
|
|
189080
189146
|
const c = (this.localConstants ?? []).find((lc) => lc.name === name);
|
|
189081
189147
|
if (c?.value === undefined)
|
|
189082
189148
|
return null;
|
|
@@ -189089,6 +189155,8 @@ Options:
|
|
|
189089
189155
|
return null;
|
|
189090
189156
|
}
|
|
189091
189157
|
_resolveStaticRecordLiteral(objectName, key) {
|
|
189158
|
+
if (this.staticLoopSourceBoundNames.has(objectName))
|
|
189159
|
+
return null;
|
|
189092
189160
|
const hit = lookupStaticRecordLiteral(objectName, key, this.localConstants);
|
|
189093
189161
|
if (!hit)
|
|
189094
189162
|
return null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"conformance-pins.d.ts","sourceRoot":"","sources":["../src/conformance-pins.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAEtD,eAAO,MAAM,eAAe,EAAE,
|
|
1
|
+
{"version":3,"file":"conformance-pins.d.ts","sourceRoot":"","sources":["../src/conformance-pins.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAEtD,eAAO,MAAM,eAAe,EAAE,eA6F7B,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -187308,7 +187308,13 @@ import {
|
|
|
187308
187308
|
prepareLoweringMatchers,
|
|
187309
187309
|
queryHrefArgs,
|
|
187310
187310
|
isValidHelperId,
|
|
187311
|
-
sortComparatorFromArrow as sortComparatorFromArrow2
|
|
187311
|
+
sortComparatorFromArrow as sortComparatorFromArrow2,
|
|
187312
|
+
isDangerousInnerHtmlAttr,
|
|
187313
|
+
resolveDangerousInnerHtml,
|
|
187314
|
+
dangerousInnerHtmlMetacharViolation,
|
|
187315
|
+
dangerousInnerHtmlDiagnostic,
|
|
187316
|
+
resolveStaticLoopSource,
|
|
187317
|
+
collectLoopBoundNames
|
|
187312
187318
|
} from "@barefootjs/jsx";
|
|
187313
187319
|
|
|
187314
187320
|
// src/adapter/boolean-result.ts
|
|
@@ -187699,6 +187705,39 @@ function renderFlatMethod(recv, depth, emit) {
|
|
|
187699
187705
|
return `bf.flat(${recv}, ${d})`;
|
|
187700
187706
|
}
|
|
187701
187707
|
|
|
187708
|
+
// src/adapter/lib/static-value.ts
|
|
187709
|
+
function staticValueToJinja(value) {
|
|
187710
|
+
if (value === null || value === undefined)
|
|
187711
|
+
return "none";
|
|
187712
|
+
if (typeof value === "boolean")
|
|
187713
|
+
return value ? "true" : "false";
|
|
187714
|
+
if (typeof value === "number")
|
|
187715
|
+
return String(value);
|
|
187716
|
+
if (typeof value === "string")
|
|
187717
|
+
return `'${escapeJinjaSingleQuoted(value)}'`;
|
|
187718
|
+
if (Array.isArray(value)) {
|
|
187719
|
+
const items = [];
|
|
187720
|
+
for (const el of value) {
|
|
187721
|
+
const serialized = staticValueToJinja(el);
|
|
187722
|
+
if (serialized === null)
|
|
187723
|
+
return null;
|
|
187724
|
+
items.push(serialized);
|
|
187725
|
+
}
|
|
187726
|
+
return `[${items.join(", ")}]`;
|
|
187727
|
+
}
|
|
187728
|
+
if (typeof value === "object") {
|
|
187729
|
+
const entries = [];
|
|
187730
|
+
for (const [key, val] of Object.entries(value)) {
|
|
187731
|
+
const serialized = staticValueToJinja(val);
|
|
187732
|
+
if (serialized === null)
|
|
187733
|
+
return null;
|
|
187734
|
+
entries.push(`${jinjaHashKey(key)}: ${serialized}`);
|
|
187735
|
+
}
|
|
187736
|
+
return `{${entries.join(", ")}}`;
|
|
187737
|
+
}
|
|
187738
|
+
return null;
|
|
187739
|
+
}
|
|
187740
|
+
|
|
187702
187741
|
// src/adapter/expr/emitters.ts
|
|
187703
187742
|
import {
|
|
187704
187743
|
groupBinaryOperand,
|
|
@@ -188244,7 +188283,7 @@ function collectBooleanTypedProps(ir) {
|
|
|
188244
188283
|
return new Set(ir.metadata.propsParams.filter((prop) => prop.type?.primitive === "boolean" || prop.type?.raw === "boolean").map((prop) => prop.name));
|
|
188245
188284
|
}
|
|
188246
188285
|
function collectNullableOptionalProps(ir) {
|
|
188247
|
-
return new Set(ir.metadata.propsParams.filter((p) => p.defaultValue === undefined && !p.isRest && p.type?.kind !== "primitive").map((p) => p.name));
|
|
188286
|
+
return new Set(ir.metadata.propsParams.filter((p) => p.defaultValue === undefined && !p.isRest && (p.type?.kind !== "primitive" || p.optional)).map((p) => p.name));
|
|
188248
188287
|
}
|
|
188249
188288
|
function collectStringValueNames(ir) {
|
|
188250
188289
|
const names = new Set;
|
|
@@ -188281,6 +188320,7 @@ class JinjaAdapter extends BaseAdapter {
|
|
|
188281
188320
|
_searchParamsLocals = new Set;
|
|
188282
188321
|
_loweringMatchers = [];
|
|
188283
188322
|
localConstants = [];
|
|
188323
|
+
staticLoopSourceBoundNames = new Set;
|
|
188284
188324
|
nullableOptionalProps = new Set;
|
|
188285
188325
|
constructor(options = {}) {
|
|
188286
188326
|
super();
|
|
@@ -188296,6 +188336,7 @@ class JinjaAdapter extends BaseAdapter {
|
|
|
188296
188336
|
this.propsParams = ir.metadata.propsParams.map((p) => ({ name: p.name }));
|
|
188297
188337
|
this.booleanTypedProps = collectBooleanTypedProps(ir);
|
|
188298
188338
|
this.localConstants = ir.metadata.localConstants ?? [];
|
|
188339
|
+
this.staticLoopSourceBoundNames = collectLoopBoundNames(ir);
|
|
188299
188340
|
this.nullableOptionalProps = collectNullableOptionalProps(ir);
|
|
188300
188341
|
this.stringValueNames = collectStringValueNames(ir);
|
|
188301
188342
|
this.moduleStringConsts = collectModuleStringConsts(ir.metadata.localConstants);
|
|
@@ -188417,7 +188458,8 @@ class JinjaAdapter extends BaseAdapter {
|
|
|
188417
188458
|
renderElement(element) {
|
|
188418
188459
|
const tag = element.tag;
|
|
188419
188460
|
const attrs = this.renderAttributes(element);
|
|
188420
|
-
const
|
|
188461
|
+
const dangerousHtml = this.renderDangerousInnerHtml(element);
|
|
188462
|
+
const children = dangerousHtml !== null ? dangerousHtml : this.renderChildren(element.children);
|
|
188421
188463
|
let hydrationAttrs = "";
|
|
188422
188464
|
if (element.needsScope) {
|
|
188423
188465
|
hydrationAttrs += ` ${this.renderScopeMarker("")}`;
|
|
@@ -188452,6 +188494,22 @@ class JinjaAdapter extends BaseAdapter {
|
|
|
188452
188494
|
}
|
|
188453
188495
|
return `<${tag}${attrs}${hydrationAttrs}>${children}</${tag}>`;
|
|
188454
188496
|
}
|
|
188497
|
+
renderDangerousInnerHtml(element) {
|
|
188498
|
+
const resolution = resolveDangerousInnerHtml(element);
|
|
188499
|
+
if (!resolution)
|
|
188500
|
+
return null;
|
|
188501
|
+
if (resolution.kind === "dynamic") {
|
|
188502
|
+
this.errors.push(dangerousInnerHtmlDiagnostic(resolution.expr, resolution.loc));
|
|
188503
|
+
return "";
|
|
188504
|
+
}
|
|
188505
|
+
const violation = dangerousInnerHtmlMetacharViolation(resolution.html, this.name);
|
|
188506
|
+
if (violation) {
|
|
188507
|
+
const attr = element.attrs.find(isDangerousInnerHtmlAttr);
|
|
188508
|
+
this.errors.push(dangerousInnerHtmlDiagnostic(`{ __html: ${JSON.stringify(resolution.html)} }`, attr.loc, violation));
|
|
188509
|
+
return "";
|
|
188510
|
+
}
|
|
188511
|
+
return resolution.html;
|
|
188512
|
+
}
|
|
188455
188513
|
renderExpression(expr) {
|
|
188456
188514
|
if (expr.clientOnly) {
|
|
188457
188515
|
if (expr.slotId) {
|
|
@@ -188459,7 +188517,7 @@ class JinjaAdapter extends BaseAdapter {
|
|
|
188459
188517
|
}
|
|
188460
188518
|
return "";
|
|
188461
188519
|
}
|
|
188462
|
-
const jinjaExpr = `bf.string(${this.convertExpressionToJinja(expr.expr)})`;
|
|
188520
|
+
const jinjaExpr = `bf.string(${this.convertExpressionToJinja(expr.expr, expr.parsed)})`;
|
|
188463
188521
|
if (expr.slotId) {
|
|
188464
188522
|
return `{{ bf.text_start("${expr.slotId}") | safe }}{{ ${jinjaExpr} }}{{ bf.text_end() | safe }}`;
|
|
188465
188523
|
}
|
|
@@ -188551,8 +188609,12 @@ ${whenTrue}
|
|
|
188551
188609
|
}
|
|
188552
188610
|
});
|
|
188553
188611
|
}
|
|
188612
|
+
const staticItems = resolveStaticLoopSource(loop.arrayParsed, this.localConstants, {
|
|
188613
|
+
isNameShadowed: (name) => this.staticLoopSourceBoundNames.has(name)
|
|
188614
|
+
});
|
|
188615
|
+
const staticArray = staticItems !== null ? staticValueToJinja(staticItems) : null;
|
|
188554
188616
|
const arrayName = loop.array.trim();
|
|
188555
|
-
if (/^[A-Za-z_$][\w$]*$/.test(arrayName)) {
|
|
188617
|
+
if (staticArray === null && /^[A-Za-z_$][\w$]*$/.test(arrayName)) {
|
|
188556
188618
|
const arrayConst = (this.localConstants ?? []).find((c) => c.name === arrayName);
|
|
188557
188619
|
if (arrayConst && !arrayConst.isModule && this._resolveLiteralConst(arrayName) === null) {
|
|
188558
188620
|
this.errors.push({
|
|
@@ -188566,7 +188628,7 @@ ${whenTrue}
|
|
|
188566
188628
|
});
|
|
188567
188629
|
}
|
|
188568
188630
|
}
|
|
188569
|
-
const rawArray = this.convertExpressionToJinja(loop.array);
|
|
188631
|
+
const rawArray = staticArray ?? this.convertExpressionToJinja(loop.array);
|
|
188570
188632
|
let array = rawArray;
|
|
188571
188633
|
if (loop.sortComparator) {
|
|
188572
188634
|
const sort = loop.sortComparator;
|
|
@@ -188878,6 +188940,8 @@ ${name}="{{ bf.string(${val}) }}"
|
|
|
188878
188940
|
for (const attr of element.attrs) {
|
|
188879
188941
|
if (attr.clientOnly)
|
|
188880
188942
|
continue;
|
|
188943
|
+
if (isDangerousInnerHtmlAttr(attr))
|
|
188944
|
+
continue;
|
|
188881
188945
|
let attrName;
|
|
188882
188946
|
if (attr.name === "className")
|
|
188883
188947
|
attrName = "class";
|
|
@@ -189077,6 +189141,8 @@ Options:
|
|
|
189077
189141
|
return isBooleanResultExpr(expr) || isAriaBooleanAttr(name) || this.isBooleanTypedPropRef(expr);
|
|
189078
189142
|
}
|
|
189079
189143
|
_resolveLiteralConst(name) {
|
|
189144
|
+
if (this.staticLoopSourceBoundNames.has(name))
|
|
189145
|
+
return null;
|
|
189080
189146
|
const c = (this.localConstants ?? []).find((lc) => lc.name === name);
|
|
189081
189147
|
if (c?.value === undefined)
|
|
189082
189148
|
return null;
|
|
@@ -189089,6 +189155,8 @@ Options:
|
|
|
189089
189155
|
return null;
|
|
189090
189156
|
}
|
|
189091
189157
|
_resolveStaticRecordLiteral(objectName, key) {
|
|
189158
|
+
if (this.staticLoopSourceBoundNames.has(objectName))
|
|
189159
|
+
return null;
|
|
189092
189160
|
const hit = lookupStaticRecordLiteral(objectName, key, this.localConstants);
|
|
189093
189161
|
if (!hit)
|
|
189094
189162
|
return null;
|
|
@@ -189126,14 +189194,10 @@ Options:
|
|
|
189126
189194
|
var jinjaAdapter = new JinjaAdapter;
|
|
189127
189195
|
// src/conformance-pins.ts
|
|
189128
189196
|
var conformancePins = {
|
|
189129
|
-
"static-array-children": [{ code: "BF103", severity: "error" }],
|
|
189130
|
-
"todo-app": [{ code: "BF103", severity: "error" }],
|
|
189131
|
-
"todo-app-ssr": [{ code: "BF103", severity: "error" }],
|
|
189132
189197
|
"static-array-from-props": [
|
|
189133
189198
|
{ code: "BF101", severity: "error", issue: "https://github.com/piconic-ai/barefootjs/issues/2087" }
|
|
189134
189199
|
],
|
|
189135
189200
|
"static-array-from-props-with-component": [
|
|
189136
|
-
{ code: "BF103", severity: "error" },
|
|
189137
189201
|
{ code: "BF101", severity: "error", issue: "https://github.com/piconic-ai/barefootjs/issues/2087" }
|
|
189138
189202
|
],
|
|
189139
189203
|
"filter-nested-callback-predicate": [
|
|
@@ -189142,8 +189206,7 @@ var conformancePins = {
|
|
|
189142
189206
|
"filter-nested-find-predicate": [
|
|
189143
189207
|
{ code: "BF101", severity: "error", issue: "https://github.com/piconic-ai/barefootjs/issues/2038" }
|
|
189144
189208
|
],
|
|
189145
|
-
"
|
|
189146
|
-
"dangerous-inner-html": [{ code: "BF101", severity: "error" }]
|
|
189209
|
+
"dangerous-inner-html-dynamic": [{ code: "BF101", severity: "error", issue: "https://github.com/piconic-ai/barefootjs/issues/2215" }]
|
|
189147
189210
|
};
|
|
189148
189211
|
// src/render-divergences.ts
|
|
189149
189212
|
var renderDivergences = {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render-divergences.d.ts","sourceRoot":"","sources":["../src/render-divergences.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AAExD,eAAO,MAAM,iBAAiB,EAAE,
|
|
1
|
+
{"version":3,"file":"render-divergences.d.ts","sourceRoot":"","sources":["../src/render-divergences.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AAExD,eAAO,MAAM,iBAAiB,EAAE,iBAK/B,CAAA"}
|