@barefootjs/xslate 0.18.4 → 0.18.7

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/build.js CHANGED
@@ -187308,7 +187308,13 @@ import {
187308
187308
  queryHrefArgs,
187309
187309
  isValidHelperId,
187310
187310
  sortComparatorFromArrow as sortComparatorFromArrow2,
187311
- isLowerableLoopDestructure
187311
+ isLowerableLoopDestructure,
187312
+ isDangerousInnerHtmlAttr,
187313
+ resolveDangerousInnerHtml,
187314
+ dangerousInnerHtmlMetacharViolation,
187315
+ dangerousInnerHtmlDiagnostic,
187316
+ resolveStaticLoopSource,
187317
+ collectLoopBoundNames as collectLoopBoundNames2
187312
187318
  } from "@barefootjs/jsx";
187313
187319
 
187314
187320
  // src/adapter/boolean-result.ts
@@ -187365,7 +187371,7 @@ function isAriaBooleanAttr(name) {
187365
187371
  }
187366
187372
 
187367
187373
  // src/adapter/xslate-adapter.ts
187368
- import { BF_SLOT, BF_COND, BF_REGION } from "@barefootjs/shared";
187374
+ import { BF_SLOT, BF_COND, BF_REGION, escapeHtml } from "@barefootjs/shared";
187369
187375
 
187370
187376
  // src/adapter/lib/constants.ts
