@wavemaker-ai/react-codegen 1.0.0-rc.647502 → 1.0.0-rc.647582

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.
Files changed (85) hide show
  1. package/dist/transpiler/index.mjs +1007 -1033
  2. package/dist/transpiler/index.mjs.map +1 -1
  3. package/package-lock.json +125 -125
  4. package/package.json +1 -1
  5. package/src/transpile/bind.ex.transformer.js +18 -1
  6. package/src/transpile/bind.ex.transformer.js.map +1 -1
  7. package/src/transpile/components/container/accordion-pane.transformer.js +4 -20
  8. package/src/transpile/components/container/accordion-pane.transformer.js.map +1 -1
  9. package/src/transpile/components/container/container.transformer.js +7 -21
  10. package/src/transpile/components/container/container.transformer.js.map +1 -1
  11. package/src/transpile/components/container/panel.transformer.js +4 -20
  12. package/src/transpile/components/container/panel.transformer.js.map +1 -1
  13. package/src/transpile/components/container/tabpane.transformer.js +4 -20
  14. package/src/transpile/components/container/tabpane.transformer.js.map +1 -1
  15. package/src/transpile/components/container/wizardstep.transformer.js +4 -36
  16. package/src/transpile/components/container/wizardstep.transformer.js.map +1 -1
  17. package/src/transpile/components/data/card/card-content.transformer.js +4 -20
  18. package/src/transpile/components/data/card/card-content.transformer.js.map +1 -1
  19. package/src/transpile/components/data/form/field-widget-shared.js +9 -0
  20. package/src/transpile/components/data/form/field-widget-shared.js.map +1 -0
  21. package/src/transpile/components/data/form/form-field.transformer.js +24 -26
  22. package/src/transpile/components/data/form/form-field.transformer.js.map +1 -1
  23. package/src/transpile/components/data/list/list-transformer.js +9 -2
  24. package/src/transpile/components/data/list/list-transformer.js.map +1 -1
  25. package/src/transpile/components/data/live-filter-field.transformer.js +30 -32
  26. package/src/transpile/components/data/live-filter-field.transformer.js.map +1 -1
  27. package/src/transpile/components/data/live-form-shared.js +135 -0
  28. package/src/transpile/components/data/live-form-shared.js.map +1 -0
  29. package/src/transpile/components/data/livefilter.transformer.js +3 -123
  30. package/src/transpile/components/data/livefilter.transformer.js.map +1 -1
  31. package/src/transpile/components/data/liveform.transformer.js +9 -128
  32. package/src/transpile/components/data/liveform.transformer.js.map +1 -1
  33. package/src/transpile/components/data/table/table-column.transformer.js +6 -3
  34. package/src/transpile/components/data/table/table-column.transformer.js.map +1 -1
  35. package/src/transpile/components/data/table/table-row.transformer.js +9 -20
  36. package/src/transpile/components/data/table/table-row.transformer.js.map +1 -1
  37. package/src/transpile/components/data/table/table.transformer.js +5 -2
  38. package/src/transpile/components/data/table/table.transformer.js.map +1 -1
  39. package/src/transpile/components/data/table/utils.js +70 -0
  40. package/src/transpile/components/data/table/utils.js.map +1 -1
  41. package/src/transpile/components/dialogs/alert-dialog.transformer.js +5 -13
  42. package/src/transpile/components/dialogs/alert-dialog.transformer.js.map +1 -1
  43. package/src/transpile/components/dialogs/confirm-dialog.transformer.js +5 -13
  44. package/src/transpile/components/dialogs/confirm-dialog.transformer.js.map +1 -1
  45. package/src/transpile/components/dialogs/dialog-factory.js +18 -0
  46. package/src/transpile/components/dialogs/dialog-factory.js.map +1 -0
  47. package/src/transpile/components/dialogs/iframe-dialog.transformer.js +5 -13
  48. package/src/transpile/components/dialogs/iframe-dialog.transformer.js.map +1 -1
  49. package/src/transpile/components/layout/footer.transformer.js +7 -45
  50. package/src/transpile/components/layout/footer.transformer.js.map +1 -1
  51. package/src/transpile/components/layout/header.transformer.js +7 -45
  52. package/src/transpile/components/layout/header.transformer.js.map +1 -1
  53. package/src/transpile/components/layout/layout-region-factory.js +46 -0
  54. package/src/transpile/components/layout/layout-region-factory.js.map +1 -0
  55. package/src/transpile/components/layout/leftnav.transformer.js +7 -45
  56. package/src/transpile/components/layout/leftnav.transformer.js.map +1 -1
  57. package/src/transpile/components/layout/rightnav.transformer.js +7 -45
  58. package/src/transpile/components/layout/rightnav.transformer.js.map +1 -1
  59. package/src/transpile/components/layout/topnav.transformer.js +7 -45
  60. package/src/transpile/components/layout/topnav.transformer.js.map +1 -1
  61. package/src/transpile/components/navigation/popover.transformer.js +5 -21
  62. package/src/transpile/components/navigation/popover.transformer.js.map +1 -1
  63. package/src/transpile/components/page/build-partial-markup.js +55 -0
  64. package/src/transpile/components/page/build-partial-markup.js.map +1 -0
  65. package/src/transpile/components/page/partial-container.transformer.js +2 -47
  66. package/src/transpile/components/page/partial-container.transformer.js.map +1 -1
  67. package/src/transpile/components/page/with-partial-container.js +26 -0
  68. package/src/transpile/components/page/with-partial-container.js.map +1 -0
  69. package/src/transpile/components/partial/partial-content.transformer.js +2 -47
  70. package/src/transpile/components/partial/partial-content.transformer.js.map +1 -1
  71. package/src/transpile/components/utils.js +58 -67
  72. package/src/transpile/components/utils.js.map +1 -1
  73. package/src/transpile/transform-markup.js +5 -2
  74. package/src/transpile/transform-markup.js.map +1 -1
  75. package/src/transpile/transpile.js +265 -134
  76. package/src/transpile/transpile.js.map +1 -1
  77. package/src/transpile/widget-inline-style-processor.js +58 -20
  78. package/src/transpile/widget-inline-style-processor.js.map +1 -1
  79. package/src/utils/grouping-util.js +41 -13
  80. package/src/utils/grouping-util.js.map +1 -1
  81. package/src/variables/variable.transformer.js +64 -18
  82. package/src/variables/variable.transformer.js.map +1 -1
  83. package/templates/component/layout.hbs +1 -0
  84. package/templates/project/package.json +4 -4
  85. package/templates/variables.template +3 -0
