marko 5.39.34 → 5.39.36
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/runtime/helpers/tags-compat/dom-debug.js +3 -1
- package/dist/runtime/helpers/tags-compat/dom-debug.mjs +2 -1
- package/dist/runtime/helpers/tags-compat/dom.js +3 -1
- package/dist/runtime/helpers/tags-compat/dom.mjs +2 -1
- package/dist/runtime/helpers/tags-compat/html-debug.js +3 -3
- package/dist/runtime/helpers/tags-compat/html-debug.mjs +2 -1
- package/dist/runtime/helpers/tags-compat/html.js +3 -3
- package/dist/runtime/helpers/tags-compat/html.mjs +2 -1
- package/dist/runtime/helpers/tags-compat/runtime-dom.js +22 -0
- package/dist/runtime/helpers/tags-compat/runtime-html.js +10 -1
- package/dist/translator/tag/custom-tag.js +125 -0
- package/dist/translator/text/index[vdom].js +3 -5
- package/dist/translator/util/optimize-vdom-create.js +2 -4
- package/package.json +4 -5
- package/src/runtime/helpers/tags-compat/dom-debug.js +3 -1
- package/src/runtime/helpers/tags-compat/dom-debug.mjs +2 -1
- package/src/runtime/helpers/tags-compat/dom.js +3 -1
- package/src/runtime/helpers/tags-compat/dom.mjs +2 -1
- package/src/runtime/helpers/tags-compat/html-debug.js +3 -3
- package/src/runtime/helpers/tags-compat/html-debug.mjs +2 -1
- package/src/runtime/helpers/tags-compat/html.js +3 -3
- package/src/runtime/helpers/tags-compat/html.mjs +2 -1
- package/src/runtime/helpers/tags-compat/runtime-dom.js +22 -0
- package/src/runtime/helpers/tags-compat/runtime-html.js +10 -1
- package/src/translator/tag/custom-tag.js +125 -0
- package/src/translator/text/index[vdom].js +2 -4
- package/src/translator/util/optimize-vdom-create.js +2 -4
- package/tags-html.d.ts +152 -3801
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
"use strict";const runtimeHtml = require("./runtime-html.js");
|
|
2
|
+
exports.s = runtimeHtml.p(require("@marko/runtime-tags/debug/html").compat);
|
|
3
|
+
exports.f = runtimeHtml.f;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
"use strict";const runtimeHtml = require("./runtime-html.js");
|
|
2
|
+
exports.s = runtimeHtml.p(require("@marko/runtime-tags/html").compat);
|
|
3
|
+
exports.f = runtimeHtml.f;
|
|
@@ -13,7 +13,29 @@ const dynamicTag = require("../dynamic-tag");
|
|
|
13
13
|
const Component = require("../../components/Component");
|
|
14
14
|
const noopRenderer = require("../serialize-noop").aM_;
|
|
15
15
|
|
|
16
|
+
// Bound in `p` so entry files (dom / dom-debug, cjs / esm) just re-export `f`.
|
|
17
|
+
let resumeClassFunction;
|
|
18
|
+
|
|
19
|
+
// Rebuilds a hoisted class handler against whichever component the resumed
|
|
20
|
+
// scope names, so it fires without the parent having to rerender.
|
|
21
|
+
exports.f = (id, factory) => {
|
|
22
|
+
resumeClassFunction(
|
|
23
|
+
id,
|
|
24
|
+
(scope) =>
|
|
25
|
+
function () {
|
|
26
|
+
// Resolved on call: the tags resume runs before `$MC` creates the class
|
|
27
|
+
// component this handler belongs to.
|
|
28
|
+
return factory(
|
|
29
|
+
_n_[scope.m5h] ||
|
|
30
|
+
_n_[scope.m5c] ||
|
|
31
|
+
scope.bs_
|
|
32
|
+
).apply(this, arguments);
|
|
33
|
+
}
|
|
34
|
+
);
|
|
35
|
+
};
|
|
36
|
+
|
|
16
37
|
exports.p = function (domCompat) {
|
|
38
|
+
resumeClassFunction = domCompat.resumeClassFunction;
|
|
17
39
|
dynamicTag.bq_ = function tagsToVdom(
|
|
18
40
|
renderer,
|
|
19
41
|
renderBody,
|
|
@@ -9,7 +9,14 @@ const createRenderer = require("../../components/renderer");
|
|
|
9
9
|
const defaultCreateOut = require("../../createOut");
|
|
10
10
|
const dynamicTag5 = require("../dynamic-tag");
|
|
11
11
|
|
|
12
|
+
// Bound in `p` so entry files (html / html-debug, cjs / esm) just re-export `f`.
|
|
13
|
+
let registerClassFunction;
|
|
14
|
+
|
|
15
|
+
exports.f = (id, fn, component, out) =>
|
|
16
|
+
registerClassFunction(out.global, id, fn, component.id);
|
|
17
|
+
|
|
12
18
|
exports.p = function (htmlCompat) {
|
|
19
|
+
registerClassFunction = htmlCompat.registerClassFunction;
|
|
13
20
|
const writersByGlobal = new WeakMap();
|
|
14
21
|
const boundaryModeByRenderer = new WeakMap();
|
|
15
22
|
const isMarko6 = (fn) => typeof fn !== "function" || htmlCompat.isTagsAPI(fn);
|
|
@@ -144,7 +151,9 @@ exports.p = function (htmlCompat) {
|
|
|
144
151
|
component,
|
|
145
152
|
input,
|
|
146
153
|
writers.tagsAPI,
|
|
147
|
-
!willRerender &&
|
|
154
|
+
!willRerender && (
|
|
155
|
+
hasBridgedClassEvent(input) ||
|
|
156
|
+
htmlCompat.hasPendingClassFunctions(out.global))
|
|
148
157
|
);
|
|
149
158
|
out.ef();
|
|
150
159
|
},
|
|
@@ -7,6 +7,9 @@ var _babelUtils = require("@marko/compiler/babel-utils");
|
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
10
13
|
var _loadImport = require("../util/load-import");
|
|
11
14
|
var _withPreviousLocation = _interopRequireDefault(require("../util/with-previous-location"));
|
|
12
15
|
var _dynamicTag = _interopRequireDefault(require("./dynamic-tag"));
|
|
@@ -26,6 +29,7 @@ function _default(path, isNullable) {
|
|
|
26
29
|
let tagIdentifier;
|
|
27
30
|
|
|
28
31
|
if (node.extra?.featureType === "tags") {
|
|
32
|
+
registerClassHandlerFunctions(path);
|
|
29
33
|
// A dynamic `<${tagName}>` already references the imported template
|
|
30
34
|
// binding directly; only a static tag name needs to be resolved to one.
|
|
31
35
|
if (_compiler.types.isStringLiteral(name)) {
|
|
@@ -131,4 +135,125 @@ function _default(path, isNullable) {
|
|
|
131
135
|
} else {
|
|
132
136
|
path.replaceWith(customTagRenderCall);
|
|
133
137
|
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Hoist direct attribute handlers to a component factory for class→tags resume.
|
|
141
|
+
// Nested functions in object/array attr values are not supported across the boundary.
|
|
142
|
+
function registerClassHandlerFunctions(path) {
|
|
143
|
+
for (const attr of path.get("attributes")) {
|
|
144
|
+
if (!attr.isMarkoAttribute()) continue;
|
|
145
|
+
const valuePath = attr.get("value");
|
|
146
|
+
if (
|
|
147
|
+
!valuePath.isFunctionExpression() &&
|
|
148
|
+
!valuePath.isArrowFunctionExpression())
|
|
149
|
+
{
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
const factory = hoistToFactory(valuePath);
|
|
153
|
+
if (factory) {
|
|
154
|
+
replaceWithResumable(valuePath, factory);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// `input`/`out`/`state`/`$global` only become renderer parameters in `Program.exit`,
|
|
160
|
+
// so at this point they can still look module scoped.
|
|
161
|
+
const RENDER_LOCALS = new Set(["input", "out", "state", "$global"]);
|
|
162
|
+
|
|
163
|
+
// Only the component survives into the browser; anything else the body closes
|
|
164
|
+
// over belongs to a render frame that resume cannot rebuild.
|
|
165
|
+
function hoistToFactory(fnPath) {
|
|
166
|
+
const file = (0, _babelUtils.getFile)();
|
|
167
|
+
const componentId = file._componentInstanceIdentifier;
|
|
168
|
+
if (!componentId) return null;
|
|
169
|
+
|
|
170
|
+
const program = (0, _babelUtils.getProgram)();
|
|
171
|
+
const outer = new Set();
|
|
172
|
+
|
|
173
|
+
for (let scope = fnPath.scope.parent; scope; scope = scope.parent) {
|
|
174
|
+
for (const name in scope.bindings) {
|
|
175
|
+
const binding = scope.bindings[name];
|
|
176
|
+
if (!binding.referencePaths.some((ref) => ref.isDescendant(fnPath))) {
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if (
|
|
181
|
+
name === "component" ||
|
|
182
|
+
name === componentId.name ||
|
|
183
|
+
binding.identifier === componentId)
|
|
184
|
+
{
|
|
185
|
+
outer.add("component");
|
|
186
|
+
} else if (RENDER_LOCALS.has(name) || binding.scope !== program.scope) {
|
|
187
|
+
outer.add(name);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
if (scope === program.scope) break;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
for (const name of outer) {
|
|
194
|
+
if (name !== "component") return null;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const factoryId = program.scope.generateUidIdentifier("marko_class_fn");
|
|
198
|
+
|
|
199
|
+
program.pushContainer("body", [
|
|
200
|
+
_compiler.types.variableDeclaration("const", [
|
|
201
|
+
_compiler.types.variableDeclarator(
|
|
202
|
+
factoryId,
|
|
203
|
+
_compiler.types.arrowFunctionExpression([_compiler.types.cloneNode(componentId)], fnPath.node)
|
|
204
|
+
)]
|
|
205
|
+
)]
|
|
206
|
+
);
|
|
207
|
+
|
|
208
|
+
return factoryId;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function replaceWithResumable(fnPath, factoryId) {
|
|
212
|
+
const file = (0, _babelUtils.getFile)();
|
|
213
|
+
const { markoOpts } = file;
|
|
214
|
+
const isHTML = markoOpts.output === "html";
|
|
215
|
+
const id = _compiler.types.stringLiteral(nextClassFnId());
|
|
216
|
+
const built = _compiler.types.callExpression(_compiler.types.cloneNode(factoryId), [
|
|
217
|
+
_compiler.types.cloneNode(file._componentInstanceIdentifier)]
|
|
218
|
+
);
|
|
219
|
+
let replacement;
|
|
220
|
+
|
|
221
|
+
if (isHTML) {
|
|
222
|
+
replacement = _compiler.types.callExpression(compatHelper(), [
|
|
223
|
+
id,
|
|
224
|
+
built,
|
|
225
|
+
_compiler.types.cloneNode(file._componentInstanceIdentifier),
|
|
226
|
+
_compiler.types.identifier("out")]
|
|
227
|
+
);
|
|
228
|
+
} else {
|
|
229
|
+
// Registered once per module so a resumed reference can rebuild the
|
|
230
|
+
// handler against whichever component instance the scope names.
|
|
231
|
+
(0, _babelUtils.getProgram)().pushContainer("body", [
|
|
232
|
+
_compiler.types.expressionStatement(
|
|
233
|
+
_compiler.types.callExpression(compatHelper(), [id, _compiler.types.cloneNode(factoryId)])
|
|
234
|
+
)]
|
|
235
|
+
);
|
|
236
|
+
replacement = built;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
fnPath.replaceWith(replacement);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function nextClassFnId() {
|
|
243
|
+
const file = (0, _babelUtils.getFile)();
|
|
244
|
+
file._markoClassFnCount = (file._markoClassFnCount || 0) + 1;
|
|
245
|
+
return `${file.metadata.marko.id}/h${file._markoClassFnCount - 1}`;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
function compatHelper() {
|
|
249
|
+
const file = (0, _babelUtils.getFile)();
|
|
250
|
+
const { optimize, modules, output } = file.markoOpts;
|
|
251
|
+
return (0, _babelUtils.importNamed)(
|
|
252
|
+
file,
|
|
253
|
+
`marko/${optimize ? "dist" : "src"}/runtime/helpers/tags-compat/${
|
|
254
|
+
output === "html" ? "html" : "dom"}${
|
|
255
|
+
optimize ? "" : "-debug"}.${modules === "esm" ? "mjs" : "js"}`,
|
|
256
|
+
"f",
|
|
257
|
+
"marko_class_fn"
|
|
258
|
+
);
|
|
134
259
|
}
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
"use strict";exports.__esModule = true;exports.default = _default;var _compiler = require("@marko/compiler");
|
|
2
|
-
var
|
|
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 };}
|
|
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(
|
|
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 };}
|
|
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(
|
|
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.
|
|
3
|
+
"version": "5.39.36",
|
|
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.
|
|
71
|
-
"@marko/runtime-tags": "^6.3.
|
|
70
|
+
"@marko/compiler": "^5.42.2",
|
|
71
|
+
"@marko/runtime-tags": "^6.3.44",
|
|
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.
|
|
87
|
+
"marko": "5.39.36"
|
|
89
88
|
},
|
|
90
89
|
"engines": {
|
|
91
90
|
"node": ">=22"
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
const runtimeHtml = require("./runtime-html.js");
|
|
2
|
+
exports.s = runtimeHtml.p(require("@marko/runtime-tags/debug/html").compat);
|
|
3
|
+
exports.f = runtimeHtml.f;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
const runtimeHtml = require("./runtime-html.js");
|
|
2
|
+
exports.s = runtimeHtml.p(require("@marko/runtime-tags/html").compat);
|
|
3
|
+
exports.f = runtimeHtml.f;
|
|
@@ -13,7 +13,29 @@ const dynamicTag = require("../dynamic-tag");
|
|
|
13
13
|
const Component = require("../../components/Component");
|
|
14
14
|
const noopRenderer = require("../serialize-noop").___noop;
|
|
15
15
|
|
|
16
|
+
// Bound in `p` so entry files (dom / dom-debug, cjs / esm) just re-export `f`.
|
|
17
|
+
let resumeClassFunction;
|
|
18
|
+
|
|
19
|
+
// Rebuilds a hoisted class handler against whichever component the resumed
|
|
20
|
+
// scope names, so it fires without the parent having to rerender.
|
|
21
|
+
exports.f = (id, factory) => {
|
|
22
|
+
resumeClassFunction(
|
|
23
|
+
id,
|
|
24
|
+
(scope) =>
|
|
25
|
+
function () {
|
|
26
|
+
// Resolved on call: the tags resume runs before `$MC` creates the class
|
|
27
|
+
// component this handler belongs to.
|
|
28
|
+
return factory(
|
|
29
|
+
___componentLookup[scope.m5h] ||
|
|
30
|
+
___componentLookup[scope.m5c] ||
|
|
31
|
+
scope.___marko5Component,
|
|
32
|
+
).apply(this, arguments);
|
|
33
|
+
},
|
|
34
|
+
);
|
|
35
|
+
};
|
|
36
|
+
|
|
16
37
|
exports.p = function (domCompat) {
|
|
38
|
+
resumeClassFunction = domCompat.resumeClassFunction;
|
|
17
39
|
dynamicTag.___runtimeCompat = function tagsToVdom(
|
|
18
40
|
renderer,
|
|
19
41
|
renderBody,
|
|
@@ -9,7 +9,14 @@ const createRenderer = require("../../components/renderer");
|
|
|
9
9
|
const defaultCreateOut = require("../../createOut");
|
|
10
10
|
const dynamicTag5 = require("../dynamic-tag");
|
|
11
11
|
|
|
12
|
+
// Bound in `p` so entry files (html / html-debug, cjs / esm) just re-export `f`.
|
|
13
|
+
let registerClassFunction;
|
|
14
|
+
|
|
15
|
+
exports.f = (id, fn, component, out) =>
|
|
16
|
+
registerClassFunction(out.global, id, fn, component.id);
|
|
17
|
+
|
|
12
18
|
exports.p = function (htmlCompat) {
|
|
19
|
+
registerClassFunction = htmlCompat.registerClassFunction;
|
|
13
20
|
const writersByGlobal = new WeakMap();
|
|
14
21
|
const boundaryModeByRenderer = new WeakMap();
|
|
15
22
|
const isMarko6 = (fn) => typeof fn !== "function" || htmlCompat.isTagsAPI(fn);
|
|
@@ -144,7 +151,9 @@ exports.p = function (htmlCompat) {
|
|
|
144
151
|
component,
|
|
145
152
|
input,
|
|
146
153
|
writers.tagsAPI,
|
|
147
|
-
!willRerender &&
|
|
154
|
+
!willRerender &&
|
|
155
|
+
(hasBridgedClassEvent(input) ||
|
|
156
|
+
htmlCompat.hasPendingClassFunctions(out.global)),
|
|
148
157
|
);
|
|
149
158
|
out.ef();
|
|
150
159
|
},
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { types as t } from "@marko/compiler";
|
|
2
2
|
import {
|
|
3
3
|
assertNoArgs,
|
|
4
|
+
getFile,
|
|
5
|
+
getProgram,
|
|
4
6
|
getTagDef,
|
|
5
7
|
importDefault,
|
|
8
|
+
importNamed,
|
|
6
9
|
resolveRelativePath,
|
|
7
10
|
resolveTagImport,
|
|
8
11
|
} from "@marko/compiler/babel-utils";
|
|
@@ -26,6 +29,7 @@ export default function (path, isNullable) {
|
|
|
26
29
|
let tagIdentifier;
|
|
27
30
|
|
|
28
31
|
if (node.extra?.featureType === "tags") {
|
|
32
|
+
registerClassHandlerFunctions(path);
|
|
29
33
|
// A dynamic `<${tagName}>` already references the imported template
|
|
30
34
|
// binding directly; only a static tag name needs to be resolved to one.
|
|
31
35
|
if (t.isStringLiteral(name)) {
|
|
@@ -132,3 +136,124 @@ export default function (path, isNullable) {
|
|
|
132
136
|
path.replaceWith(customTagRenderCall);
|
|
133
137
|
}
|
|
134
138
|
}
|
|
139
|
+
|
|
140
|
+
// Hoist direct attribute handlers to a component factory for class→tags resume.
|
|
141
|
+
// Nested functions in object/array attr values are not supported across the boundary.
|
|
142
|
+
function registerClassHandlerFunctions(path) {
|
|
143
|
+
for (const attr of path.get("attributes")) {
|
|
144
|
+
if (!attr.isMarkoAttribute()) continue;
|
|
145
|
+
const valuePath = attr.get("value");
|
|
146
|
+
if (
|
|
147
|
+
!valuePath.isFunctionExpression() &&
|
|
148
|
+
!valuePath.isArrowFunctionExpression()
|
|
149
|
+
) {
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
const factory = hoistToFactory(valuePath);
|
|
153
|
+
if (factory) {
|
|
154
|
+
replaceWithResumable(valuePath, factory);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// `input`/`out`/`state`/`$global` only become renderer parameters in `Program.exit`,
|
|
160
|
+
// so at this point they can still look module scoped.
|
|
161
|
+
const RENDER_LOCALS = new Set(["input", "out", "state", "$global"]);
|
|
162
|
+
|
|
163
|
+
// Only the component survives into the browser; anything else the body closes
|
|
164
|
+
// over belongs to a render frame that resume cannot rebuild.
|
|
165
|
+
function hoistToFactory(fnPath) {
|
|
166
|
+
const file = getFile();
|
|
167
|
+
const componentId = file._componentInstanceIdentifier;
|
|
168
|
+
if (!componentId) return null;
|
|
169
|
+
|
|
170
|
+
const program = getProgram();
|
|
171
|
+
const outer = new Set();
|
|
172
|
+
|
|
173
|
+
for (let scope = fnPath.scope.parent; scope; scope = scope.parent) {
|
|
174
|
+
for (const name in scope.bindings) {
|
|
175
|
+
const binding = scope.bindings[name];
|
|
176
|
+
if (!binding.referencePaths.some((ref) => ref.isDescendant(fnPath))) {
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if (
|
|
181
|
+
name === "component" ||
|
|
182
|
+
name === componentId.name ||
|
|
183
|
+
binding.identifier === componentId
|
|
184
|
+
) {
|
|
185
|
+
outer.add("component");
|
|
186
|
+
} else if (RENDER_LOCALS.has(name) || binding.scope !== program.scope) {
|
|
187
|
+
outer.add(name);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
if (scope === program.scope) break;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
for (const name of outer) {
|
|
194
|
+
if (name !== "component") return null;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const factoryId = program.scope.generateUidIdentifier("marko_class_fn");
|
|
198
|
+
|
|
199
|
+
program.pushContainer("body", [
|
|
200
|
+
t.variableDeclaration("const", [
|
|
201
|
+
t.variableDeclarator(
|
|
202
|
+
factoryId,
|
|
203
|
+
t.arrowFunctionExpression([t.cloneNode(componentId)], fnPath.node),
|
|
204
|
+
),
|
|
205
|
+
]),
|
|
206
|
+
]);
|
|
207
|
+
|
|
208
|
+
return factoryId;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function replaceWithResumable(fnPath, factoryId) {
|
|
212
|
+
const file = getFile();
|
|
213
|
+
const { markoOpts } = file;
|
|
214
|
+
const isHTML = markoOpts.output === "html";
|
|
215
|
+
const id = t.stringLiteral(nextClassFnId());
|
|
216
|
+
const built = t.callExpression(t.cloneNode(factoryId), [
|
|
217
|
+
t.cloneNode(file._componentInstanceIdentifier),
|
|
218
|
+
]);
|
|
219
|
+
let replacement;
|
|
220
|
+
|
|
221
|
+
if (isHTML) {
|
|
222
|
+
replacement = t.callExpression(compatHelper(), [
|
|
223
|
+
id,
|
|
224
|
+
built,
|
|
225
|
+
t.cloneNode(file._componentInstanceIdentifier),
|
|
226
|
+
t.identifier("out"),
|
|
227
|
+
]);
|
|
228
|
+
} else {
|
|
229
|
+
// Registered once per module so a resumed reference can rebuild the
|
|
230
|
+
// handler against whichever component instance the scope names.
|
|
231
|
+
getProgram().pushContainer("body", [
|
|
232
|
+
t.expressionStatement(
|
|
233
|
+
t.callExpression(compatHelper(), [id, t.cloneNode(factoryId)]),
|
|
234
|
+
),
|
|
235
|
+
]);
|
|
236
|
+
replacement = built;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
fnPath.replaceWith(replacement);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function nextClassFnId() {
|
|
243
|
+
const file = getFile();
|
|
244
|
+
file._markoClassFnCount = (file._markoClassFnCount || 0) + 1;
|
|
245
|
+
return `${file.metadata.marko.id}/h${file._markoClassFnCount - 1}`;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
function compatHelper() {
|
|
249
|
+
const file = getFile();
|
|
250
|
+
const { optimize, modules, output } = file.markoOpts;
|
|
251
|
+
return importNamed(
|
|
252
|
+
file,
|
|
253
|
+
`marko/${optimize ? "dist" : "src"}/runtime/helpers/tags-compat/${
|
|
254
|
+
output === "html" ? "html" : "dom"
|
|
255
|
+
}${optimize ? "" : "-debug"}.${modules === "esm" ? "mjs" : "js"}`,
|
|
256
|
+
"f",
|
|
257
|
+
"marko_class_fn",
|
|
258
|
+
);
|
|
259
|
+
}
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import { types as t } from "@marko/compiler";
|
|
2
|
-
import
|
|
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(
|
|
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
|
|
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(
|
|
30
|
+
[t.stringLiteral(decodeHTML(node.value))],
|
|
33
31
|
);
|
|
34
32
|
},
|
|
35
33
|
MarkoPlaceholder(path, state) {
|