187371
187377
  var XSLATE_TEMPLATE_PRIMITIVES = {
@@ -187374,7 +187380,10 @@ var XSLATE_TEMPLATE_PRIMITIVES = {
187374
187380
  Number: { arity: 1, emit: (args) => `$bf.number(${args[0]})` },
187375
187381
  "Math.floor": { arity: 1, emit: (args) => `$bf.floor(${args[0]})` },
187376
187382
  "Math.ceil": { arity: 1, emit: (args) => `$bf.ceil(${args[0]})` },
187377
- "Math.round": { arity: 1, emit: (args) => `$bf.round(${args[0]})` }
187383
+ "Math.round": { arity: 1, emit: (args) => `$bf.round(${args[0]})` },
187384
+ "Math.min": { arity: 2, emit: (args) => `$bf.min(${args[0]}, ${args[1]})` },
187385
+ "Math.max": { arity: 2, emit: (args) => `$bf.max(${args[0]}, ${args[1]})` },
187386
+ "Math.abs": { arity: 1, emit: (args) => `$bf.abs(${args[0]})` }
187378
187387
  };
187379
187388
  var XSLATE_PRIMITIVE_EMIT_MAP = Object.fromEntries(Object.entries(XSLATE_TEMPLATE_PRIMITIVES).map(([k, v]) => [k, v.emit]));
187380
187389
 
@@ -187479,6 +187488,12 @@ function renderArrayMethod(method, object, args, emit) {
187479
187488
  const recv = emit(object);
187480
187489
  return `$bf.trim(${recv})`;
187481
187490
  }
187491
+ case "trimStart":
187492
+ case "trimEnd": {
187493
+ const fn = method === "trimStart" ? "trim_start" : "trim_end";
187494
+ const recv = emit(object);
187495
+ return `$bf.${fn}(${recv})`;
187496
+ }
187482
187497
  case "toFixed": {
187483
187498
  const recv = emit(object);
187484
187499
  const digits = args.length >= 1 ? emit(args[0]) : "0";
@@ -187512,6 +187527,12 @@ function renderArrayMethod(method, object, args, emit) {
187512
187527
  const newS = emit(args[1]);
187513
187528
  return `$bf.replace(${recv}, ${oldS}, ${newS})`;
187514
187529
  }
187530
+ case "replaceAll": {
187531
+ const recv = emit(object);
187532
+ const oldS = emit(args[0]);
187533
+ const newS = emit(args[1]);
187534
+ return `$bf.replace_all(${recv}, ${oldS}, ${newS})`;
187535
+ }
187515
187536
  case "repeat": {
187516
187537
  const recv = emit(object);
187517
187538
  const count = args.length === 0 ? "0" : emit(args[0]);
@@ -187609,6 +187630,39 @@ function renderFlatMethod(recv, depth, emit) {
187609
187630
  return `$bf.flat(${recv}, ${d})`;
187610
187631
  }
187611
187632
 
187633
+ // src/adapter/lib/static-value.ts
187634
+ function staticValueToKolon(value) {
187635
+ if (value === null || value === undefined)
187636
+ return "nil";
187637
+ if (typeof value === "boolean")
187638
+ return null;
187639
+ if (typeof value === "number")
187640
+ return String(value);
187641
+ if (typeof value === "string")
187642
+ return `'${escapeKolonSingleQuoted(value)}'`;
187643
+ if (Array.isArray(value)) {
187644
+ const items = [];
187645
+ for (const el of value) {
187646
+ const serialized = staticValueToKolon(el);
187647
+ if (serialized === null)
187648
+ return null;
187649
+ items.push(serialized);
187650
+ }
187651
+ return `[${items.join(", ")}]`;
187652
+ }
187653
+ if (typeof value === "object") {
187654
+ const entries = [];
187655
+ for (const [key, val] of Object.entries(value)) {
187656
+ const serialized = staticValueToKolon(val);
187657
+ if (serialized === null)
187658
+ return null;
187659
+ entries.push(`${kolonHashKey(key)} => ${serialized}`);
187660
+ }
187661
+ return `{ ${entries.join(", ")} }`;
187662
+ }
187663
+ return null;
187664
+ }
187665
+
187612
187666
  // src/adapter/expr/emitters.ts
187613
187667
  import {
187614
187668
  groupBinaryOperand,
@@ -187655,7 +187709,7 @@ class XslateFilterEmitter {
187655
187709
  return "nil";
187656
187710
  return String(value);
187657
187711
  }
187658
- member(object, property, _computed, emit) {
187712
+ member(object, property, _computed, _optional, emit) {
187659
187713
  if (property === "length") {
187660
187714
  return `$bf.length(${emit(object)})`;
187661
187715
  }
@@ -187767,7 +187821,7 @@ class XslateTopLevelEmitter {
187767
187821
  return "nil";
187768
187822
  return String(value);
187769
187823
  }
187770
- member(object, property, _computed, emit) {
187824
+ member(object, property, _computed, _optional, emit) {
187771
187825
  if (object.kind === "identifier" && object.name === "props") {
187772
187826
  return `$${property}`;
187773
187827
  }
@@ -188152,6 +188206,9 @@ function generateDerivedMemoSeed(ctx, ir) {
188152
188206
  ` : "";
188153
188207
  }
188154
188208
 
188209
+ // src/adapter/props/prop-classes.ts
188210
+ import { collectLoopBoundNames } from "@barefootjs/jsx";
188211
+
188155
188212
  // src/adapter/value/parsed-literal.ts
188156
188213
  import { evalStringArrayJoin } from "@barefootjs/jsx";
188157
188214
  function isStringTypeInfo(type2) {
@@ -188182,6 +188239,12 @@ function collectStringValueNames(ir) {
188182
188239
  if (isStringTypeInfo(p.type))
188183
188240
  names.add(p.name);
188184
188241
  }
188242
+ for (const c of ir.metadata.localConstants) {
188243
+ if (isStringTypeInfo(c.type ?? undefined) || isBareStringLiteral(c.value))
188244
+ names.add(c.name);
188245
+ }
188246
+ for (const bound of collectLoopBoundNames(ir))
188247
+ names.delete(bound);
188185
188248
  return names;
188186
188249
  }
188187
188250
 
@@ -188208,6 +188271,7 @@ class XslateAdapter extends BaseAdapter {
188208
188271
  options;
188209
188272
  errors = [];
188210
188273
  inLoop = false;
188274
+ currentLoopKeyDepth = 0;
188211
188275
  propsObjectName = null;
188212
188276
  propsParams = [];
188213
188277
  booleanTypedProps = new Set;
@@ -188216,6 +188280,7 @@ class XslateAdapter extends BaseAdapter {
188216
188280
  _searchParamsLocals = new Set;
188217
188281
  _loweringMatchers = [];
188218
188282
  localConstants = [];
188283
+ staticLoopSourceBoundNames = new Set;
188219
188284
  nullableOptionalProps = new Set;
188220
188285
  constructor(options = {}) {
188221
188286
  super();
@@ -188231,6 +188296,7 @@ class XslateAdapter extends BaseAdapter {
188231
188296
  this.propsParams = ir.metadata.propsParams.map((p) => ({ name: p.name }));
188232
188297
  this.booleanTypedProps = collectBooleanTypedProps(ir);
188233
188298
  this.localConstants = ir.metadata.localConstants ?? [];
188299
+ this.staticLoopSourceBoundNames = collectLoopBoundNames2(ir);
188234
188300
  this.nullableOptionalProps = collectNullableOptionalProps(ir);
188235
188301
  this.stringValueNames = collectStringValueNames(ir);
188236
188302
  this.moduleStringConsts = collectModuleStringConsts(ir.metadata.localConstants);
@@ -188284,7 +188350,7 @@ class XslateAdapter extends BaseAdapter {
188284
188350
  return this.renderElement(node);
188285
188351
  }
188286
188352
  emitText(node) {
188287
- return node.value;
188353
+ return escapeHtml(node.value);
188288
188354
  }
188289
188355
  emitExpression(node) {
188290
188356
  return this.renderExpression(node);
@@ -188347,7 +188413,8 @@ class XslateAdapter extends BaseAdapter {
188347
188413
  renderElement(element) {
188348
188414
  const tag = element.tag;
188349
188415
  const attrs = this.renderAttributes(element);
188350
- const children = this.renderChildren(element.children);
188416
+ const dangerousHtml = this.renderDangerousInnerHtml(element);
188417
+ const children = dangerousHtml !== null ? dangerousHtml : this.renderChildren(element.children);
188351
188418
  let hydrationAttrs = "";
188352
188419
  if (element.needsScope) {
188353
188420
  hydrationAttrs += ` ${this.renderScopeMarker("")}`;
@@ -188382,6 +188449,22 @@ class XslateAdapter extends BaseAdapter {
188382
188449
  }
188383
188450
  return `<${tag}${attrs}${hydrationAttrs}>${children}</${tag}>`;
188384
188451
  }
188452
+ renderDangerousInnerHtml(element) {
188453
+ const resolution = resolveDangerousInnerHtml(element);
188454
+ if (!resolution)
188455
+ return null;
188456
+ if (resolution.kind === "dynamic") {
188457
+ this.errors.push(dangerousInnerHtmlDiagnostic(resolution.expr, resolution.loc));
188458
+ return "";
188459
+ }
188460
+ const violation = dangerousInnerHtmlMetacharViolation(resolution.html, this.name);
188461
+ if (violation) {
188462
+ const attr = element.attrs.find(isDangerousInnerHtmlAttr);
188463
+ this.errors.push(dangerousInnerHtmlDiagnostic(`{ __html: ${JSON.stringify(resolution.html)} }`, attr.loc, violation));
188464
+ return "";
188465
+ }
188466
+ return resolution.html;
188467
+ }
188385
188468
  renderExpression(expr) {
188386
188469
  if (expr.clientOnly) {
188387
188470
  if (expr.slotId) {
@@ -188389,7 +188472,7 @@ class XslateAdapter extends BaseAdapter {
188389
188472
  }
188390
188473
  return "";
188391
188474
  }
188392
- const perlExpr = this.convertExpressionToKolon(expr.expr);
188475
+ const perlExpr = this.convertExpressionToKolon(expr.expr, expr.parsed);
188393
188476
  if (expr.slotId) {
188394
188477
  return `<: $bf.text_start("${expr.slotId}") | mark_raw :><: ${perlExpr} :><: $bf.text_end() | mark_raw :>`;
188395
188478
  }
@@ -188481,8 +188564,12 @@ ${whenTrue}
188481
188564
  }
188482
188565
  });
188483
188566
  }
188567
+ const staticItems = resolveStaticLoopSource(loop.arrayParsed, this.localConstants, {
188568
+ isNameShadowed: (name) => this.staticLoopSourceBoundNames.has(name)
188569
+ });
188570
+ const staticArray = staticItems !== null ? staticValueToKolon(staticItems) : null;
188484
188571
  const arrayName = loop.array.trim();
188485
- if (/^[A-Za-z_$][\w$]*$/.test(arrayName)) {
188572
+ if (staticArray === null && /^[A-Za-z_$][\w$]*$/.test(arrayName)) {
188486
188573
  const arrayConst = (this.localConstants ?? []).find((c) => c.name === arrayName);
188487
188574
  if (arrayConst && !arrayConst.isModule && this._resolveLiteralConst(arrayName) === null) {
188488
188575
  this.errors.push({
@@ -188496,7 +188583,7 @@ ${whenTrue}
188496
188583
  });
188497
188584
  }
188498
188585
  }
188499
- const rawArray = this.convertExpressionToKolon(loop.array);
188586
+ const rawArray = staticArray ?? this.convertExpressionToKolon(loop.array);
188500
188587
  let array = rawArray;
188501
188588
  if (loop.sortComparator) {
188502
188589
  const sort = loop.sortComparator;
@@ -188508,9 +188595,12 @@ ${whenTrue}
188508
188595
  }
188509
188596
  const param = loop.param;
188510
188597
  const renderedChildren = this.renderChildren(loop.children);
188511
- const loopVar = loop.iterationShape === "keys" ? "__bf_item" : supportableDestructure ? "__bf_item" : param;
188598
+ const loopVar = loop.objectIteration === "entries" ? "__bf_pair" : loop.objectIteration ? param : loop.iterationShape === "keys" ? "__bf_item" : supportableDestructure ? "__bf_item" : param;
188512
188599
  const indexLocalLines = [];
188513
- if (loop.iterationShape === "keys") {
188600
+ if (loop.objectIteration === "entries") {
188601
+ indexLocalLines.push(`: my $${loop.index ?? param} = $${loopVar}.key;`);
188602
+ indexLocalLines.push(`: my $${param} = $${loopVar}.value;`);
188603
+ } else if (loop.objectIteration) {} else if (loop.iterationShape === "keys") {
188514
188604
  indexLocalLines.push(`: my $${param} = $~${loopVar}.index;`);
188515
188605
  } else if (loop.index) {
188516
188606
  indexLocalLines.push(`: my $${loop.index} = $~${loopVar}.index;`);
@@ -188530,13 +188620,17 @@ ${whenTrue}
188530
188620
  }
188531
188621
  const prevInLoop = this.inLoop;
188532
188622
  this.inLoop = true;
188623
+ const prevLoopKeyDepth = this.currentLoopKeyDepth;
188624
+ this.currentLoopKeyDepth = loop.depth;
188533
188625
  const childrenUnderLoop = this.renderChildren(loop.children);
188626
+ this.currentLoopKeyDepth = prevLoopKeyDepth;
188534
188627
  this.inLoop = prevInLoop;
188535
188628
  const bodyChildren = loop.bodyIsItemConditional && loop.key ? `<: $bf.comment("loop-i:" ~ ${this.convertExpressionToKolon(loop.key)}) | mark_raw :>
188536
188629
  ${childrenUnderLoop}` : childrenUnderLoop;
188537
188630
  const lines = [];
188538
188631
  lines.push(`<: $bf.comment("loop:${loop.markerId}") | mark_raw :>`);
188539
- lines.push(`: for ${array} -> $${loopVar} {`);
188632
+ const forHeader = loop.objectIteration === "entries" ? `: for ${array}.kv() -> $${loopVar} {` : loop.objectIteration === "keys" ? `: for ${array}.keys() -> $${loopVar} {` : loop.objectIteration === "values" ? `: for ${array}.values() -> $${loopVar} {` : `: for ${array} -> $${loopVar} {`;
188633
+ lines.push(forHeader);
188540
188634
  for (const il of indexLocalLines)
188541
188635
  lines.push(il);
188542
188636
  if (loop.filterPredicate) {
@@ -188607,9 +188701,20 @@ ${childrenUnderLoop}` : childrenUnderLoop;
188607
188701
  renderComponent(comp) {
188608
188702
  const segments = [{ kind: "entries", parts: [] }];
188609
188703
  const currentEntries = () => this.componentPropSegmentEntries(segments);
188704
+ const namedSlotMacros = [];
188610
188705
  for (const p of comp.props) {
188611
188706
  if ((p.name.match(/^on[A-Z]/) || p.name === "ref") && p.value.kind === "expression")
188612
188707
  continue;
188708
+ if (p.value.kind === "jsx-children" && p.name !== "children") {
188709
+ const prevInLoop = this.inLoop;
188710
+ this.inLoop = false;
188711
+ const slotBody = this.renderChildren(p.value.children);
188712
+ this.inLoop = prevInLoop;
188713
+ const macroName = `bf_prop_${this.childrenCaptureCounter++}`;
188714
+ namedSlotMacros.push(`<: macro ${macroName} -> () { :>${slotBody}<: } :>`);
188715
+ currentEntries().push(`${kolonHashKey(p.name)} => ${macroName}()`);
188716
+ continue;
188717
+ }
188613
188718
  if (p.value.kind === "spread") {
188614
188719
  const trimmed = p.value.expr.trim();
188615
188720
  if (this.propsObjectName && this.propsObjectName === trimmed) {
@@ -188638,11 +188743,11 @@ ${childrenUnderLoop}` : childrenUnderLoop;
188638
188743
  const macroName = `bf_children_${comp.slotId ?? "c" + this.childrenCaptureCounter++}`;
188639
188744
  currentEntries().push(`children => ${macroName}()`);
188640
188745
  const dict = this.combineComponentPropSegments(segments);
188641
- return `<: macro ${macroName} -> () { :>${childrenBody}<: } :><: $bf.render_child('${tplName}', ${dict}) | mark_raw :>`;
188746
+ return `${namedSlotMacros.join("")}<: macro ${macroName} -> () { :>${childrenBody}<: } :><: $bf.render_child('${tplName}', ${dict}) | mark_raw :>`;
188642
188747
  }
188643
188748
  const isEmpty = segments.every((s) => s.kind === "entries" && s.parts.length === 0);
188644
188749
  const hashEntries = isEmpty ? "" : `, ${this.combineComponentPropSegments(segments)}`;
188645
- return `<: $bf.render_child('${tplName}'${hashEntries}) | mark_raw :>`;
188750
+ return `${namedSlotMacros.join("")}<: $bf.render_child('${tplName}'${hashEntries}) | mark_raw :>`;
188646
188751
  }
188647
188752
  childrenCaptureCounter = 0;
188648
188753
  presenceVarCounter = 0;
@@ -188687,7 +188792,7 @@ ${alternate}
188687
188792
  ${children}`;
188688
188793
  }
188689
188794
  elementAttrEmitter = {
188690
- emitLiteral: (value, name) => `${name}="${value.value}"`,
188795
+ emitLiteral: (value, name) => `${name}="${escapeHtml(value.value)}"`,
188691
188796
  emitExpression: (value, name) => {
188692
188797
  if (name === "style") {
188693
188798
  const css = this.tryLowerStyleObject(value.expr);
@@ -188791,12 +188896,15 @@ ${name}="<: ${val} :>"
188791
188896
  for (const attr of element.attrs) {
188792
188897
  if (attr.clientOnly)
188793
188898
  continue;
188899
+ if (isDangerousInnerHtmlAttr(attr))
188900
+ continue;
188794
188901
  let attrName;
188795
188902
  if (attr.name === "className")
188796
188903
  attrName = "class";
188797
- else if (attr.name === "key")
188798
- attrName = "data-key";
188799
- else
188904
+ else if (attr.name === "key") {
188905
+ const depth = this.currentLoopKeyDepth;
188906
+ attrName = depth > 0 ? `data-key-${depth}` : "data-key";
188907
+ } else
188800
188908
  attrName = attr.name;
188801
188909
  const lowered = emitAttrValue(attr.value, this.elementAttrEmitter, attrName);
188802
188910
  if (lowered)
@@ -188973,6 +189081,8 @@ Options:
188973
189081
  return this.booleanTypedProps.has(bare);
188974
189082
  }
188975
189083
  _resolveLiteralConst(name) {
189084
+ if (this.staticLoopSourceBoundNames.has(name))
189085
+ return null;
188976
189086
  const c = (this.localConstants ?? []).find((lc) => lc.name === name);
188977
189087
  if (c?.value === undefined)
188978
189088
  return null;
@@ -188985,6 +189095,8 @@ Options:
188985
189095
  return null;
188986
189096
  }
188987
189097
  _resolveStaticRecordLiteral(objectName, key) {
189098
+ if (this.staticLoopSourceBoundNames.has(objectName))
189099
+ return null;
188988
189100
  const hit = lookupStaticRecordLiteral(objectName, key, this.localConstants);
188989
189101
  if (!hit)
188990
189102
  return null;
@@ -1 +1 @@
1
- {"version":3,"file":"conformance-pins.d.ts","sourceRoot":"","sources":["../src/conformance-pins.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAEtD,eAAO,MAAM,eAAe,EAAE,eAgH7B,CAAA"}
1
+ {"version":3,"file":"conformance-pins.d.ts","sourceRoot":"","sources":["../src/conformance-pins.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAEtD,eAAO,MAAM,eAAe,EAAE,eAyG7B,CAAA"}