marko 5.39.35 → 5.39.37

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.
@@ -178,6 +178,8 @@ function addTagsEvents(attrs, componentDef, customEvents) {
178
178
  var eventName = event[0];
179
179
  var handler = event[1];
180
180
  var extraArgs = event[3];
181
+ // A Class parent addresses a Tags child by the child's own camelCase prop
182
+ // (`onSetFilter`); a dashed name does not type-check against its `Input`.
181
183
  var prop = "on" + eventName.charAt(0).toUpperCase() + eventName.slice(1);
182
184
 
183
185
  if (IS_SERVER) {
@@ -152,7 +152,7 @@ const analyze = exports.analyze = {
152
152
  const childFile = (0, _babelUtils.loadFileForTag)(tag);
153
153
  if (childFile?.ast.program.extra?.featureType === "tags") {
154
154
  tag.node.extra.featureType = "tags";
155
- (file.path.node.extra ??= {}).needsCompat = true;
155
+ markInteropBoundary(file, tag);
156
156
  }
157
157
  } else if ((0, _babelUtils.isDynamicTag)(tag)) {
158
158
  // A dynamic `<${expr}/>` whose name references an imported Tags API
@@ -169,7 +169,7 @@ const analyze = exports.analyze = {
169
169
  );
170
170
  if (childFile?.ast.program.extra?.featureType === "tags") {
171
171
  (tag.node.extra ??= {}).featureType = "tags";
172
- (file.path.node.extra ??= {}).needsCompat = true;
172
+ markInteropBoundary(file, tag);
173
173
  return true;
174
174
  }
175
175
  }
@@ -702,6 +702,50 @@ function getRuntimeEntryFiles(output, optimize) {
702
702
 
703
703
  }
704
704
 
705
+ /**
706
+ * Records what crosses into a Tags child so the page entry can link the client
707
+ * side of the boundary: anything passed at all is revived through the compat
708
+ * layer, and a direct function attribute is hoisted into this module and
709
+ * registered for resume, so the module itself has to load — a split component's
710
+ * browser file is not enough.
711
+ */
712
+ function markInteropBoundary(file, tag) {
713
+ const extra = file.path.node.extra ??= {};
714
+ extra.needsCompat = true;
715
+
716
+ if (!extra.resumesClassFns) {
717
+ for (const attr of tag.get("attributes")) {
718
+ const value = attr.isMarkoAttribute() && attr.get("value");
719
+ if (
720
+ value && (
721
+ value.isFunctionExpression() || value.isArrowFunctionExpression()))
722
+ {
723
+ extra.resumesClassFns = true;
724
+ break;
725
+ }
726
+ }
727
+ }
728
+
729
+ if (
730
+ tag.node.body.body.length ||
731
+ tag.node.attributeTags.length ||
732
+ tag.node.attributes.some(isRevivedAttr))
733
+ {
734
+ extra.resumesCompat = true;
735
+ }
736
+ }
737
+
738
+ // A literal cannot be a Class renderer or a handler the Tags side revives, so
739
+ // passing one does not pull the compat layer into the page entry.
740
+ function isRevivedAttr(attr) {
741
+ return (
742
+ !_compiler.types.isMarkoAttribute(attr) ||
743
+ !!attr.arguments?.length ||
744
+ !_compiler.types.isLiteral(attr.value) ||
745
+ _compiler.types.isTemplateLiteral(attr.value));
746
+
747
+ }
748
+
705
749
  function isRenderContent({ node }) {
706
750
  return /^Marko/.test(node.type) && !node.static;
707
751
  }
@@ -733,15 +777,25 @@ function getClassHydrationMode(file, visited = new Set()) {
733
777
  // A Tags template records interactivity on its program, not in metadata;
734
778
  // it hydrates itself, so a Class ancestor has to keep the boundary.
735
779
  if (file.ast.program.extra?.isInteractive) {
780
+ file.ast.program.extra.hydratesTags = true;
736
781
  return meta.classHydration = CLASS_HYDRATION_SELF;
737
782
  }
738
783
 
784
+ let mode;
739
785
  for (const tag of meta.tags) {
740
786
  if (tag.endsWith(".marko")) {
741
787
  const childFile = (0, _babelUtils.loadFileForImport)(file, tag);
742
788
  if (childFile && getClassHydrationMode(childFile, visited)) {
743
- return meta.classHydration = CLASS_HYDRATION_DESCENDANT;
789
+ mode = CLASS_HYDRATION_DESCENDANT;
790
+ // A Tags descendant resumes through this boundary, which a Tags
791
+ // ancestor has to keep alive; a Class one hydrates on its own.
792
+ if (childFile.ast.program.extra?.hydratesTags) {
793
+ (file.ast.program.extra ??= {}).hydratesTags = true;
794
+ break;
795
+ }
744
796
  }
745
797
  }
746
798
  }
799
+
800
+ return mode && (meta.classHydration = mode);
747
801
  }
@@ -1,10 +1,8 @@
1
1
  "use strict";exports.__esModule = true;exports.default = _default;var _compiler = require("@marko/compiler");
2
- var _he = _interopRequireDefault(require("he"));
3
-
4
-
2
+ var _babelUtils = require("@marko/compiler/babel-utils");
5
3
 
6
4
  var _vdomOutWrite = _interopRequireDefault(require("../util/vdom-out-write"));
7
- var _withPreviousLocation = _interopRequireDefault(require("../util/with-previous-location"));function _interopRequireDefault(e) {return e && e.__esModule ? e : { default: e };}const { decode } = _he.default;
5
+ var _withPreviousLocation = _interopRequireDefault(require("../util/with-previous-location"));function _interopRequireDefault(e) {return e && e.__esModule ? e : { default: e };}
8
6
 
9
7
  function _default(path) {
10
8
  const { node } = path;
@@ -13,7 +11,7 @@ function _default(path) {
13
11
  (0, _withPreviousLocation.default)(
14
12
  (0, _vdomOutWrite.default)(
15
13
  "t",
16
- _compiler.types.stringLiteral(decode(node.value)),
14
+ _compiler.types.stringLiteral((0, _babelUtils.decodeHTML)(node.value)),
17
15
  path.hub.file._componentInstanceIdentifier
18
16
  ),
19
17
  node
@@ -6,13 +6,11 @@ var _babelUtils = require("@marko/compiler/babel-utils");
6
6
 
7
7
 
8
8
 
9
- var _he = _interopRequireDefault(require("he"));
10
-
11
9
 
12
10
 
13
11
  var _attributes = _interopRequireDefault(require("../tag/native-tag[vdom]/attributes"));
14
12
  var _keyManager = require("./key-manager");
15
- var _vdomOutWrite = _interopRequireDefault(require("./vdom-out-write"));function _interopRequireDefault(e) {return e && e.__esModule ? e : { default: e };}const { decode } = _he.default;
13
+ var _vdomOutWrite = _interopRequireDefault(require("./vdom-out-write"));function _interopRequireDefault(e) {return e && e.__esModule ? e : { default: e };}
16
14
 
17
15
  const skipDirectives = new Set([
18
16
  "key",
@@ -29,7 +27,7 @@ const mergeStaticCreateVisitor = {
29
27
  const { node } = path;
30
28
  state.currentRoot = _compiler.types.callExpression(
31
29
  _compiler.types.memberExpression(state.currentRoot, _compiler.types.identifier("t")),
32
- [_compiler.types.stringLiteral(decode(node.value))]
30
+ [_compiler.types.stringLiteral((0, _babelUtils.decodeHTML)(node.value))]
33
31
  );
34
32
  },
35
33
  MarkoPlaceholder(path, state) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "marko",
3
- "version": "5.39.35",
3
+ "version": "5.39.37",
4
4
  "private": false,
5
5
  "description": "UI Components + streaming, async, high performance, HTML templating for Node.js and the browser.",
6
6
  "keywords": [
@@ -67,15 +67,14 @@
67
67
  },
68
68
  "types": "index.d.ts",
69
69
  "dependencies": {
70
- "@marko/compiler": "^5.42.1",
71
- "@marko/runtime-tags": "^6.3.41",
70
+ "@marko/compiler": "^5.42.3",
71
+ "@marko/runtime-tags": "^6.3.45",
72
72
  "app-module-path": "^2.2.0",
73
73
  "argly": "^1.2.0",
74
74
  "browser-refresh-client": "1.1.4",
75
75
  "complain": "^1.6.1",
76
76
  "csstype": "^3.2.3",
77
77
  "events-light": "^1.0.5",
78
- "he": "^1.2.0",
79
78
  "listener-tracker": "^2.0.0",
80
79
  "magic-string": "^0.30.21",
81
80
  "minimatch": "^10.2.5",
@@ -85,7 +84,7 @@
85
84
  "warp10": "^2.1.0"
86
85
  },
87
86
  "devDependencies": {
88
- "marko": "5.39.35"
87
+ "marko": "5.39.37"
89
88
  },
90
89
  "engines": {
91
90
  "node": ">=22"
@@ -178,6 +178,8 @@ function addTagsEvents(attrs, componentDef, customEvents) {
178
178
  var eventName = event[0];
179
179
  var handler = event[1];
180
180
  var extraArgs = event[3];
181
+ // A Class parent addresses a Tags child by the child's own camelCase prop
182
+ // (`onSetFilter`); a dashed name does not type-check against its `Input`.
181
183
  var prop = "on" + eventName.charAt(0).toUpperCase() + eventName.slice(1);
182
184
 
183
185
  if (IS_SERVER) {
@@ -152,7 +152,7 @@ export const analyze = {
152
152
  const childFile = loadFileForTag(tag);
153
153
  if (childFile?.ast.program.extra?.featureType === "tags") {
154
154
  tag.node.extra.featureType = "tags";
155
- (file.path.node.extra ??= {}).needsCompat = true;
155
+ markInteropBoundary(file, tag);
156
156
  }
157
157
  } else if (isDynamicTag(tag)) {
158
158
  // A dynamic `<${expr}/>` whose name references an imported Tags API
@@ -169,7 +169,7 @@ export const analyze = {
169
169
  );
170
170
  if (childFile?.ast.program.extra?.featureType === "tags") {
171
171
  (tag.node.extra ??= {}).featureType = "tags";
172
- (file.path.node.extra ??= {}).needsCompat = true;
172
+ markInteropBoundary(file, tag);
173
173
  return true;
174
174
  }
175
175
  }
@@ -702,6 +702,50 @@ export function getRuntimeEntryFiles(output, optimize) {
702
702
  ];
703
703
  }
704
704
 
705
+ /**
706
+ * Records what crosses into a Tags child so the page entry can link the client
707
+ * side of the boundary: anything passed at all is revived through the compat
708
+ * layer, and a direct function attribute is hoisted into this module and
709
+ * registered for resume, so the module itself has to load — a split component's
710
+ * browser file is not enough.
711
+ */
712
+ function markInteropBoundary(file, tag) {
713
+ const extra = (file.path.node.extra ??= {});
714
+ extra.needsCompat = true;
715
+
716
+ if (!extra.resumesClassFns) {
717
+ for (const attr of tag.get("attributes")) {
718
+ const value = attr.isMarkoAttribute() && attr.get("value");
719
+ if (
720
+ value &&
721
+ (value.isFunctionExpression() || value.isArrowFunctionExpression())
722
+ ) {
723
+ extra.resumesClassFns = true;
724
+ break;
725
+ }
726
+ }
727
+ }
728
+
729
+ if (
730
+ tag.node.body.body.length ||
731
+ tag.node.attributeTags.length ||
732
+ tag.node.attributes.some(isRevivedAttr)
733
+ ) {
734
+ extra.resumesCompat = true;
735
+ }
736
+ }
737
+
738
+ // A literal cannot be a Class renderer or a handler the Tags side revives, so
739
+ // passing one does not pull the compat layer into the page entry.
740
+ function isRevivedAttr(attr) {
741
+ return (
742
+ !t.isMarkoAttribute(attr) ||
743
+ !!attr.arguments?.length ||
744
+ !t.isLiteral(attr.value) ||
745
+ t.isTemplateLiteral(attr.value)
746
+ );
747
+ }
748
+
705
749
  function isRenderContent({ node }) {
706
750
  return /^Marko/.test(node.type) && !node.static;
707
751
  }
@@ -733,15 +777,25 @@ function getClassHydrationMode(file, visited = new Set()) {
733
777
  // A Tags template records interactivity on its program, not in metadata;
734
778
  // it hydrates itself, so a Class ancestor has to keep the boundary.
735
779
  if (file.ast.program.extra?.isInteractive) {
780
+ file.ast.program.extra.hydratesTags = true;
736
781
  return (meta.classHydration = CLASS_HYDRATION_SELF);
737
782
  }
738
783
 
784
+ let mode;
739
785
  for (const tag of meta.tags) {
740
786
  if (tag.endsWith(".marko")) {
741
787
  const childFile = loadFileForImport(file, tag);
742
788
  if (childFile && getClassHydrationMode(childFile, visited)) {
743
- return (meta.classHydration = CLASS_HYDRATION_DESCENDANT);
789
+ mode = CLASS_HYDRATION_DESCENDANT;
790
+ // A Tags descendant resumes through this boundary, which a Tags
791
+ // ancestor has to keep alive; a Class one hydrates on its own.
792
+ if (childFile.ast.program.extra?.hydratesTags) {
793
+ (file.ast.program.extra ??= {}).hydratesTags = true;
794
+ break;
795
+ }
744
796
  }
745
797
  }
746
798
  }
799
+
800
+ return mode && (meta.classHydration = mode);
747
801
  }
@@ -1,7 +1,5 @@
1
1
  import { types as t } from "@marko/compiler";
2
- import he from "he";
3
-
4
- const { decode } = he;
2
+ import { decodeHTML } from "@marko/compiler/babel-utils";
5
3
 
6
4
  import write from "../util/vdom-out-write";
7
5
  import withPreviousLocation from "../util/with-previous-location";
@@ -13,7 +11,7 @@ export default function (path) {
13
11
  withPreviousLocation(
14
12
  write(
15
13
  "t",
16
- t.stringLiteral(decode(node.value)),
14
+ t.stringLiteral(decodeHTML(node.value)),
17
15
  path.hub.file._componentInstanceIdentifier,
18
16
  ),
19
17
  node,
@@ -6,9 +6,7 @@ import {
6
6
  isLoopTag,
7
7
  isNativeTag,
8
8
  } from "@marko/compiler/babel-utils";
9
- import he from "he";
10
-
11
- const { decode } = he;
9
+ import { decodeHTML } from "@marko/compiler/babel-utils";
12
10
 
13
11
  import translateAttributes from "../tag/native-tag[vdom]/attributes";
14
12
  import { getKeyManager, hasUserKey } from "./key-manager";
@@ -29,7 +27,7 @@ const mergeStaticCreateVisitor = {
29
27
  const { node } = path;
30
28
  state.currentRoot = t.callExpression(
31
29
  t.memberExpression(state.currentRoot, t.identifier("t")),
32
- [t.stringLiteral(decode(node.value))],
30
+ [t.stringLiteral(decodeHTML(node.value))],
33
31
  );
34
32
  },
35
33
  MarkoPlaceholder(path, state) {