@jay-framework/compiler-jay-html 0.16.5 → 0.17.1

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/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { JayImportedType, isObjectType as isObjectType$1, isImportedType, isRecursiveType, JayUnknown, RenderFragment, Imports, Import, WithValidations, isArrayType as isArrayType$1, isAtomicType, isPromiseType, isEnumType, hasRefs, GenerateTarget, JayTypeAlias, JayUnionType, mkRefsTree, JayComponentType, JayHTMLType, mkRef, equalJayTypes, getModeFileExtension, RuntimeMode, nestRefs, mergeRefsTrees, SourceFileFormat, JayEnumType, JayObjectType, JayArrayType, JayPromiseType, resolvePrimitiveType, JayRecursiveType, JAY_CONTRACT_EXTENSION as JAY_CONTRACT_EXTENSION$1, ImportsFor, JAY_FULLSTACK_COMPONENTS, JayErrorType, JayOptionalType, JayRecordType, isOptionalType, isRecordType, resolvePluginComponent, resolvePluginManifest } from "@jay-framework/compiler-shared";
1
+ import { JayImportedType, isObjectType as isObjectType$1, isImportedType, isRecursiveType, JayUnknown, RenderFragment, Imports, Import, WithValidations, isArrayType as isArrayType$1, isAtomicType, isPromiseType, isEnumType, hasRefs, GenerateTarget, JayTypeAlias, JayUnionType, mkRefsTree, JayComponentType, JayHTMLType, mkRef, equalJayTypes, getModeFileExtension, isHtmlStringType, RuntimeMode, nestRefs, mergeRefsTrees, SourceFileFormat, JayEnumType, JayObjectType, JayArrayType, JayPromiseType, resolvePrimitiveType, JayRecursiveType, JAY_CONTRACT_EXTENSION as JAY_CONTRACT_EXTENSION$1, ImportsFor, JAY_FULLSTACK_COMPONENTS, JayErrorType, JayOptionalType, JayRecordType, isOptionalType, isRecordType, resolvePluginComponent, resolvePluginManifest } from "@jay-framework/compiler-shared";
2
2
  import path from "path";
3
3
  import { getLogger } from "@jay-framework/logger";
4
4
  import fs from "fs/promises";
@@ -5919,6 +5919,7 @@ function assignHeadlessInstance(element, contractName, ref, parentCoord, parentS
5919
5919
  );
