@jay-framework/compiler-jay-html 0.16.5 → 0.17.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/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));
@@ -14366,6 +14367,23 @@ function filterContentNodes(childNodes, onlyIfMultiple = false) {
14366
14367
  function textEscape$1(s) {
14367
14368
  return s.replace(/'/g, "\\'");
14368
14369
  }
14370
+ function decodeHtmlEntities(s) {
14371
+ return heExports.decode(s);
14372
+ }
14373
+ function findHtmlStringBindings(childNodes, variables) {
14374
+ const found = [];
14375
+ for (const child of childNodes) {
14376
+ if (child.nodeType !== NodeType.TEXT_NODE)
14377
+ continue;
14378
+ const text2 = (child.innerText || "").trim();
14379
+ for (const m of text2.matchAll(/\{([^}]+)\}/g)) {
14380
+ const accessor = parseAccessor(m[1], variables);
14381
+ if (isHtmlStringType(accessor.resolvedType))
14382
+ found.push(m[1]);
14383
+ }
14384
+ }
14385
+ return found;
14386
+ }
14369
14387
  function escapeForJsString(s) {
14370
14388
  return s.replace(/\\/g, "\\\\").replace(/'/g, "\\'").replace(/\n/g, "\\n").replace(/\r/g, "\\r");
14371
14389
  }
@@ -18307,6 +18325,7 @@ function injectHeadfullFSTemplatesRecursive(fsElements, body, sourceDir, importR
18307
18325
  for (const jayTag of jayTags) {
18308
18326
  if (!jayTag.innerHTML.trim()) {
18309
18327
  jayTag.set_content(jayHtmlBody.innerHTML);
18328
+ jayTag.setAttribute("style", "display: contents");
18310
18329
  }
18311
18330
  }
18312
18331
  }
@@ -19680,7 +19699,6 @@ ${context.indent.firstLine} ${createBody})`,
19680
19699
  const forEachFragment = forEachAccessor.render().map((_) => `(${paramName}: ${paramType}) => ${_}`);
19681
19700
  const preAdoptRefNameGenerator = context.refNameGenerator.clone();
19682
19701
  const itemChildNodes = filterContentNodes(element.childNodes);
19683
- `${forEachVariables.currentVar}.${trackBy}`;
19684
19702
  const itemContext = {
19685
19703
  ...context,
19686
19704
  variables: forEachVariables,
@@ -19855,7 +19873,6 @@ ${indent.firstLine})`,
19855
19873
  dynamicRef: true,
19856
19874
  insideSlowForEach: true
19857
19875
  };
19858
- buildRenderContext(itemContext);
19859
19876
  const itemChildNodes = filterContentNodes(element.childNodes);
19860
19877
  const childFragments = itemChildNodes.map((child) => renderHydrateNode(child, itemContext));
19861
19878
  const nonEmptyChildren = childFragments.filter((f) => f.rendered.trim());