@@ -46,6 +46,7 @@ const property_parser_1 = require("./property/property-parser");
46
46
  const utils_browser_1 = require("../utils.browser");
47
47
  const id_generator_1 = require("./id-generator");
48
48
  const widget_inline_style_processor_1 = require("./widget-inline-style-processor");
49
+ const utils_1 = require("./components/data/table/utils");
49
50
  const generateRandomString = (length = 10) => Math.random().toString(20).substr(2, length);
50
51
  exports.generateRandomString = generateRandomString;
51
52
  const EVENT_NAME_MAP = {
@@ -576,8 +577,115 @@ class Transpiler {
576
577
  className: (0, utils_browser_1.addOptionalChaining)(classes),
577
578
  };
578
579
  }
580
+ // Parse arguments properly, handling commas inside object literals and arrays
581
+ parseArguments(argString) {
582
+ const args = [];
583
+ let currentArg = "";
584
+ let braceCount = 0;
585
+ let bracketCount = 0;
586
+ for (let i = 0; i < argString.length; i++) {
587
+ const char = argString[i];
588
+ // Track object literals (curly braces) and arrays (square brackets)
589
+ if (char === "{")
590
+ braceCount++;
591
+ else if (char === "}")
592
+ braceCount--;
593
+ else if (char === "[")
594
+ bracketCount++;
595
+ else if (char === "]")
596
+ bracketCount--;
597
+ // If we encounter a comma at the top level (not inside an object or array), it's an argument separator
598
+ if (char === "," && braceCount === 0 && bracketCount === 0) {
599
+ if (currentArg.trim()) {
600
+ args.push(currentArg.trim());
601
+ }
602
+ currentArg = "";
603
+ continue;
604
+ }
605
+ currentArg += char;
606
+ }
607
+ if (currentArg.trim()) {
608
+ args.push(currentArg.trim());
609
+ }
610
+ return args;
611
+ }
612
+ // Droping literal arguments like strings, numbers, booleans, null/undefined
613
+ isLiteral(s) {
614
+ const v = s.trim();
615
+ return (/^(['"]).*\1$/.test(v) ||
616
+ /^-?\d+(?:\.\d+)?$/.test(v) ||
617
+ /^(true|false|null|undefined)$/i.test(v));
618
+ }
619
+ // Arithmetic/binary expressions (e.g. "0-5", "0+3") are not valid parameter names.
620
+ // The Angular parser converts unary negatives like -5 into binary (0-5).
621
+ isArithmeticExpression(s) {
622
+ const v = s.trim();
623
+ return /^\d+\s*[-+*/%]\s*\d+/.test(v);
624
+ }
625
+ // Check if argument contains a dot (property access), which makes it an expression, not a valid parameter name
626
+ isPropertyAccess(s) {
627
+ return s.trim().includes(".");
628
+ }
629
+ // Object literals should not be extracted as function parameters
630
+ isObjectLiteral(s) {
631
+ const trimmed = s.trim();
632
+ if (trimmed.startsWith("{") && trimmed.includes(":")) {
633
+ let braceCount = 0;
634
+ let inString = false;
635
+ let stringChar = "";
636
+ for (let i = 0; i < trimmed.length; i++) {
637
+ const char = trimmed[i];
638
+ if ((char === '"' || char === "'") && (i === 0 || trimmed[i - 1] !== "\\")) {
639
+ if (!inString) {
640
+ inString = true;
641
+ stringChar = char;
642
+ }
643
+ else if (char === stringChar) {
644
+ inString = false;
645
+ }
646
+ }
647
+ else if (!inString) {
648
+ if (char === "{")
649
+ braceCount++;
650
+ else if (char === "}")
651
+ braceCount--;
652
+ }
653
+ }
654
+ return braceCount === 0 && trimmed.endsWith("}");
655
+ }
656
+ return false;
657
+ }
658
+ // Array literals should not be extracted as function parameters
659
+ isArrayLiteral(s) {
660
+ const trimmed = s.trim();
661
+ if (trimmed.startsWith("[") && trimmed.endsWith("]")) {
662
+ let bracketCount = 0;
663
+ let inString = false;
664
+ let stringChar = "";
665
+ for (let i = 0; i < trimmed.length; i++) {
666
+ const char = trimmed[i];
667
+ if ((char === '"' || char === "'") && (i === 0 || trimmed[i - 1] !== "\\")) {
668
+ if (!inString) {
669
+ inString = true;
670
+ stringChar = char;
671
+ }
672
+ else if (char === stringChar) {
673
+ inString = false;
674
+ }
675
+ }
676
+ else if (!inString) {
677
+ if (char === "[")
678
+ bracketCount++;
679
+ else if (char === "]")
680
+ bracketCount--;
681
+ }
682
+ }
683
+ return bracketCount === 0;
684
+ }
685
+ return false;
686
+ }
579
687
  findArgs(str, context) {
580
- var _a;
688
+ var _a, _b;
581
689
  let argStr = "";
582
690
  let maxSplits = 0;
583
691
  (_a = str.match(/\([^;]*\)/g)) === null || _a === void 0 ? void 0 : _a.forEach(s => {
@@ -588,135 +696,21 @@ class Transpiler {
588
696
  }
589
697
  });
590
698
  argStr = argStr.replace(/\(|\)/g, "");
591
- if (context === null || context === void 0 ? void 0 : context.get("isInsideList")) {
699
+ if ((_b = context === null || context === void 0 ? void 0 : context.get) === null || _b === void 0 ? void 0 : _b.call(context, "isInsideList")) {
592
700
  argStr = argStr
593
701
  .split(",")
594
702
  // List row context: omit loop-scoped proxies from synthesized handler params (`$item` from outer closure)
595
703
  .filter(s => !(0, lodash_1.includes)(["$item", "currentItemWidgets"], s.trim()))
596
704
  .join(",");
597
705
  }
598
- // Parse arguments properly, handling commas inside object literals and arrays
599
- const parseArguments = (argString) => {
600
- const args = [];
601
- let currentArg = "";
602
- let braceCount = 0;
603
- let bracketCount = 0;
604
- for (let i = 0; i < argString.length; i++) {
605
- const char = argString[i];
606
- // Track object literals (curly braces) and arrays (square brackets)
607
- if (char === "{")
608
- braceCount++;
609
- else if (char === "}")
610
- braceCount--;
611
- else if (char === "[")
612
- bracketCount++;
613
- else if (char === "]")
614
- bracketCount--;
615
- // If we encounter a comma at the top level (not inside an object or array), it's an argument separator
616
- if (char === "," && braceCount === 0 && bracketCount === 0) {
617
- if (currentArg.trim()) {
618
- args.push(currentArg.trim());
619
- }
620
- currentArg = "";
621
- continue;
622
- }
623
- currentArg += char;
624
- }
625
- // Add the last argument
626
- if (currentArg.trim()) {
627
- args.push(currentArg.trim());
628
- }
629
- return args;
630
- };
631
- // Droping literal arguments like strings, numbers, booleans, null/undefined
632
- const isLiteral = (s) => {
633
- const v = s.trim();
634
- return (/^(['"]).*\1$/.test(v) ||
635
- /^-?\d+(?:\.\d+)?$/.test(v) ||
636
- /^(true|false|null|undefined)$/i.test(v));
637
- };
638
- // Arithmetic/binary expressions (e.g. "0-5", "0+3") are not valid parameter names.
639
- // The Angular parser converts unary negatives like -5 into binary (0-5).
640
- const isArithmeticExpression = (s) => {
641
- const v = s.trim();
642
- return /^\d+\s*[-+*/%]\s*\d+/.test(v);
643
- };
644
- // Check if argument contains a dot (property access), which makes it an expression, not a valid parameter name
645
- const isPropertyAccess = (s) => {
646
- return s.trim().includes(".");
647
- };
648
- // Object literals should not be extracted as function parameters
649
- const isObjectLiteral = (s) => {
650
- const trimmed = s.trim();
651
- // Check if it starts with { and contains at least one : (key-value pair)
652
- if (trimmed.startsWith("{") && trimmed.includes(":")) {
653
- // Verify it's a balanced object literal
654
- let braceCount = 0;
655
- let inString = false;
656
- let stringChar = "";
657
- for (let i = 0; i < trimmed.length; i++) {
658
- const char = trimmed[i];
659
- if ((char === '"' || char === "'") && (i === 0 || trimmed[i - 1] !== "\\")) {
660
- if (!inString) {
661
- inString = true;
662
- stringChar = char;
663
- }
664
- else if (char === stringChar) {
665
- inString = false;
666
- }
667
- }
668
- else if (!inString) {
669
- if (char === "{")
670
- braceCount++;
671
- else if (char === "}")
672
- braceCount--;
673
- }
674
- }
675
- // If braces are balanced and it ends with }, it's an object literal
676
- return braceCount === 0 && trimmed.endsWith("}");
677
- }
678
- return false;
679
- };
680
- // Array literals should not be extracted as function parameters
681
- const isArrayLiteral = (s) => {
682
- const trimmed = s.trim();
683
- // Check if it starts with [ and ends with ]
684
- if (trimmed.startsWith("[") && trimmed.endsWith("]")) {
685
- // Verify it's a balanced array literal
686
- let bracketCount = 0;
687
- let inString = false;
688
- let stringChar = "";
689
- for (let i = 0; i < trimmed.length; i++) {
690
- const char = trimmed[i];
691
- if ((char === '"' || char === "'") && (i === 0 || trimmed[i - 1] !== "\\")) {
692
- if (!inString) {
693
- inString = true;
694
- stringChar = char;
695
- }
696
- else if (char === stringChar) {
697
- inString = false;
698
- }
699
- }
700
- else if (!inString) {
701
- if (char === "[")
702
- bracketCount++;
703
- else if (char === "]")
704
- bracketCount--;
705
- }
706
- }
707
- // If brackets are balanced, it's an array literal
708
- return bracketCount === 0;
709
- }
710
- return false;
711
- };
712
- const parsedArgs = parseArguments(argStr);
706
+ const parsedArgs = this.parseArguments(argStr);
713
707
  const args = parsedArgs
714
708
  .filter(Boolean)
715
- .filter(s => !isLiteral(s))
716
- .filter(s => !isArithmeticExpression(s))
717
- .filter(s => !isPropertyAccess(s))
718
- .filter(s => !isObjectLiteral(s))
719
- .filter(s => !isArrayLiteral(s));
709
+ .filter(s => !this.isLiteral(s))
710
+ .filter(s => !this.isArithmeticExpression(s))
711
+ .filter(s => !this.isPropertyAccess(s))
712
+ .filter(s => !this.isObjectLiteral(s))
713
+ .filter(s => !this.isArrayLiteral(s));
720
714
  const usesBareEvent = /\$event\b/.test(str);
721
715
  const hasEventParam = args.some(a => a.trim() === "$event");
722
716
  if (usesBareEvent && !hasEventParam) {
@@ -724,6 +718,124 @@ class Transpiler {
724
718
  }
725
719
  return `(${args.join(", ")})`;
726
720
  }
721
+ // Parse "($event, widget)" → ["$event", "widget"]; "()" → []
722
+ parseArrowParamNames(argsStr) {
723
+ const inner = argsStr.replace(/^\(|\)$/g, "").trim();
724
+ if (!inner)
725
+ return [];
726
+ return inner
727
+ .split(",")
728
+ .map(s => s.trim())
729
+ .filter(Boolean);
730
+ }
731
+ // Detect a `;` outside strings/parens/braces/brackets — signals multiple top-level statements
732
+ hasTopLevelSemicolon(body) {
733
+ let paren = 0;
734
+ let brace = 0;
735
+ let bracket = 0;
736
+ let inString = false;
737
+ let stringChar = "";
738
+ for (let i = 0; i < body.length; i++) {
739
+ const ch = body[i];
740
+ if ((ch === '"' || ch === "'") && (i === 0 || body[i - 1] !== "\\")) {
741
+ if (!inString) {
742
+ inString = true;
743
+ stringChar = ch;
744
+ }
745
+ else if (ch === stringChar) {
746
+ inString = false;
747
+ }
748
+ continue;
749
+ }
750
+ if (inString)
751
+ continue;
752
+ if (ch === "(")
753
+ paren++;
754
+ else if (ch === ")")
755
+ paren--;
756
+ else if (ch === "{")
757
+ brace++;
758
+ else if (ch === "}")
759
+ brace--;
760
+ else if (ch === "[")
761
+ bracket++;
762
+ else if (ch === "]")
763
+ bracket--;
764
+ else if (ch === ";" && paren === 0 && brace === 0 && bracket === 0)
765
+ return true;
766
+ }
767
+ return false;
768
+ }
769
+ isInstanceBoundFragmentCallee(calleeRef) {
770
+ return Transpiler.INSTANCE_BOUND_CALLEE.test(calleeRef);
771
+ }
772
+ // Match a body shaped like `fragment(...property chain...)?.(args)` — return callee ref + raw arg list
773
+ extractFragmentMethodCall(body) {
774
+ const trimmed = body.trim();
775
+ if (!trimmed.endsWith(")") || !trimmed.startsWith("fragment"))
776
+ return null;
777
+ let depth = 0;
778
+ let openIdx = -1;
779
+ for (let i = trimmed.length - 1; i >= 0; i--) {
780
+ const ch = trimmed[i];
781
+ if (ch === ")")
782
+ depth++;
783
+ else if (ch === "(") {
784
+ depth--;
785
+ if (depth === 0) {
786
+ openIdx = i;
787
+ break;
788
+ }
789
+ }
790
+ }
791
+ if (openIdx < 2)
792
+ return null;
793
+ if (trimmed.substring(openIdx - 2, openIdx) !== "?.")
794
+ return null;
795
+ const calleeRef = trimmed.substring(0, openIdx - 2);
796
+ if (!Transpiler.FRAGMENT_CALLEE_REF.test(calleeRef))
797
+ return null;
798
+ const argsStr = trimmed.substring(openIdx + 1, trimmed.length - 1);
799
+ const callArgs = this.parseArguments(argsStr);
800
+ return { calleeRef, callArgs };
801
+ }
802
+ // Decide if an `on-*` handler body can be emitted as a direct function reference instead of an arrow wrapper.
803
+ // Eligible when body is a single `fragment?.x?.(...)` call whose args are all simple identifiers already
804
+ // present in the synthesized arrow parameter list — i.e. nothing references closure-only values like `$item`,
805
+ // `currentItemWidgetsRef.current`, literals, property-access expressions, or table column `rowData`.
806
+ //
807
+ // Additional exclusion: callee paths through `Actions` or `Variables` resolve to runtime instance
808
+ // methods (NavigationAction.invoke, BaseVariable.invoke, setData, navigate, …) that rely on `this`.
809
+ // Emitting them as detached refs strips the receiver and breaks runtime + WmAnchor's
810
+ // `getGoToPageNameFromClickHandler` source-string detection, so always wrap those in an arrow.
811
+ canUseDirectHandlerReference(body, arrowParams) {
812
+ const trimmed = body.replace(/;+\s*$/, "").trim();
813
+ if (!trimmed)
814
+ return null;
815
+ if (this.hasTopLevelSemicolon(trimmed))
816
+ return null;
817
+ const parsed = this.extractFragmentMethodCall(trimmed);
818
+ if (!parsed)
819
+ return null;
820
+ if (this.isInstanceBoundFragmentCallee(parsed.calleeRef))
821
+ return null;
822
+ const paramSet = new Set(arrowParams);
823
+ for (const raw of parsed.callArgs) {
824
+ const a = raw.trim();
825
+ if (!a)
826
+ continue;
827
+ if (this.isLiteral(a) ||
828
+ this.isArithmeticExpression(a) ||
829
+ this.isObjectLiteral(a) ||
830
+ this.isArrayLiteral(a) ||
831
+ this.isPropertyAccess(a)) {
832
+ return null;
833
+ }
834
+ if (!paramSet.has(a))
835
+ return null;
836
+ }
837
+ return parsed.calleeRef;
838
+ }
727
839
  quoteAttr(v) {
728
840
  return ("" + v) /* Forces the conversion to string. */
729
841
  .replace(/&/g, "&amp;") /* This MUST be the 1st replacement. */
@@ -745,6 +857,7 @@ class Transpiler {
745
857
  return attrName.endsWith("url") || attrName.endsWith("src");
746
858
  }
747
859
  transformAttr(tagName, name, value, context, tx) {
860
+ var _a, _b, _c;
748
861
  if (name === "styles" || name === "style" || name === "className") {
749
862
  // continue
750
863
  }
@@ -759,16 +872,24 @@ class Transpiler {
759
872
  value = value.replace(/item\)/g, "$item)");
760
873
  // List preprocessors strip `?.` via removeOptionChaining before dataset replace — restore
761
874
  // fragment/Variables optional chaining for the emitted handler body.
762
- if (context === null || context === void 0 ? void 0 : context.get("isInsideList")) {
875
+ if ((_a = context === null || context === void 0 ? void 0 : context.get) === null || _a === void 0 ? void 0 : _a.call(context, "isInsideList")) {
763
876
  value = value.replace(/;+\s*$/, "").trim();
764
877
  value = addFragmentOptionalChaining(value, false);
765
878
  }
766
879
  const args = this.findArgs(value, context);
767
- if (context === null || context === void 0 ? void 0 : context.get("isInsideTableColumn")) {
880
+ if ((_b = context === null || context === void 0 ? void 0 : context.get) === null || _b === void 0 ? void 0 : _b.call(context, "isInsideTableColumn")) {
768
881
  value = value.replace(/\brow\b/g, "rowData");
769
882
  }
770
- value = `${args} => {${value}}`;
771
- value = `{${value}}`;
883
+ const arrowParams = this.parseArrowParamNames(args);
884
+ const bodyForCheck = value.replace(/;+\s*$/, "").trim();
885
+ const directRef = this.canUseDirectHandlerReference(bodyForCheck, arrowParams);
886
+ if (directRef) {
887
+ value = `{${directRef}}`;
888
+ }
889
+ else {
890
+ value = `${args} => {${value}}`;
891
+ value = `{${value}}`;
892
+ }
772
893
  }
773
894
  else if (name === "datasource" || name === "deletedatasource") {
774
895
  if (value.startsWith("fragment")) {
@@ -784,7 +905,10 @@ class Transpiler {
784
905
  let exp = `${value.substring(5)}`;
785
906
  exp = exp.replace("fragment.Page", "fragment");
786
907
  const isProgressCircleDatavalue = tagName === "wm-progress-circle" && name === "datavalue";
787
- exp = (0, utils_browser_1.modifyExpression)(exp);
908
+ exp = ((_c = context === null || context === void 0 ? void 0 : context.get) === null || _c === void 0 ? void 0 : _c.call(context, "isInsideTableColumn"))
909
+ ? (0, utils_1.transformTableColumnClassExpression)(exp)
910
+ : (0, utils_browser_1.modifyExpression)(exp);
911
+ exp = (0, bind_ex_transformer_1.resolveFormatContext)(exp, context);
788
912
  exp = this.convertStringBooleanTernary(exp);
789
913
  // If expression is empty after transformation, use empty string instead of empty braces
790
914
  if (!exp) {
@@ -890,9 +1014,17 @@ class Transpiler {
890
1014
  transpiler.transformers.set(tagName, transformer);
891
1015
  }
892
1016
  }
1017
+ // Pure property / safe-property / keyed-read chain rooted at `fragment`.
1018
+ // Rejects callee refs that contain intermediate calls (e.g. `fragment.a?.b?.()?.c`),
1019
+ // operators, assignments, whitespace — anything that would change semantics when
1020
+ // evaluated at render time instead of click time.
1021
+ Transpiler.FRAGMENT_CALLEE_REF = /^fragment(?:\??\.[a-zA-Z_$][\w$]*|(?:\?\.)?\[[^\]]*\])*$/;
1022
+ // Callee paths rooted at runtime instance objects (Actions, Variables) whose methods
1023
+ // (invoke, navigate, setData, …) rely on `this` and must not be emitted as detached refs.
1024
+ Transpiler.INSTANCE_BOUND_CALLEE = /(?:\?\.|\.)(?:Actions|Variables)(?:\?\.|\.|\[|$)/;
893
1025
  const transpiler = new Transpiler();
894
1026
  exports.registerTransformer = transpiler.registerTransformer.bind(transpiler);
895
- const transpileMarkup = (markup, isPartOfPrefab, splitCode, variables, preview) => {
1027
+ const transpileMarkup = (markup, isPartOfPrefab, splitCode, variables, preview, insideTableColumn) => {
896
1028
  const parsed = (0, exports.parse)(markup, {
897
1029
  blockTextElements: {},
898
1030
  });
@@ -927,6 +1059,7 @@ const transpileMarkup = (markup, isPartOfPrefab, splitCode, variables, preview)
927
1059
  twoWayBindingVariables: twoWayBindingVariables,
928
1060
  autolayoutCodegen,
929
1061
  preview: preview === true,
1062
+ ...(insideTableColumn ? { isInsideTableColumn: true } : {}),
930
1063
  },
931
1064
  });
932
1065
  // Process all child nodes (including text nodes that come before the main element)
@@ -1014,15 +1147,13 @@ const createExpression = (element, attrName) => {
1014
1147
  displayexpression = displayexpression.replace(/\$item\[fragment.(.*?)\]/g, "$item['$1']");
1015
1148
  displayexpression = displayexpression.replace(/\$item\['(.*?)'\]/g, "_get($item, '$1')");
1016
1149
  displayexpression = displayexpression.replace(/fragment.index/g, "$index");
1017
- if (displayexpression.indexOf("fragment.formatters.") >= 0) {
1018
- displayexpression = displayexpression.replace(new RegExp(bind_ex_transformer_1.FORMAT_CONTEXT, "g"), "$item");
1150
+ if (/formatters/.test(displayexpression)) {
1151
+ displayexpression = displayexpression.split(bind_ex_transformer_1.FORMAT_CONTEXT).join("$item");
1019
1152
  }
1020
1153
  // Transform fragment.name -> $item.name for arrow functions with $item
1021
1154
  displayexpression = displayexpression.replace(/fragment\.([a-zA-Z_$][a-zA-Z0-9_$]*)/g, "$item.$1");
1022
- // Add optional chaining for all property access (e.g., $item.App.appLocale -> $item?.App?.appLocale)
1023
- // Use negative lookbehind to avoid double optional chaining (??)
1024
- displayexpression = displayexpression.replace(/(?<!\?)\.([a-zA-Z_$][a-zA-Z0-9_$]*)/g, "?.$1");
1025
- displayexpression = displayexpression.replace(/([a-zA-Z0-9_$\]])\[/g, "$1?.[");
1155
+ // Add optional chaining while preserving dots inside string literals (e.g. custom.rowCurrencyList)
1156
+ displayexpression = (0, utils_browser_1.addOptionalChaining)(displayexpression);
1026
1157
  const exp = (0, lodash_1.includes)(displayexpression, "(") ? `${displayexpression}` : displayexpression;
1027
1158
  if (displayexpression.indexOf("$index") >= 0) {
1028
1159
  return `{($item, $index, $length) => (${exp})}`;