5920
5920
  if (significantChildren.length > 1) {
5921
5921
  const wrapper = parse_2("<div></div>").querySelector("div");
5922
+ wrapper.setAttribute("style", "display: contents");
5922
5923
  const children = [...element.childNodes];
5923
5924
  element.innerHTML = "";
5924
5925
  children.forEach((child) => wrapper.appendChild(child));
@@ -8854,14 +8855,40 @@ function peg$parse(input, options) {
8854
8855
  return s0;
8855
8856
  }
8856
8857
  function peg$parsedynamicComponentProp() {
8857
- var s0, s1;
8858
+ var s0, s1, s2, s3;
8858
8859
  s0 = peg$currPos;
8859
8860
  s1 = peg$parseinteger();
8860
8861
  if (s1 !== peg$FAILED) {
8861
- peg$savedPos = s0;
8862
- s1 = peg$c80(s1);
8862
+ s2 = peg$currPos;
8863
+ peg$silentFails++;
8864
+ if (input.length > peg$currPos) {
8865
+ s3 = input.charAt(peg$currPos);
8866
+ peg$currPos++;
8867
+ } else {
8868
+ s3 = peg$FAILED;
8869
+ if (peg$silentFails === 0) {
8870
+ peg$fail(peg$c71);
8871
+ }
8872
+ }
8873
+ peg$silentFails--;
8874
+ if (s3 === peg$FAILED) {
8875
+ s2 = void 0;
8876
+ } else {
8877
+ peg$currPos = s2;
8878
+ s2 = peg$FAILED;
8879
+ }
8880
+ if (s2 !== peg$FAILED) {
8881
+ peg$savedPos = s0;
8882
+ s1 = peg$c80(s1);
8883
+ s0 = s1;
8884
+ } else {
8885
+ peg$currPos = s0;
8886
+ s0 = peg$FAILED;
8887
+ }
8888
+ } else {
8889
+ peg$currPos = s0;
8890
+ s0 = peg$FAILED;
8863
8891
  }
8864
- s0 = s1;
8865
8892
  if (s0 === peg$FAILED) {
8866
8893
  s0 = peg$currPos;
8867
8894
  s1 = peg$parsetemplate();
@@ -14366,6 +14393,23 @@ function filterContentNodes(childNodes, onlyIfMultiple = false) {
14366
14393
  function textEscape$1(s) {
14367
14394
  return s.replace(/'/g, "\\'");
14368
14395
  }
14396
+ function decodeHtmlEntities(s) {
14397
+ return heExports.decode(s);
14398
+ }
14399
+ function findHtmlStringBindings(childNodes, variables) {
14400
+ const found = [];
14401
+ for (const child of childNodes) {
14402
+ if (child.nodeType !== NodeType.TEXT_NODE)
14403
+ continue;
14404
+ const text2 = (child.innerText || "").trim();
14405
+ for (const m of text2.matchAll(/\{([^}]+)\}/g)) {
14406
+ const accessor = parseAccessor(m[1], variables);
14407
+ if (isHtmlStringType(accessor.resolvedType))
14408
+ found.push(m[1]);
14409
+ }
14410
+ }
14411
+ return found;
14412
+ }
14369
14413
  function escapeForJsString(s) {
14370
14414
  return s.replace(/\\/g, "\\\\").replace(/'/g, "\\'").replace(/\n/g, "\\n").replace(/\r/g, "\\r");
14371
14415
  }
@@ -18307,6 +18351,7 @@ function injectHeadfullFSTemplatesRecursive(fsElements, body, sourceDir, importR
18307
18351
  for (const jayTag of jayTags) {
18308
18352
  if (!jayTag.innerHTML.trim()) {
18309
18353
  jayTag.set_content(jayHtmlBody.innerHTML);
18354
+ jayTag.setAttribute("style", "display: contents");
18310
18355
  }
18311
18356
  }
18312
18357
  }
@@ -19680,7 +19725,6 @@ ${context.indent.firstLine} ${createBody})`,
19680
19725
  const forEachFragment = forEachAccessor.render().map((_) => `(${paramName}: ${paramType}) => ${_}`);
19681
19726
  const preAdoptRefNameGenerator = context.refNameGenerator.clone();
19682
19727
  const itemChildNodes = filterContentNodes(element.childNodes);
19683
- `${forEachVariables.currentVar}.${trackBy}`;
19684
19728
  const itemContext = {
19685
19729
  ...context,
19686
19730
  variables: forEachVariables,
@@ -19855,7 +19899,6 @@ ${indent.firstLine})`,
19855
19899
  dynamicRef: true,
19856
19900
  insideSlowForEach: true
19857
19901
  };
19858
- buildRenderContext(itemContext);
19859
19902
  const itemChildNodes = filterContentNodes(element.childNodes);
19860
19903
  const childFragments = itemChildNodes.map((child) => renderHydrateNode(child, itemContext));
19861
19904
  const nonEmptyChildren = childFragments.filter((f) => f.rendered.trim());
@@ -19964,7 +20007,7 @@ function renderHydrateHeadlessInstance(element, context, renderContext, contract
19964
20007
  const coordResult = extractHeadlessCoordinate(element, contractName);
19965
20008
  if (isValidationError(coordResult))
19966
20009
  return coordResult;
19967
- const { instanceCoord, coordSegments, coordinateSuffix, childScopeId } = coordResult;
20010
+ const { instanceCoord, coordinateSuffix, childScopeId } = coordResult;
19968
20011
  const isInsideForEach = context.insideFastForEach;
19969
20012
  let coordinateKey2;
19970
20013
  if (isInsideForEach) {
@@ -20216,6 +20259,21 @@ function renderHydrateElementContent(element, context, renderContext, coordinate
20216
20259
  textFragment = null;
20217
20260
  }
20218
20261
  }
20262
+ const htmlStringBindings = findHtmlStringBindings(childNodes, variables);
20263
+ const isHtmlStringChild = htmlStringBindings.length > 0;
20264
+ if (isHtmlStringChild && (childNodes.length !== 1 || childNodes[0].nodeType !== NodeType.TEXT_NODE)) {
20265
+ return new RenderFragment("", Imports.none(), [
20266
+ `html-string binding {${htmlStringBindings[0]}} must be the sole child of its parent element, not mixed with sibling elements`
20267
+ ]);
20268
+ }
20269
+ if (isHtmlStringChild) {
20270
+ const text2 = (childNodes[0].innerText || "").trim();
20271
+ if (text2 !== `{${htmlStringBindings[0]}}`) {
20272
+ return new RenderFragment("", Imports.none(), [
20273
+ `html-string binding {${htmlStringBindings[0]}} must be the sole child of its parent element, not mixed with other content`
20274
+ ]);
20275
+ }
20276
+ }
20219
20277
  const hasInteractiveChildren = childNodes.some(
20220
20278
  (child) => child.nodeType === NodeType.ELEMENT_NODE && (isConditional(child) && conditionIsInteractive(
20221
20279
  child.getAttribute("if"),
@@ -20285,7 +20343,7 @@ function renderHydrateElementContent(element, context, renderContext, coordinate
20285
20343
  let childImports = Imports.none();
20286
20344
  const childValidations = [];
20287
20345
  const childRefs = [];
20288
- childNodes.forEach((child, index) => {
20346
+ childNodes.forEach((child) => {
20289
20347
  if (child.nodeType === NodeType.ELEMENT_NODE) {
20290
20348
  const frag = renderHydrateNode(child, context);
20291
20349
  if (frag.rendered.trim()) {
@@ -20322,6 +20380,16 @@ function renderHydrateElementContent(element, context, renderContext, coordinate
20322
20380
  mergeRefsTrees(...childRefs, renderedRef.refs)
20323
20381
  );
20324
20382
  }
20383
+ if (isHtmlStringChild && textFragment && !hasDynamicAttrs) {
20384
+ const accessor = textFragment.rendered.replace(/^dt\(/, "").replace(/\)$/, "");
20385
+ const refSuffix2 = renderedRef.rendered ? `, ${renderedRef.rendered}` : "";
20386
+ return new RenderFragment(
20387
+ `${indent.firstLine}adoptElement("${coordinate}", ${attributes2.rendered}, [dh(${accessor})]${refSuffix2})`,
20388
+ Imports.for(Import.adoptElement).plus(Import.dynamicHtml).plus(textFragment.imports.minus(Import.dynamicText)).plus(renderedRef.imports).plus(attributes2.imports),
20389
+ [...textFragment.validations, ...renderedRef.validations, ...attributes2.validations],
20390
+ renderedRef.refs
20391
+ );
20392
+ }
20325
20393
  if (textFragment && !hasDynamicAttrs) {
20326
20394
  const accessor = textFragment.rendered.replace(/^dt\(/, "").replace(/\)$/, "");
20327
20395
  if (refName) {
@@ -20455,7 +20523,32 @@ function renderFunctionDeclaration(preRenderType) {
20455
20523
  return `export declare function render(options?: RenderElementOptions): ${preRenderType}`;
20456
20524
  }
20457
20525
  function renderTextNode(variables, text2, indent) {
20458
- return parseTextExpression(textEscape$1(text2), variables).map((_) => indent.firstLine + _);
20526
+ return parseTextExpression(textEscape$1(decodeHtmlEntities(text2)), variables).map(
20527
+ (_) => indent.firstLine + _
20528
+ );
20529
+ }
20530
+ function tryRenderHtmlStringChild(childNodes, variables, indent) {
20531
+ const htmlStringBindings = findHtmlStringBindings(childNodes, variables);
20532
+ if (htmlStringBindings.length === 0)
20533
+ return null;
20534
+ if (childNodes.length !== 1 || childNodes[0].nodeType !== NodeType.TEXT_NODE) {
20535
+ return new RenderFragment("", Imports.none(), [
20536
+ `html-string binding {${htmlStringBindings[0]}} must be the sole child of its parent element, not mixed with sibling elements`
20537
+ ]);
20538
+ }
20539
+ const text2 = (childNodes[0].innerText || "").trim();
20540
+ if (text2 !== `{${htmlStringBindings[0]}}`) {
20541
+ return new RenderFragment("", Imports.none(), [
20542
+ `html-string binding {${htmlStringBindings[0]}} must be the sole child of its parent element, not mixed with other content`
20543
+ ]);
20544
+ }
20545
+ const accessor = parseAccessor(htmlStringBindings[0], variables);
20546
+ const accessorCode = accessor.render();
20547
+ return new RenderFragment(
20548
+ `${indent.firstLine}dh(${variables.currentVar} => ${accessorCode.rendered})`,
20549
+ Imports.for(Import.dynamicHtml).plus(accessorCode.imports),
20550
+ [...accessor.validations, ...accessorCode.validations]
20551
+ );
20459
20552
  }
20460
20553
  function renderStyleAttribute(styleString, variables) {
20461
20554
  const { declarations, hasDynamic } = parseStyleDeclarations(styleString, variables);
@@ -20695,7 +20788,7 @@ function renderChildCompRef$1(element, { dynamicRef, variables, refNameGenerator
20695
20788
  return new RenderFragment(`${constName}()`, Imports.for(), [], refs);
20696
20789
  }
20697
20790
  function renderNode(node2, context) {
20698
- let { variables, importedSymbols, importedSandboxedSymbols, indent, importerMode } = context;
20791
+ let { variables, importedSandboxedSymbols, indent, importerMode } = context;
20699
20792
  function de2(tagName, attributes2, children, ref, currIndent = indent) {
20700
20793
  const refWithPrefixComma = ref.rendered.length ? `, ${ref.rendered}` : "";
20701
20794
  const tagFunc = tagToNamespace(tagName, true, context.namespaces);
@@ -20753,6 +20846,22 @@ function renderNode(node2, context) {
20753
20846
  };
20754
20847
  }
20755
20848
  let childNodes = filterContentNodes(node2.childNodes, true);
20849
+ const htmlStringChild = tryRenderHtmlStringChild(
20850
+ childNodes,
20851
+ contextForChildren.variables,
20852
+ contextForChildren.indent.child().noFirstLineBreak()
20853
+ );
20854
+ if (htmlStringChild) {
20855
+ let attributes22 = renderAttributes$1(htmlElement, contextForChildren);
20856
+ let renderedRef2 = renderElementRef$1(htmlElement, contextForChildren);
20857
+ return e2(
20858
+ htmlElement.rawTagName,
20859
+ attributes22,
20860
+ htmlStringChild,
20861
+ renderedRef2,
20862
+ newContext.indent
20863
+ );
20864
+ }
20756
20865
  let childIndent = contextForChildren.indent.child();
20757
20866
  if (childNodes.length === 1 && childNodes[0].nodeType === NodeType.TEXT_NODE)
20758
20867
  childIndent = childIndent.noFirstLineBreak();
@@ -21347,7 +21456,7 @@ ${Indent.forceIndent(code, 4)},
21347
21456
  funcRepository)`
21348
21457
  );
21349
21458
  }
21350
- const { renderedRefsManager, refsManagerImport } = renderReferenceManager(
21459
+ const { renderedRefsManager } = renderReferenceManager(
21351
21460
  renderedRoot.refs,
21352
21461
  ReferenceManagerTarget.element
21353
21462
  );
@@ -22273,8 +22382,9 @@ ${indent.firstLine}}`,
22273
22382
  );
22274
22383
  const closeTag = w(itemIndent, `'</${element.rawTagName}>'`);
22275
22384
  const itemBody = mergeServerFragments([openTag, coordinateW, children, closeTag]);
22385
+ const safeArrayExpr = arrayExpr.includes("?.") ? `(${arrayExpr} ?? [])` : arrayExpr;
22276
22386
  return new RenderFragment(
22277
- `${indent.firstLine}for (const ${forEachVariables.currentVar} of ${arrayExpr}) {
22387
+ `${indent.firstLine}for (const ${forEachVariables.currentVar} of ${safeArrayExpr}) {
22278
22388
  ${itemBody.rendered}
22279
22389
  ${indent.firstLine}}`,
22280
22390
  itemBody.imports,
@@ -22284,7 +22394,7 @@ ${indent.firstLine}}`,
22284
22394
  if (isSlowForEach(element)) {
22285
22395
  const slowForEachInfo = getSlowForEachInfo(element);
22286
22396
  if (slowForEachInfo) {
22287
- const { arrayName, jayIndex, jayTrackBy } = slowForEachInfo;
22397
+ const { arrayName, jayIndex } = slowForEachInfo;
22288
22398
  const slowValidated = validateSlowForEachAccessor(arrayName, variables);
22289
22399
  if (isValidationError(slowValidated))
22290
22400
  return slowValidated;
@@ -22337,7 +22447,7 @@ function renderServerHeadlessInstance(element, context, contractName) {
22337
22447
  const coordResult = extractHeadlessCoordinate(element, contractName);
22338
22448
  if (isValidationError(coordResult))
22339
22449
  return coordResult;
22340
- const { instanceCoord, coordSegments, coordinateSuffix } = coordResult;
22450
+ const { instanceCoord, coordinateSuffix } = coordResult;
22341
22451
  let instanceKeyExpr;
22342
22452
  if (context.insideForEach) {
22343
22453
  const trackByKeys = Object.keys(context.varMappings);
@@ -22555,8 +22665,9 @@ function renderServerForEachAsString(element, context) {
22555
22665
  variables: forEachVariables
22556
22666
  };
22557
22667
  const itemContent = renderServerElementAsString(element, itemContext);
22668
+ const safeArrayExpr = arrayExpr.includes("?.") ? `(${arrayExpr} ?? [])` : arrayExpr;
22558
22669
  return new RenderFragment(
22559
- `${arrayExpr}.map((${forEachVariables.currentVar}) => ${itemContent.rendered}).join('')`,
22670
+ `${safeArrayExpr}.map((${forEachVariables.currentVar}) => ${itemContent.rendered}).join('')`,
22560
22671
  itemContent.imports,
22561
22672
  itemContent.validations
22562
22673
  );
@@ -22776,14 +22887,24 @@ function renderServerElementContent(element, context, options) {
22776
22887
  }
22777
22888
  if (isVoid)
22778
22889
  return mergeServerFragments(parts);
22890
+ const htmlStringBindings = findHtmlStringBindings(childNodes, variables);
22891
+ if (htmlStringBindings.length > 0 && !dynamicTextFragment) {
22892
+ return new RenderFragment("", Imports.none(), [
22893
+ `html-string binding {${htmlStringBindings[0]}} must be the sole child of its parent element, not mixed with sibling elements`
22894
+ ]);
22895
+ }
22779
22896
  if (dynamicTextFragment) {
22780
- parts.push(
22781
- w(
22782
- indent,
22783
- `escapeHtml(String(${dynamicTextFragment.rendered}))`,
22784
- Imports.for(Import.escapeHtml)
22785
- )
22786
- );
22897
+ if (htmlStringBindings.length > 0) {
22898
+ parts.push(w(indent, `String(${dynamicTextFragment.rendered})`));
22899
+ } else {
22900
+ parts.push(
22901
+ w(
22902
+ indent,
22903
+ `escapeHtml(String(${dynamicTextFragment.rendered}))`,
22904
+ Imports.for(Import.escapeHtml)
22905
+ )
22906
+ );
22907
+ }
22787
22908
  } else {
22788
22909
  const childContext = {
22789
22910
  ...context,
@@ -396,11 +396,12 @@ tags:
396
396
 
397
397
  ### Basic Types
398
398
 
399
- | Type | Example | Description |
400
- | --------- | ------------------- | ----------------- |
401
- | `string` | `dataType: string` | Text values |
402
- | `number` | `dataType: number` | Numeric values |
403
- | `boolean` | `dataType: boolean` | True/false values |
399
+ | Type | Example | Description |
400
+ | ------------- | ----------------------- | ------------------------------------------------------------- |
401
+ | `string` | `dataType: string` | Text values |
402
+ | `html-string` | `dataType: html-string` | HTML content (rich text, CMS output) — rendered via innerHTML |
403
+ | `number` | `dataType: number` | Numeric values |
404
+ | `boolean` | `dataType: boolean` | True/false values |
404
405
 
405
406
  ### Enum Types
406
407
 
@@ -15,6 +15,7 @@ Each property in the YAML becomes a property of the component's view state, supp
15
15
  | Type | Example | Description |
16
16
  | --------------- | ---------------------------------------------------------------------------- | ------------------------------------ |
17
17
  | `string` | `text: string` | Text values |
18
+ | `html-string` | `richContent: html-string` | HTML content (rich text, CMS output) |
18
19
  | `number` | `count: number` | Numeric values |
19
20
  | `boolean` | `isVisible: boolean` | True/false values |
20
21
  | `object` | <code>user: </br>&nbsp;&nbsp;name: string</br>&nbsp;&nbsp;age: number</code> | Nested object structures |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jay-framework/compiler-jay-html",
3
- "version": "0.16.5",
3
+ "version": "0.17.1",
4
4
  "description": "",
5
5
  "license": "Apache-2.0",
6
6
  "main": "dist/index.js",
@@ -34,14 +34,15 @@
34
34
  },
35
35
  "author": "",
36
36
  "dependencies": {
37
- "@jay-framework/compiler-analyze-exported-types": "^0.16.5",
38
- "@jay-framework/compiler-shared": "^0.16.5",
39
- "@jay-framework/component": "^0.16.5",
40
- "@jay-framework/logger": "^0.16.5",
41
- "@jay-framework/runtime": "^0.16.5",
42
- "@jay-framework/secure": "^0.16.5",
37
+ "@jay-framework/compiler-analyze-exported-types": "^0.17.1",
38
+ "@jay-framework/compiler-shared": "^0.17.1",
39
+ "@jay-framework/component": "^0.17.1",
40
+ "@jay-framework/logger": "^0.17.1",
41
+ "@jay-framework/runtime": "^0.17.1",
42
+ "@jay-framework/secure": "^0.17.1",
43
43
  "@types/js-yaml": "^4.0.9",
44
44
  "change-case": "^4.1.2",
45
+ "he": "^1.2.0",
45
46
  "js-yaml": "^4.1.0",
46
47
  "node-html-parser": "^6.1.12",
47
48
  "pegjs": "^0.10.0",
@@ -51,8 +52,8 @@
51
52
  },
52
53
  "devDependencies": {
53
54
  "@caiogondim/strip-margin": "^1.0.0",
54
- "@jay-framework/4-react": "^0.16.5",
55
- "@jay-framework/dev-environment": "^0.16.5",
55
+ "@jay-framework/4-react": "^0.17.1",
56
+ "@jay-framework/dev-environment": "^0.17.1",
56
57
  "@testing-library/jest-dom": "^6.2.0",
57
58
  "@types/js-beautify": "^1",
58
59
  "@types/node": "^20.11.5",