@@ -19964,7 +19981,7 @@ function renderHydrateHeadlessInstance(element, context, renderContext, contract
19964
19981
  const coordResult = extractHeadlessCoordinate(element, contractName);
19965
19982
  if (isValidationError(coordResult))
19966
19983
  return coordResult;
19967
- const { instanceCoord, coordSegments, coordinateSuffix, childScopeId } = coordResult;
19984
+ const { instanceCoord, coordinateSuffix, childScopeId } = coordResult;
19968
19985
  const isInsideForEach = context.insideFastForEach;
19969
19986
  let coordinateKey2;
19970
19987
  if (isInsideForEach) {
@@ -20216,6 +20233,21 @@ function renderHydrateElementContent(element, context, renderContext, coordinate
20216
20233
  textFragment = null;
20217
20234
  }
20218
20235
  }
20236
+ const htmlStringBindings = findHtmlStringBindings(childNodes, variables);
20237
+ const isHtmlStringChild = htmlStringBindings.length > 0;
20238
+ if (isHtmlStringChild && (childNodes.length !== 1 || childNodes[0].nodeType !== NodeType.TEXT_NODE)) {
20239
+ return new RenderFragment("", Imports.none(), [
20240
+ `html-string binding {${htmlStringBindings[0]}} must be the sole child of its parent element, not mixed with sibling elements`
20241
+ ]);
20242
+ }
20243
+ if (isHtmlStringChild) {
20244
+ const text2 = (childNodes[0].innerText || "").trim();
20245
+ if (text2 !== `{${htmlStringBindings[0]}}`) {
20246
+ return new RenderFragment("", Imports.none(), [
20247
+ `html-string binding {${htmlStringBindings[0]}} must be the sole child of its parent element, not mixed with other content`
20248
+ ]);
20249
+ }
20250
+ }
20219
20251
  const hasInteractiveChildren = childNodes.some(
20220
20252
  (child) => child.nodeType === NodeType.ELEMENT_NODE && (isConditional(child) && conditionIsInteractive(
20221
20253
  child.getAttribute("if"),
@@ -20285,7 +20317,7 @@ function renderHydrateElementContent(element, context, renderContext, coordinate
20285
20317
  let childImports = Imports.none();
20286
20318
  const childValidations = [];
20287
20319
  const childRefs = [];
20288
- childNodes.forEach((child, index) => {
20320
+ childNodes.forEach((child) => {
20289
20321
  if (child.nodeType === NodeType.ELEMENT_NODE) {
20290
20322
  const frag = renderHydrateNode(child, context);
20291
20323
  if (frag.rendered.trim()) {
@@ -20322,6 +20354,16 @@ function renderHydrateElementContent(element, context, renderContext, coordinate
20322
20354
  mergeRefsTrees(...childRefs, renderedRef.refs)
20323
20355
  );
20324
20356
  }
20357
+ if (isHtmlStringChild && textFragment && !hasDynamicAttrs) {
20358
+ const accessor = textFragment.rendered.replace(/^dt\(/, "").replace(/\)$/, "");
20359
+ const refSuffix2 = renderedRef.rendered ? `, ${renderedRef.rendered}` : "";
20360
+ return new RenderFragment(
20361
+ `${indent.firstLine}adoptElement("${coordinate}", ${attributes2.rendered}, [dh(${accessor})]${refSuffix2})`,
20362
+ Imports.for(Import.adoptElement).plus(Import.dynamicHtml).plus(textFragment.imports.minus(Import.dynamicText)).plus(renderedRef.imports).plus(attributes2.imports),
20363
+ [...textFragment.validations, ...renderedRef.validations, ...attributes2.validations],
20364
+ renderedRef.refs
20365
+ );
20366
+ }
20325
20367
  if (textFragment && !hasDynamicAttrs) {
20326
20368
  const accessor = textFragment.rendered.replace(/^dt\(/, "").replace(/\)$/, "");
20327
20369
  if (refName) {
@@ -20455,7 +20497,32 @@ function renderFunctionDeclaration(preRenderType) {
20455
20497
  return `export declare function render(options?: RenderElementOptions): ${preRenderType}`;
20456
20498
  }
20457
20499
  function renderTextNode(variables, text2, indent) {
20458
- return parseTextExpression(textEscape$1(text2), variables).map((_) => indent.firstLine + _);
20500
+ return parseTextExpression(textEscape$1(decodeHtmlEntities(text2)), variables).map(
20501
+ (_) => indent.firstLine + _
20502
+ );
20503
+ }
20504
+ function tryRenderHtmlStringChild(childNodes, variables, indent) {
20505
+ const htmlStringBindings = findHtmlStringBindings(childNodes, variables);
20506
+ if (htmlStringBindings.length === 0)
20507
+ return null;
20508
+ if (childNodes.length !== 1 || childNodes[0].nodeType !== NodeType.TEXT_NODE) {
20509
+ return new RenderFragment("", Imports.none(), [
20510
+ `html-string binding {${htmlStringBindings[0]}} must be the sole child of its parent element, not mixed with sibling elements`
20511
+ ]);
20512
+ }
20513
+ const text2 = (childNodes[0].innerText || "").trim();
20514
+ if (text2 !== `{${htmlStringBindings[0]}}`) {
20515
+ return new RenderFragment("", Imports.none(), [
20516
+ `html-string binding {${htmlStringBindings[0]}} must be the sole child of its parent element, not mixed with other content`
20517
+ ]);
20518
+ }
20519
+ const accessor = parseAccessor(htmlStringBindings[0], variables);
20520
+ const accessorCode = accessor.render();
20521
+ return new RenderFragment(
20522
+ `${indent.firstLine}dh(${variables.currentVar} => ${accessorCode.rendered})`,
20523
+ Imports.for(Import.dynamicHtml).plus(accessorCode.imports),
20524
+ [...accessor.validations, ...accessorCode.validations]
20525
+ );
20459
20526
  }
20460
20527
  function renderStyleAttribute(styleString, variables) {
20461
20528
  const { declarations, hasDynamic } = parseStyleDeclarations(styleString, variables);
@@ -20695,7 +20762,7 @@ function renderChildCompRef$1(element, { dynamicRef, variables, refNameGenerator
20695
20762
  return new RenderFragment(`${constName}()`, Imports.for(), [], refs);
20696
20763
  }
20697
20764
  function renderNode(node2, context) {
20698
- let { variables, importedSymbols, importedSandboxedSymbols, indent, importerMode } = context;
20765
+ let { variables, importedSandboxedSymbols, indent, importerMode } = context;
20699
20766
  function de2(tagName, attributes2, children, ref, currIndent = indent) {
20700
20767
  const refWithPrefixComma = ref.rendered.length ? `, ${ref.rendered}` : "";
20701
20768
  const tagFunc = tagToNamespace(tagName, true, context.namespaces);
@@ -20753,6 +20820,22 @@ function renderNode(node2, context) {
20753
20820
  };
20754
20821
  }
20755
20822
  let childNodes = filterContentNodes(node2.childNodes, true);
20823
+ const htmlStringChild = tryRenderHtmlStringChild(
20824
+ childNodes,
20825
+ contextForChildren.variables,
20826
+ contextForChildren.indent.child().noFirstLineBreak()
20827
+ );
20828
+ if (htmlStringChild) {
20829
+ let attributes22 = renderAttributes$1(htmlElement, contextForChildren);
20830
+ let renderedRef2 = renderElementRef$1(htmlElement, contextForChildren);
20831
+ return e2(
20832
+ htmlElement.rawTagName,
20833
+ attributes22,
20834
+ htmlStringChild,
20835
+ renderedRef2,
20836
+ newContext.indent
20837
+ );
20838
+ }
20756
20839
  let childIndent = contextForChildren.indent.child();
20757
20840
  if (childNodes.length === 1 && childNodes[0].nodeType === NodeType.TEXT_NODE)
20758
20841
  childIndent = childIndent.noFirstLineBreak();
@@ -21347,7 +21430,7 @@ ${Indent.forceIndent(code, 4)},
21347
21430
  funcRepository)`
21348
21431
  );
21349
21432
  }
21350
- const { renderedRefsManager, refsManagerImport } = renderReferenceManager(
21433
+ const { renderedRefsManager } = renderReferenceManager(
21351
21434
  renderedRoot.refs,
21352
21435
  ReferenceManagerTarget.element
21353
21436
  );
@@ -22273,8 +22356,9 @@ ${indent.firstLine}}`,
22273
22356
  );
22274
22357
  const closeTag = w(itemIndent, `'</${element.rawTagName}>'`);
22275
22358
  const itemBody = mergeServerFragments([openTag, coordinateW, children, closeTag]);
22359
+ const safeArrayExpr = arrayExpr.includes("?.") ? `(${arrayExpr} ?? [])` : arrayExpr;
22276
22360
  return new RenderFragment(
22277
- `${indent.firstLine}for (const ${forEachVariables.currentVar} of ${arrayExpr}) {
22361
+ `${indent.firstLine}for (const ${forEachVariables.currentVar} of ${safeArrayExpr}) {
22278
22362
  ${itemBody.rendered}
22279
22363
  ${indent.firstLine}}`,
22280
22364
  itemBody.imports,
@@ -22284,7 +22368,7 @@ ${indent.firstLine}}`,
22284
22368
  if (isSlowForEach(element)) {
22285
22369
  const slowForEachInfo = getSlowForEachInfo(element);
22286
22370
  if (slowForEachInfo) {
22287
- const { arrayName, jayIndex, jayTrackBy } = slowForEachInfo;
22371
+ const { arrayName, jayIndex } = slowForEachInfo;
22288
22372
  const slowValidated = validateSlowForEachAccessor(arrayName, variables);
22289
22373
  if (isValidationError(slowValidated))
22290
22374
  return slowValidated;
@@ -22337,7 +22421,7 @@ function renderServerHeadlessInstance(element, context, contractName) {
22337
22421
  const coordResult = extractHeadlessCoordinate(element, contractName);
22338
22422
  if (isValidationError(coordResult))
22339
22423
  return coordResult;
22340
- const { instanceCoord, coordSegments, coordinateSuffix } = coordResult;
22424
+ const { instanceCoord, coordinateSuffix } = coordResult;
22341
22425
  let instanceKeyExpr;
22342
22426
  if (context.insideForEach) {
22343
22427
  const trackByKeys = Object.keys(context.varMappings);
@@ -22555,8 +22639,9 @@ function renderServerForEachAsString(element, context) {
22555
22639
  variables: forEachVariables
22556
22640
  };
22557
22641
  const itemContent = renderServerElementAsString(element, itemContext);
22642
+ const safeArrayExpr = arrayExpr.includes("?.") ? `(${arrayExpr} ?? [])` : arrayExpr;
22558
22643
  return new RenderFragment(
22559
- `${arrayExpr}.map((${forEachVariables.currentVar}) => ${itemContent.rendered}).join('')`,
22644
+ `${safeArrayExpr}.map((${forEachVariables.currentVar}) => ${itemContent.rendered}).join('')`,
22560
22645
  itemContent.imports,
22561
22646
  itemContent.validations
22562
22647
  );
@@ -22776,14 +22861,24 @@ function renderServerElementContent(element, context, options) {
22776
22861
  }
22777
22862
  if (isVoid)
22778
22863
  return mergeServerFragments(parts);
22864
+ const htmlStringBindings = findHtmlStringBindings(childNodes, variables);
22865
+ if (htmlStringBindings.length > 0 && !dynamicTextFragment) {
22866
+ return new RenderFragment("", Imports.none(), [
22867
+ `html-string binding {${htmlStringBindings[0]}} must be the sole child of its parent element, not mixed with sibling elements`
22868
+ ]);
22869
+ }
22779
22870
  if (dynamicTextFragment) {
22780
- parts.push(
22781
- w(
22782
- indent,
22783
- `escapeHtml(String(${dynamicTextFragment.rendered}))`,
22784
- Imports.for(Import.escapeHtml)
22785
- )
22786
- );
22871
+ if (htmlStringBindings.length > 0) {
22872
+ parts.push(w(indent, `String(${dynamicTextFragment.rendered})`));
22873
+ } else {
22874
+ parts.push(
22875
+ w(
22876
+ indent,
22877
+ `escapeHtml(String(${dynamicTextFragment.rendered}))`,
22878
+ Imports.for(Import.escapeHtml)
22879
+ )
22880
+ );
22881
+ }
22787
22882
  } else {
22788
22883
  const childContext = {
22789
22884
  ...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.0",
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.0",
38
+ "@jay-framework/compiler-shared": "^0.17.0",
39
+ "@jay-framework/component": "^0.17.0",
40
+ "@jay-framework/logger": "^0.17.0",
41
+ "@jay-framework/runtime": "^0.17.0",
42
+ "@jay-framework/secure": "^0.17.0",
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.0",
56
+ "@jay-framework/dev-environment": "^0.17.0",
56
57
  "@testing-library/jest-dom": "^6.2.0",
57
58
  "@types/js-beautify": "^1",
58
59
  "@types/node": "^20.11.5",