octane 0.6.2 → 0.6.3
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/cjs/dom-binding-handoff.cjs +2 -1
- package/dist/cjs/dom-binding-protocol.cjs +4 -3
- package/dist/cjs/dom-binding-styles.cjs +3 -2
- package/dist/cjs/dom-bindings.cjs +24 -23
- package/dist/cjs/error-codes.client.generated.cjs +2 -1
- package/dist/cjs/error-codes.server.generated.cjs +2 -1
- package/dist/cjs/hydration/event-capture.cjs +2 -1
- package/dist/cjs/independent-hydration-protocol.cjs +3 -2
- package/dist/cjs/runtime.cjs +169 -155
- package/dist/cjs/runtime.server.cjs +40 -34
- package/dist/cjs/signals/control-binding.cjs +7 -6
- package/dist/cjs/signals/derived-facade.cjs +2 -1
- package/dist/cjs/signals/document-owner.cjs +4 -3
- package/dist/cjs/signals/facade.cjs +10 -9
- package/dist/cjs/signals/graph.cjs +5 -4
- package/dist/cjs/signals/native-read-client.cjs +4 -3
- package/dist/cjs/signals/owner-context.cjs +4 -3
- package/dist/cjs/signals/query-attempt-observer.cjs +2 -1
- package/dist/cjs/signals/query-facade.cjs +2 -1
- package/dist/cjs/signals/scalar-computations.cjs +2 -1
- package/dist/cjs/signals/transition-action.cjs +10 -9
- package/dist/cjs/signals/transition-candidate.cjs +2 -1
- package/dist/cjs/version.cjs +1 -1
- package/dist/compiler/compile.js +380 -12
- package/dist/node/aria-diagnostics.js +92 -0
- package/dist/node/behavior-form-submissions.js +228 -0
- package/dist/node/behavior-root-types.js +0 -0
- package/dist/node/behavior-root.js +746 -0
- package/dist/node/class-names.js +25 -0
- package/dist/node/compatibility.js +10 -0
- package/dist/node/component-flags.js +23 -0
- package/dist/node/constants.js +113 -0
- package/dist/node/context-epoch.js +13 -0
- package/dist/node/context-identity.js +46 -0
- package/dist/node/css.js +80 -0
- package/dist/node/data-encoding.js +134 -0
- package/dist/node/devtools-hook.js +229 -0
- package/dist/node/dom-binding-claims.js +4 -0
- package/dist/node/dom-binding-classes.js +152 -0
- package/dist/node/dom-binding-controls.js +6 -0
- package/dist/node/dom-binding-handoff.js +77 -0
- package/dist/node/dom-binding-program.js +1617 -0
- package/dist/node/dom-binding-projections.js +204 -0
- package/dist/node/dom-binding-protocol.js +130 -0
- package/dist/node/dom-binding-signals.js +135 -0
- package/dist/node/dom-binding-styles.js +280 -0
- package/dist/node/dom-bindings.js +1087 -0
- package/dist/node/dom-focused-move.js +46 -0
- package/dist/node/dom-stage.js +878 -0
- package/dist/node/dom-tables.js +382 -0
- package/dist/node/error-codes.client.generated.js +1066 -0
- package/dist/node/error-codes.server.generated.js +736 -0
- package/dist/node/error-message.js +27 -0
- package/dist/node/event-names.js +15 -0
- package/dist/node/form-diagnostics.js +96 -0
- package/dist/node/form-submission.js +43 -0
- package/dist/node/has-own.js +4 -0
- package/dist/node/head-ownership.js +31 -0
- package/dist/node/hook-slot-cache.js +91 -0
- package/dist/node/host-property-diagnostics.js +189 -0
- package/dist/node/html-tree-validation.js +193 -0
- package/dist/node/hydration/condition.js +15 -0
- package/dist/node/hydration/control-capture.js +237 -0
- package/dist/node/hydration/document-lifecycle.js +89 -0
- package/dist/node/hydration/event-capture.js +362 -0
- package/dist/node/hydration/idle.js +23 -0
- package/dist/node/hydration/independent-island.js +317 -0
- package/dist/node/hydration/index.js +74 -0
- package/dist/node/hydration/interaction-config.js +61 -0
- package/dist/node/hydration/interaction.js +35 -0
- package/dist/node/hydration/load.js +15 -0
- package/dist/node/hydration/media.js +33 -0
- package/dist/node/hydration/native-intent.js +68 -0
- package/dist/node/hydration/never.js +12 -0
- package/dist/node/hydration/stream-delivery.js +345 -0
- package/dist/node/hydration/stream-receiver.js +190 -0
- package/dist/node/hydration/stream-result-receiver.js +276 -0
- package/dist/node/hydration/streamed-signals.js +186 -0
- package/dist/node/hydration/types.js +0 -0
- package/dist/node/hydration/visible.js +69 -0
- package/dist/node/hydration-markers.js +44 -0
- package/dist/node/independent-hydration-protocol.js +91 -0
- package/dist/node/index.js +461 -0
- package/dist/node/internal/client.js +7 -0
- package/dist/node/internal/context.js +5 -0
- package/dist/node/internal/server.js +5 -0
- package/dist/node/internal/signal-read.js +4 -0
- package/dist/node/method-dep.js +25 -0
- package/dist/node/profiling.js +432 -0
- package/dist/node/public-types.js +0 -0
- package/dist/node/react/fiber-adapter.js +57 -0
- package/dist/node/react/index.js +397 -0
- package/dist/node/react/react-compat-envelope.js +78 -0
- package/dist/node/react/react-compat-server.js +129 -0
- package/dist/node/react/react-compat-shared.js +104 -0
- package/dist/node/react/react-compat.js +223 -0
- package/dist/node/react/server.js +81 -0
- package/dist/node/react/shared.js +75 -0
- package/dist/node/renderer-bridge.js +35 -0
- package/dist/node/resize-observer.js +105 -0
- package/dist/node/resource-hint-diagnostics.js +67 -0
- package/dist/node/runtime-tags.js +22 -0
- package/dist/node/runtime.js +28881 -0
- package/dist/node/runtime.server.js +8016 -0
- package/dist/node/sanitize-url.js +34 -0
- package/dist/node/server/early-signals.js +54 -0
- package/dist/node/server/index.js +336 -0
- package/dist/node/server/rpc-batch.js +129 -0
- package/dist/node/server/rpc-stream.js +125 -0
- package/dist/node/server/rpc.js +48 -0
- package/dist/node/server/signal-query-observation.js +134 -0
- package/dist/node/server/streamed-region.js +31 -0
- package/dist/node/server/streamed-signals.js +557 -0
- package/dist/node/server-call.js +75 -0
- package/dist/node/server-rpc-batch-client.js +119 -0
- package/dist/node/server-rpc-client.js +108 -0
- package/dist/node/server-rpc-protocol.js +109 -0
- package/dist/node/server-rpc-stream-client.js +98 -0
- package/dist/node/shared-value-helpers.js +40 -0
- package/dist/node/signals/actions.js +463 -0
- package/dist/node/signals/client.js +22 -0
- package/dist/node/signals/computations.js +452 -0
- package/dist/node/signals/control-binding.js +388 -0
- package/dist/node/signals/control-handoff.js +12 -0
- package/dist/node/signals/derived-facade.js +25 -0
- package/dist/node/signals/document-owner.js +48 -0
- package/dist/node/signals/early-values.js +124 -0
- package/dist/node/signals/encoding.js +6 -0
- package/dist/node/signals/engine.js +668 -0
- package/dist/node/signals/errors.js +54 -0
- package/dist/node/signals/facade.js +441 -0
- package/dist/node/signals/graph.js +817 -0
- package/dist/node/signals/handle-protocol.js +11 -0
- package/dist/node/signals/index.js +87 -0
- package/dist/node/signals/native-read-client.js +319 -0
- package/dist/node/signals/native-read-collector.js +132 -0
- package/dist/node/signals/native-read-events.js +45 -0
- package/dist/node/signals/native-read-inspection.js +20 -0
- package/dist/node/signals/native-read-retry.js +30 -0
- package/dist/node/signals/native-read-seeds.js +243 -0
- package/dist/node/signals/native-read-server.js +99 -0
- package/dist/node/signals/owner-context.js +88 -0
- package/dist/node/signals/query-attempt-observer.js +42 -0
- package/dist/node/signals/query-facade.js +41 -0
- package/dist/node/signals/read-protocol.js +125 -0
- package/dist/node/signals/requests.js +716 -0
- package/dist/node/signals/scalar-computations.js +57 -0
- package/dist/node/signals/scope-streams.js +147 -0
- package/dist/node/signals/server.js +22 -0
- package/dist/node/signals/transition-action.js +555 -0
- package/dist/node/signals/transition-candidate.js +101 -0
- package/dist/node/signals/transition-coordinator.js +255 -0
- package/dist/node/signals/transition-state.js +82 -0
- package/dist/node/signals/types.js +20 -0
- package/dist/node/static/index.js +10 -0
- package/dist/node/stream-protocol.js +114 -0
- package/dist/node/streamed-signals-protocol.js +130 -0
- package/dist/node/style-values.js +96 -0
- package/dist/node/sub-slot.js +35 -0
- package/dist/node/testing.js +14 -0
- package/dist/node/trusted-html.js +6 -0
- package/dist/node/tsrx-iterable.js +5 -0
- package/dist/node/tsrx-spread.js +10 -0
- package/dist/node/universal-core.js +10010 -0
- package/dist/node/universal-dom-boundary.js +237 -0
- package/dist/node/universal-native.js +28 -0
- package/dist/node/universal.js +17 -0
- package/dist/node/version.js +4 -0
- package/dist/runtime.d.ts +18 -0
- package/dist/runtime.js +13 -2
- package/dist/runtime.server.d.ts +7 -0
- package/dist/runtime.server.js +4 -0
- package/dist/version.js +1 -1
- package/package.json +62 -1
|
@@ -27,6 +27,7 @@ var import_facade = require("./facade.cjs");
|
|
|
27
27
|
var import_owner_context = require("./owner-context.cjs");
|
|
28
28
|
var import_requests = require("./requests.cjs");
|
|
29
29
|
var import_types = require("./types.cjs");
|
|
30
|
+
const __octaneDev = process.env.NODE_ENV !== "production";
|
|
30
31
|
function __octaneNoArgError(code) {
|
|
31
32
|
return "Minified Octane error #" + code + "; visit https://octanejs.dev/errors/" + code + " for the full message or use a development build for full errors and additional helpful warnings.";
|
|
32
33
|
}
|
|
@@ -43,7 +44,7 @@ class QueryDescriptor extends import_facade.Descriptor {
|
|
|
43
44
|
}
|
|
44
45
|
function __queryAt(site, select, load, options) {
|
|
45
46
|
if (typeof select !== "function" || typeof load !== "function") {
|
|
46
|
-
throw new TypeError(
|
|
47
|
+
throw new TypeError(__octaneDev ? "query$ requires selector and loader functions." : __octaneNoArgError(193));
|
|
47
48
|
}
|
|
48
49
|
const explicit = (0, import_facade.signalOptionsKey)(options);
|
|
49
50
|
site ??= explicit;
|
|
@@ -23,6 +23,7 @@ __export(scalar_computations_exports, {
|
|
|
23
23
|
module.exports = __toCommonJS(scalar_computations_exports);
|
|
24
24
|
var import_engine = require("./engine.cjs");
|
|
25
25
|
var import_graph = require("./graph.cjs");
|
|
26
|
+
const __octaneDev = process.env.NODE_ENV !== "production";
|
|
26
27
|
function __octaneNoArgError(code) {
|
|
27
28
|
return "Minified Octane error #" + code + "; visit https://octanejs.dev/errors/" + code + " for the full message or use a development build for full errors and additional helpful warnings.";
|
|
28
29
|
}
|
|
@@ -53,7 +54,7 @@ class ScalarBinding {
|
|
|
53
54
|
compute;
|
|
54
55
|
forkCandidate(target) {
|
|
55
56
|
if (this.frozen || this.owner.readBarrier || !this.compute) {
|
|
56
|
-
throw new import_graph.CandidateUnsupportedError(
|
|
57
|
+
throw new import_graph.CandidateUnsupportedError(__octaneDev ? "Frozen scalar candidates are not supported." : __octaneNoArgError(205));
|
|
57
58
|
}
|
|
58
59
|
target.compute = this.node.compute;
|
|
59
60
|
}
|
|
@@ -25,6 +25,7 @@ module.exports = __toCommonJS(transition_action_exports);
|
|
|
25
25
|
var import_errors = require("./errors.cjs");
|
|
26
26
|
var import_read_protocol = require("./read-protocol.cjs");
|
|
27
27
|
var import_transition_state = require("./transition-state.cjs");
|
|
28
|
+
const __octaneDev = process.env.NODE_ENV !== "production";
|
|
28
29
|
function __octaneNoArgError(code) {
|
|
29
30
|
return "Minified Octane error #" + code + "; visit https://octanejs.dev/errors/" + code + " for the full message or use a development build for full errors and additional helpful warnings.";
|
|
30
31
|
}
|
|
@@ -70,9 +71,9 @@ class SignalActionFrame {
|
|
|
70
71
|
demand;
|
|
71
72
|
run(callback) {
|
|
72
73
|
if (!this.active)
|
|
73
|
-
throw new TypeError(
|
|
74
|
+
throw new TypeError(__octaneDev ? "The signal candidate has retired." : __octaneNoArgError(203));
|
|
74
75
|
if (import_transition_state.activeCandidate && import_transition_state.activeCandidate !== this) {
|
|
75
|
-
throw new import_transition_state.CandidateUnsupportedError(
|
|
76
|
+
throw new import_transition_state.CandidateUnsupportedError(__octaneDev ? "Nested signal candidates are not supported." : __octaneNoArgError(206));
|
|
76
77
|
}
|
|
77
78
|
const previous = (0, import_transition_state.swapActiveSignalCandidate)(this);
|
|
78
79
|
try {
|
|
@@ -83,7 +84,7 @@ class SignalActionFrame {
|
|
|
83
84
|
}
|
|
84
85
|
resolve(node) {
|
|
85
86
|
if (!this.active)
|
|
86
|
-
throw new TypeError(
|
|
87
|
+
throw new TypeError(__octaneDev ? "The signal candidate has retired." : __octaneNoArgError(203));
|
|
87
88
|
const original = this.originals?.get(node);
|
|
88
89
|
if (original) {
|
|
89
90
|
this.demand?.add(original);
|
|
@@ -94,7 +95,7 @@ class SignalActionFrame {
|
|
|
94
95
|
if (existing)
|
|
95
96
|
return existing.target;
|
|
96
97
|
if (import_transition_state.candidateGraph.historical() || node.owner.readBarrier || !node.owner.forkCandidate) {
|
|
97
|
-
throw new import_transition_state.CandidateUnsupportedError(
|
|
98
|
+
throw new import_transition_state.CandidateUnsupportedError(__octaneDev ? "Only live candidate-capable owners are supported." : __octaneNoArgError(207));
|
|
98
99
|
}
|
|
99
100
|
import_transition_state.candidateGraph.assertAlive(node.owner);
|
|
100
101
|
this.invalidatePreparation();
|
|
@@ -130,7 +131,7 @@ class SignalActionFrame {
|
|
|
130
131
|
}
|
|
131
132
|
write(node, value) {
|
|
132
133
|
if (!this.validate())
|
|
133
|
-
throw new TypeError(
|
|
134
|
+
throw new TypeError(__octaneDev ? "Rebase the signal candidate before writing." : __octaneNoArgError(208));
|
|
134
135
|
const target = this.resolve(node);
|
|
135
136
|
const current = import_transition_state.candidateGraph.strictValue(import_transition_state.candidateGraph.refreshNode(target), node.key);
|
|
136
137
|
let previous = current;
|
|
@@ -175,7 +176,7 @@ class SignalActionFrame {
|
|
|
175
176
|
/** Only observed candidates allocate forwarding sources; ordinary reads keep their identity. */
|
|
176
177
|
nativeSource(target, read, source) {
|
|
177
178
|
if (!nativeExtension)
|
|
178
|
-
throw new import_transition_state.CandidateUnsupportedError(
|
|
179
|
+
throw new import_transition_state.CandidateUnsupportedError(__octaneDev ? "Native signal presentation is not installed." : __octaneNoArgError(209));
|
|
179
180
|
return nativeExtension.source(this.entries.get(this.originals.get(target)), read, source);
|
|
180
181
|
}
|
|
181
182
|
validate() {
|
|
@@ -259,7 +260,7 @@ class SignalActionFrame {
|
|
|
259
260
|
/** Urgent writes win their own cells without restarting unaffected producer leases. */
|
|
260
261
|
rebase() {
|
|
261
262
|
if (!this.active)
|
|
262
|
-
throw new TypeError(
|
|
263
|
+
throw new TypeError(__octaneDev ? "The signal candidate has retired." : __octaneNoArgError(203));
|
|
263
264
|
const hadWrites = this.hasWrites();
|
|
264
265
|
this.generation++;
|
|
265
266
|
this.invalidatePreparation();
|
|
@@ -267,7 +268,7 @@ class SignalActionFrame {
|
|
|
267
268
|
for (const entry of this.entries?.values() ?? []) {
|
|
268
269
|
import_transition_state.candidateGraph.assertAlive(entry.node.owner);
|
|
269
270
|
if (entry.epoch !== entry.node.owner.epoch || entry.node.owner.readBarrier) {
|
|
270
|
-
throw new TypeError(
|
|
271
|
+
throw new TypeError(__octaneDev ? "The candidate owner changed lifetime." : __octaneNoArgError(210));
|
|
271
272
|
}
|
|
272
273
|
const operations = entry.urgentOperations;
|
|
273
274
|
if (!entry.withdrawn && !operations && entry.revision === entry.node.revision)
|
|
@@ -417,7 +418,7 @@ class SignalActionFrame {
|
|
|
417
418
|
for (let link = target.deps; link; link = link.nextDep) {
|
|
418
419
|
const original = this.originals.get(link.dep);
|
|
419
420
|
if (!original)
|
|
420
|
-
throw new TypeError(
|
|
421
|
+
throw new TypeError(__octaneDev ? "Candidate dependency escaped its frame." : __octaneNoArgError(211));
|
|
421
422
|
import_transition_state.candidateGraph.link(original, node);
|
|
422
423
|
}
|
|
423
424
|
const currentChanged = node.state?.snapshot !== state.snapshot || !import_transition_state.candidateGraph.sameState(node.state, state);
|
|
@@ -23,6 +23,7 @@ __export(transition_candidate_exports, {
|
|
|
23
23
|
module.exports = __toCommonJS(transition_candidate_exports);
|
|
24
24
|
var import_transition_state = require("./transition-state.cjs");
|
|
25
25
|
var import_transition_action = require("./transition-action.cjs");
|
|
26
|
+
const __octaneDev = process.env.NODE_ENV !== "production";
|
|
26
27
|
function __octaneNoArgError(code) {
|
|
27
28
|
return "Minified Octane error #" + code + "; visit https://octanejs.dev/errors/" + code + " for the full message or use a development build for full errors and additional helpful warnings.";
|
|
28
29
|
}
|
|
@@ -36,7 +37,7 @@ function createNativeReadCandidateSource(candidate) {
|
|
|
36
37
|
getVersion: () => target === void 0 ? NaN : !accepted ? target.getVersion() : target.getVersion() === canonicalVersion ? acceptedVersion : NaN,
|
|
37
38
|
subscribe(notify) {
|
|
38
39
|
if (target === void 0)
|
|
39
|
-
throw new TypeError(
|
|
40
|
+
throw new TypeError(__octaneDev ? "The native read candidate has retired." : __octaneNoArgError(212));
|
|
40
41
|
const subscription = { notify, dispose: target.subscribe(notify) };
|
|
41
42
|
subscriptions.add(subscription);
|
|
42
43
|
return () => {
|
package/dist/cjs/version.cjs
CHANGED
|
@@ -21,7 +21,7 @@ __export(version_exports, {
|
|
|
21
21
|
version: () => version
|
|
22
22
|
});
|
|
23
23
|
module.exports = __toCommonJS(version_exports);
|
|
24
|
-
const version = "0.6.
|
|
24
|
+
const version = "0.6.3";
|
|
25
25
|
// Annotate the CommonJS export names for ESM import in node:
|
|
26
26
|
0 && (module.exports = {
|
|
27
27
|
version
|
package/dist/compiler/compile.js
CHANGED
|
@@ -1452,6 +1452,8 @@ const INTERNAL_CLIENT_RUNTIME_HELPERS = new Set([
|
|
|
1452
1452
|
'enableSignalBindings',
|
|
1453
1453
|
'createElementAt',
|
|
1454
1454
|
'createElementFromConfig',
|
|
1455
|
+
'isRenderCall',
|
|
1456
|
+
'deferRecord',
|
|
1455
1457
|
'bindSignalText',
|
|
1456
1458
|
'bindSignalChild',
|
|
1457
1459
|
'bindSignalAttribute',
|
|
@@ -1491,6 +1493,7 @@ const INTERNAL_SERVER_RUNTIME_HELPERS = new Set([
|
|
|
1491
1493
|
'enableServerSignalBindings',
|
|
1492
1494
|
'createElementAt',
|
|
1493
1495
|
'createElementFromConfig',
|
|
1496
|
+
'isRenderCall',
|
|
1494
1497
|
'ssrSignalValue',
|
|
1495
1498
|
'ssrSignalControlValue',
|
|
1496
1499
|
'ssrSignalControlAttrs',
|
|
@@ -12087,6 +12090,11 @@ function compileServerComponent(node, ctx) {
|
|
|
12087
12090
|
const beforeCss = ctx.cssInjections.length;
|
|
12088
12091
|
const scoping = applyStyleScopes(node, ctx);
|
|
12089
12092
|
node = scoping.node;
|
|
12093
|
+
// A plain return-JSX declaration can also be called directly; its returned
|
|
12094
|
+
// JSX then needs the same deferred value the client emits.
|
|
12095
|
+
if (node.body?.type === 'BlockStatement' && !node._octaneBindingView) {
|
|
12096
|
+
node = { ...node, _octaneDirectCallReturn: true };
|
|
12097
|
+
}
|
|
12090
12098
|
const cssHash = scoping.cssHash;
|
|
12091
12099
|
const cssEntries = [...ctx.moduleCssInjections, ...ctx.cssInjections.slice(beforeCss)].sort(
|
|
12092
12100
|
(a, b) => a.order - b.order,
|
|
@@ -12280,6 +12288,7 @@ function ssrCompileBodyWithMapTemps(
|
|
|
12280
12288
|
|
|
12281
12289
|
let statements;
|
|
12282
12290
|
let jsxNodes;
|
|
12291
|
+
let directCallRoot = null;
|
|
12283
12292
|
if (node.body && node.body.type === 'JSXCodeBlock') {
|
|
12284
12293
|
statements = returnedOutput
|
|
12285
12294
|
? (node.body.body || []).map(normalizeOwnRenderableReturns)
|
|
@@ -12298,6 +12307,9 @@ function ssrCompileBodyWithMapTemps(
|
|
|
12298
12307
|
jsxNodes = [];
|
|
12299
12308
|
for (const child of bodyRewritten) {
|
|
12300
12309
|
if (child.type === 'ReturnStatement' && child.argument && isJsxNode(child.argument)) {
|
|
12310
|
+
if (directCallRoot === null && node._octaneDirectCallReturn === true) {
|
|
12311
|
+
directCallRoot = child.argument;
|
|
12312
|
+
}
|
|
12301
12313
|
// return-JSX form: the returned host element (+ its directive children) is
|
|
12302
12314
|
// the render output — route it to jsxNodes so it flows through ssrEmitNode
|
|
12303
12315
|
// (byte-identical SSR to the `@{}` form), not printed as `return <jsx>`.
|
|
@@ -12425,6 +12437,53 @@ function ssrCompileBodyWithMapTemps(
|
|
|
12425
12437
|
ctx._returnedFragmentTemplate = prevReturnedFragmentTemplate;
|
|
12426
12438
|
ctx._tsxValuePos = prevValuePos;
|
|
12427
12439
|
ctx._valueDirectiveLowering = prevValueDirectiveLowering;
|
|
12440
|
+
// Mirrors compileReturnJsxFunction: a direct call defers the record that a
|
|
12441
|
+
// body call renders now. Its fragment sub is declared only in that branch, and
|
|
12442
|
+
// it is lowered after the body template so body-call output is unchanged.
|
|
12443
|
+
let directCall = null;
|
|
12444
|
+
const directCallKind = directCallRoot === null ? null : directCallReturnKind(directCallRoot, ctx);
|
|
12445
|
+
if (directCallKind === 'value') {
|
|
12446
|
+
// Directives in the returned value fold into helpers owned by the direct
|
|
12447
|
+
// call, so a body call never declares them.
|
|
12448
|
+
const subs = [];
|
|
12449
|
+
const previousLowering = ctx._valueDirectiveLowering;
|
|
12450
|
+
ctx._valueDirectiveLowering = serverValueDirectiveFold(ctx, name, subs, cssHash);
|
|
12451
|
+
try {
|
|
12452
|
+
const returned = rewriteHookCalls(b.return(directCallRoot), ctx, name, localSetupSlots);
|
|
12453
|
+
directCall = { subs, value: rewriteJsxValues(returned.argument, ctx) };
|
|
12454
|
+
} finally {
|
|
12455
|
+
ctx._valueDirectiveLowering = previousLowering;
|
|
12456
|
+
}
|
|
12457
|
+
} else if (directCallKind === 'fragment') {
|
|
12458
|
+
const subs = [];
|
|
12459
|
+
const record = serverValueDirectiveFold(
|
|
12460
|
+
ctx,
|
|
12461
|
+
name,
|
|
12462
|
+
subs,
|
|
12463
|
+
cssHash,
|
|
12464
|
+
false,
|
|
12465
|
+
'html',
|
|
12466
|
+
)(directCallRoot);
|
|
12467
|
+
ctx.runtimeNeeded.add('createScopedValue');
|
|
12468
|
+
directCall = {
|
|
12469
|
+
subs,
|
|
12470
|
+
value: inheritOriginLoc(
|
|
12471
|
+
b.call(rtAlias('createScopedValue'), b.arrow([], record)),
|
|
12472
|
+
directCallRoot,
|
|
12473
|
+
),
|
|
12474
|
+
};
|
|
12475
|
+
}
|
|
12476
|
+
const renderCallTest =
|
|
12477
|
+
directCall === null
|
|
12478
|
+
? null
|
|
12479
|
+
: () =>
|
|
12480
|
+
inheritOriginLoc(
|
|
12481
|
+
b.call(
|
|
12482
|
+
requireRuntimeForContext(ctx, 'isRenderCall'),
|
|
12483
|
+
node.params.length > 1 ? secondArgument(node) : b.id('__s'),
|
|
12484
|
+
),
|
|
12485
|
+
directCallRoot,
|
|
12486
|
+
);
|
|
12428
12487
|
|
|
12429
12488
|
const body = [];
|
|
12430
12489
|
body.push(...serverThemeTouchStatements(themeTouches ?? [], ctx, node));
|
|
@@ -12488,7 +12547,39 @@ function ssrCompileBodyWithMapTemps(
|
|
|
12488
12547
|
}
|
|
12489
12548
|
}
|
|
12490
12549
|
}
|
|
12491
|
-
|
|
12550
|
+
// A direct call's deferred fragment registers its own head elements when it
|
|
12551
|
+
// renders, so the body-call registrations run only for a body call.
|
|
12552
|
+
const guardHead = (statements) =>
|
|
12553
|
+
renderCallTest === null || statements.length === 0
|
|
12554
|
+
? statements
|
|
12555
|
+
: [inheritOriginLoc(b.if(renderCallTest(), b.block(statements), null), statements[0])];
|
|
12556
|
+
body.push(...guardHead(frontHead), ...rewritten, ...inlinedSubs, ...guardHead(deferredHead));
|
|
12557
|
+
if (directCall !== null) {
|
|
12558
|
+
const scopeNames = collectFunctionScopeBindings(
|
|
12559
|
+
node.params.length > 0 ? node.params : [b.id('__props')],
|
|
12560
|
+
[...rewritten, ...inlinedSubs],
|
|
12561
|
+
new Set([...mapTemps, '__s', '__extra']),
|
|
12562
|
+
);
|
|
12563
|
+
const captures = directCallCaptures(node, scopeNames, directCall.subs, directCall.value);
|
|
12564
|
+
const branch =
|
|
12565
|
+
captures === null
|
|
12566
|
+
? [...directCall.subs, b.return(directCall.value)]
|
|
12567
|
+
: [
|
|
12568
|
+
b.return(
|
|
12569
|
+
hoistCapturingHelper(
|
|
12570
|
+
ctx,
|
|
12571
|
+
`${name}$direct`,
|
|
12572
|
+
captures,
|
|
12573
|
+
directCall.subs,
|
|
12574
|
+
directCall.value,
|
|
12575
|
+
directCallRoot,
|
|
12576
|
+
),
|
|
12577
|
+
),
|
|
12578
|
+
];
|
|
12579
|
+
body.push(
|
|
12580
|
+
inheritOriginLoc(b.if(b.unary('!', renderCallTest()), b.block(branch), null), directCallRoot),
|
|
12581
|
+
);
|
|
12582
|
+
}
|
|
12492
12583
|
// PROPS-FIRST ABI (matches the client): `(…userParams, __s, __extra)`. A leading
|
|
12493
12584
|
// `__props` placeholder stands in when there are no user params, so a verbatim
|
|
12494
12585
|
// `function Foo(props)` and a compiled component both bind props from arg 0.
|
|
@@ -19990,6 +20081,9 @@ function compileReturnJsxFunction(node, ctx, options) {
|
|
|
19990
20081
|
// their closure over setup locals/props — and only their values + the control
|
|
19991
20082
|
// expression are threaded into the renderer as `props.hN` holes.
|
|
19992
20083
|
const compInlinedSubs = [];
|
|
20084
|
+
// Set once a returned record needs a separate direct-call value.
|
|
20085
|
+
let renderCall = null;
|
|
20086
|
+
const returnedRecords = [];
|
|
19993
20087
|
// Fold a directive found at value position into a hoisted renderer owned by THIS
|
|
19994
20088
|
// body — the same fold the `@{}` body and the server emitter build.
|
|
19995
20089
|
const lowerBodyValueDirective =
|
|
@@ -20121,7 +20215,23 @@ function compileReturnJsxFunction(node, ctx, options) {
|
|
|
20121
20215
|
};
|
|
20122
20216
|
}
|
|
20123
20217
|
}
|
|
20124
|
-
|
|
20218
|
+
const record = lowerReturnJsx(h.argument, ctx, compInlinedSubs, cssHash);
|
|
20219
|
+
if (node._octaneBindingView || !directCallNeedsClientBranch(h.argument, node, ctx)) {
|
|
20220
|
+
return { ...h, argument: record };
|
|
20221
|
+
}
|
|
20222
|
+
renderCall ??= renderCallScopeParam(node, ctx);
|
|
20223
|
+
// Built once the function's top-level bindings are all known.
|
|
20224
|
+
const placeholder = inheritOriginLoc(b.id('__octaneReturnedRecord'), h.argument);
|
|
20225
|
+
returnedRecords.push({
|
|
20226
|
+
placeholder,
|
|
20227
|
+
record,
|
|
20228
|
+
origin: h.argument,
|
|
20229
|
+
test: inheritOriginLoc(
|
|
20230
|
+
b.call(requireRuntimeForContext(ctx, 'isRenderCall'), cloneAstNode(renderCall.scope)),
|
|
20231
|
+
h.argument,
|
|
20232
|
+
),
|
|
20233
|
+
});
|
|
20234
|
+
return { ...h, argument: placeholder };
|
|
20125
20235
|
}
|
|
20126
20236
|
return rewriteJsxValues(h, ctx);
|
|
20127
20237
|
});
|
|
@@ -20133,6 +20243,20 @@ function compileReturnJsxFunction(node, ctx, options) {
|
|
|
20133
20243
|
ctx.currentAutoCalculatedRenderableRefs = prevAutoCalculatedRenderableRefs;
|
|
20134
20244
|
ctx.currentMapTemps = prevMapTemps;
|
|
20135
20245
|
}
|
|
20246
|
+
if (returnedRecords.length > 0) {
|
|
20247
|
+
const scopeNames = collectFunctionScopeBindings(
|
|
20248
|
+
renderCall.params,
|
|
20249
|
+
[...compInlinedSubs, ...newStatements],
|
|
20250
|
+
new Set(mapTemps),
|
|
20251
|
+
);
|
|
20252
|
+
const replacements = new Map(
|
|
20253
|
+
returnedRecords.map((entry) => [
|
|
20254
|
+
entry.placeholder,
|
|
20255
|
+
splitReturnedRecord(ctx, node, name, scopeNames, entry),
|
|
20256
|
+
]),
|
|
20257
|
+
);
|
|
20258
|
+
newStatements = mapAst(newStatements, (candidate) => replacements.get(candidate) ?? null);
|
|
20259
|
+
}
|
|
20136
20260
|
if (
|
|
20137
20261
|
ctx.autoMemo &&
|
|
20138
20262
|
ctx.privateUnescapedComponents.has(name) &&
|
|
@@ -20184,7 +20308,7 @@ function compileReturnJsxFunction(node, ctx, options) {
|
|
|
20184
20308
|
}
|
|
20185
20309
|
const emittedFunction = b.function_declaration(
|
|
20186
20310
|
node.id,
|
|
20187
|
-
node.params,
|
|
20311
|
+
renderCall?.params ?? node.params,
|
|
20188
20312
|
b.block(
|
|
20189
20313
|
ctx.nativeReads ? wrapNativeReadScope(returnBody, b.void0, nativeReadNames(ctx)) : returnBody,
|
|
20190
20314
|
),
|
|
@@ -20532,6 +20656,238 @@ function requiresTemplateNormalization(
|
|
|
20532
20656
|
);
|
|
20533
20657
|
}
|
|
20534
20658
|
|
|
20659
|
+
// A named return-JSX declaration is also a component. Its body call evaluates
|
|
20660
|
+
// the returned record in the scope that renders it. A direct call returns a JSX
|
|
20661
|
+
// value instead, which must resolve where it renders, like the value an arrow
|
|
20662
|
+
// function returns. Both emitters classify the same authored root: 'fragment'
|
|
20663
|
+
// defers the compiled fragment record, 'value' uses ordinary value lowering, and
|
|
20664
|
+
// null marks static host markup that renders the same anywhere. The server's
|
|
20665
|
+
// body call renders the whole tree to HTML, so every non-literal hole and every
|
|
20666
|
+
// component below the root needs deferral there.
|
|
20667
|
+
function directCallReturnKind(node, ctx, stableNames = null) {
|
|
20668
|
+
if (VALUE_DIRECTIVE_ARM_TYPES.has(node.type)) return 'fragment';
|
|
20669
|
+
if (requiresTemplateNormalization(node, 'html', true, ctx)) return 'fragment';
|
|
20670
|
+
if (node.type !== 'Element' && node.type !== 'JSXElement') {
|
|
20671
|
+
return jsxValueChildrenNeedRenderScope(node, false, stableNames) ? 'value' : null;
|
|
20672
|
+
}
|
|
20673
|
+
if (isComponentTag(node)) return 'value';
|
|
20674
|
+
return jsxValueRootNeedsRenderScope(node, stableNames) ||
|
|
20675
|
+
jsxValueChildrenNeedRenderScope(node, false, stableNames)
|
|
20676
|
+
? 'fragment'
|
|
20677
|
+
: null;
|
|
20678
|
+
}
|
|
20679
|
+
|
|
20680
|
+
// Whether the client's body-call record evaluates anything a direct call must
|
|
20681
|
+
// defer. The client record only stores hole values and interprets them where
|
|
20682
|
+
// it mounts, so reading an unreassigned local is the same during the call and
|
|
20683
|
+
// at render. Value-lowered roots already defer, except a component's own props.
|
|
20684
|
+
function directCallNeedsClientBranch(node, fn, ctx) {
|
|
20685
|
+
const stable = directCallStableNames(fn);
|
|
20686
|
+
const kind = directCallReturnKind(node, ctx, stable);
|
|
20687
|
+
if (kind === 'fragment') return true;
|
|
20688
|
+
return (
|
|
20689
|
+
kind === 'value' &&
|
|
20690
|
+
(node.type === 'Element' || node.type === 'JSXElement') &&
|
|
20691
|
+
jsxValueRootNeedsRenderScope(node, stable)
|
|
20692
|
+
);
|
|
20693
|
+
}
|
|
20694
|
+
|
|
20695
|
+
// Names that code anywhere in the function assigns after declaring them.
|
|
20696
|
+
const DIRECT_CALL_ASSIGNED_NAMES = new WeakMap();
|
|
20697
|
+
function directCallAssignedNames(fn) {
|
|
20698
|
+
const cached = DIRECT_CALL_ASSIGNED_NAMES.get(fn);
|
|
20699
|
+
if (cached !== undefined) return cached;
|
|
20700
|
+
const assigned = new Set();
|
|
20701
|
+
const target = (node) => {
|
|
20702
|
+
if (node?.type === 'Identifier') assigned.add(node.name);
|
|
20703
|
+
else if (node != null && typeof node === 'object') collectBindings(node, assigned);
|
|
20704
|
+
};
|
|
20705
|
+
mapAst(fn.body, (node) => {
|
|
20706
|
+
if (node.type === 'AssignmentExpression') target(node.left);
|
|
20707
|
+
else if (node.type === 'UpdateExpression') target(node.argument);
|
|
20708
|
+
else if (
|
|
20709
|
+
(node.type === 'ForInStatement' || node.type === 'ForOfStatement') &&
|
|
20710
|
+
node.left?.type !== 'VariableDeclaration'
|
|
20711
|
+
) {
|
|
20712
|
+
target(node.left);
|
|
20713
|
+
}
|
|
20714
|
+
return null;
|
|
20715
|
+
});
|
|
20716
|
+
DIRECT_CALL_ASSIGNED_NAMES.set(fn, assigned);
|
|
20717
|
+
return assigned;
|
|
20718
|
+
}
|
|
20719
|
+
|
|
20720
|
+
// Parameters and top-level declarations that nothing in the function assigns.
|
|
20721
|
+
// Reading one runs no user code and yields the same value during the call and
|
|
20722
|
+
// at render, so the client record needs no deferral for it.
|
|
20723
|
+
function directCallStableNames(fn) {
|
|
20724
|
+
const names = collectComponentLocals(fn);
|
|
20725
|
+
for (const name of directCallAssignedNames(fn)) names.delete(name);
|
|
20726
|
+
return names;
|
|
20727
|
+
}
|
|
20728
|
+
|
|
20729
|
+
// A direct call's deferred value reads the function's locals after the call has
|
|
20730
|
+
// returned. Declaring its closure inside the function would make those locals
|
|
20731
|
+
// context slots, allocating a context on every call, body calls included, so
|
|
20732
|
+
// the value is built by a module function that receives them as arguments.
|
|
20733
|
+
// Returns those arguments, or null when a copy could differ from the live
|
|
20734
|
+
// binding: a captured authored local that the function reassigns, or a read of
|
|
20735
|
+
// `this` or `arguments`.
|
|
20736
|
+
function directCallCaptures(fn, scopeNames, statements, value) {
|
|
20737
|
+
const body = b.block([...statements, b.return(value)]);
|
|
20738
|
+
let contextual = false;
|
|
20739
|
+
mapAst(body, (node) => {
|
|
20740
|
+
if (
|
|
20741
|
+
node.type === 'ThisExpression' ||
|
|
20742
|
+
node.type === 'Super' ||
|
|
20743
|
+
node.type === 'MetaProperty' ||
|
|
20744
|
+
(node.type === 'Identifier' && node.name === 'arguments')
|
|
20745
|
+
) {
|
|
20746
|
+
contextual = true;
|
|
20747
|
+
}
|
|
20748
|
+
return contextual ? node : null;
|
|
20749
|
+
});
|
|
20750
|
+
if (contextual) return null;
|
|
20751
|
+
const captures = [...collectFreeIdentifiers(body, new Set())]
|
|
20752
|
+
.filter((identifier) => scopeNames.has(identifier))
|
|
20753
|
+
.sort();
|
|
20754
|
+
const assigned = directCallAssignedNames(fn);
|
|
20755
|
+
return captures.some((identifier) => assigned.has(identifier)) ? null : captures;
|
|
20756
|
+
}
|
|
20757
|
+
|
|
20758
|
+
// Declare `function helper(captures) { ...statements; return value; }` among the
|
|
20759
|
+
// module's hoisted helpers and return a call to it.
|
|
20760
|
+
function hoistCapturingHelper(ctx, preferred, captures, statements, value, origin) {
|
|
20761
|
+
const helper = allocCompilerName(ctx, preferred);
|
|
20762
|
+
const ids = () => captures.map((identifier) => inheritOriginLoc(b.id(identifier), origin));
|
|
20763
|
+
ctx.hoistedHelpers.push(
|
|
20764
|
+
inheritOriginLoc(
|
|
20765
|
+
b.function_declaration(b.id(helper), ids(), b.block([...statements, b.return(value)])),
|
|
20766
|
+
origin,
|
|
20767
|
+
),
|
|
20768
|
+
);
|
|
20769
|
+
return inheritOriginLoc(b.call(helper, ...ids()), origin);
|
|
20770
|
+
}
|
|
20771
|
+
|
|
20772
|
+
// The client's returned record, split between a body call and a direct call.
|
|
20773
|
+
// The record is printed once, in a module function the body call invokes; a
|
|
20774
|
+
// direct call defers that same function until the value renders.
|
|
20775
|
+
function splitReturnedRecord(ctx, fn, name, scopeNames, { record, test, origin }) {
|
|
20776
|
+
const captures = directCallCaptures(fn, scopeNames, [], record);
|
|
20777
|
+
if (captures === null) {
|
|
20778
|
+
ctx.runtimeNeeded.add('createScopedValue');
|
|
20779
|
+
const direct = b.call(rtAlias('createScopedValue'), b.arrow([], cloneAstNode(record)));
|
|
20780
|
+
return inheritOriginLoc(b.conditional(test, record, inheritOriginLoc(direct, origin)), origin);
|
|
20781
|
+
}
|
|
20782
|
+
const read = hoistCapturingHelper(ctx, `${name}$record`, captures, [], record, origin);
|
|
20783
|
+
const direct = b.call(
|
|
20784
|
+
requireRuntimeForContext(ctx, 'deferRecord'),
|
|
20785
|
+
b.id(read.callee.name),
|
|
20786
|
+
...read.arguments.map((argument) => cloneAstNode(argument)),
|
|
20787
|
+
);
|
|
20788
|
+
return inheritOriginLoc(b.conditional(test, read, inheritOriginLoc(direct, origin)), origin);
|
|
20789
|
+
}
|
|
20790
|
+
|
|
20791
|
+
// Names an emitted function body binds in its own scope: parameters, top-level
|
|
20792
|
+
// declarations, and `var` declarations in nested blocks.
|
|
20793
|
+
function collectFunctionScopeBindings(params, statements, into) {
|
|
20794
|
+
for (const param of params) collectBindings(param, into);
|
|
20795
|
+
const visit = (statement, topLevel) => {
|
|
20796
|
+
if (statement == null || typeof statement !== 'object') return;
|
|
20797
|
+
switch (statement.type) {
|
|
20798
|
+
case 'VariableDeclaration':
|
|
20799
|
+
if (topLevel || statement.kind === 'var') {
|
|
20800
|
+
for (const declaration of statement.declarations || []) {
|
|
20801
|
+
collectBindings(declaration.id, into);
|
|
20802
|
+
}
|
|
20803
|
+
}
|
|
20804
|
+
return;
|
|
20805
|
+
case 'FunctionDeclaration':
|
|
20806
|
+
case 'ClassDeclaration':
|
|
20807
|
+
if (topLevel && statement.id) into.add(statement.id.name);
|
|
20808
|
+
return;
|
|
20809
|
+
case 'BlockStatement':
|
|
20810
|
+
for (const child of statement.body || []) visit(child, false);
|
|
20811
|
+
return;
|
|
20812
|
+
case 'IfStatement':
|
|
20813
|
+
visit(statement.consequent, false);
|
|
20814
|
+
visit(statement.alternate, false);
|
|
20815
|
+
return;
|
|
20816
|
+
case 'ForStatement':
|
|
20817
|
+
visit(statement.init, false);
|
|
20818
|
+
visit(statement.body, false);
|
|
20819
|
+
return;
|
|
20820
|
+
case 'ForInStatement':
|
|
20821
|
+
case 'ForOfStatement':
|
|
20822
|
+
visit(statement.left, false);
|
|
20823
|
+
visit(statement.body, false);
|
|
20824
|
+
return;
|
|
20825
|
+
case 'WhileStatement':
|
|
20826
|
+
case 'DoWhileStatement':
|
|
20827
|
+
case 'LabeledStatement':
|
|
20828
|
+
visit(statement.body, false);
|
|
20829
|
+
return;
|
|
20830
|
+
case 'TryStatement':
|
|
20831
|
+
visit(statement.block, false);
|
|
20832
|
+
visit(statement.handler?.body, false);
|
|
20833
|
+
visit(statement.finalizer, false);
|
|
20834
|
+
return;
|
|
20835
|
+
case 'SwitchStatement':
|
|
20836
|
+
for (const clause of statement.cases || []) {
|
|
20837
|
+
for (const child of clause.consequent || []) visit(child, false);
|
|
20838
|
+
}
|
|
20839
|
+
return;
|
|
20840
|
+
default:
|
|
20841
|
+
return;
|
|
20842
|
+
}
|
|
20843
|
+
};
|
|
20844
|
+
for (const statement of statements) visit(statement, true);
|
|
20845
|
+
return into;
|
|
20846
|
+
}
|
|
20847
|
+
|
|
20848
|
+
// Argument 1 of a function whose own parameters already reach it: the second
|
|
20849
|
+
// parameter when the function never reassigns it, `arguments[1]` otherwise.
|
|
20850
|
+
function secondArgument(fn) {
|
|
20851
|
+
const params = fn.params || [];
|
|
20852
|
+
const second = params[1]?.type === 'AssignmentPattern' ? params[1].left : params[1];
|
|
20853
|
+
return second?.type === 'Identifier' &&
|
|
20854
|
+
params[0]?.type !== 'RestElement' &&
|
|
20855
|
+
!(params[0]?.type === 'Identifier' && params[0].name === 'this') &&
|
|
20856
|
+
!directCallAssignedNames(fn).has(second.name)
|
|
20857
|
+
? b.id(second.name)
|
|
20858
|
+
: b.member(b.id('arguments'), b.literal(1), true);
|
|
20859
|
+
}
|
|
20860
|
+
|
|
20861
|
+
// The argument a body call receives its Scope in. A spare default parameter
|
|
20862
|
+
// keeps the function's `length` and avoids an `arguments` object; functions
|
|
20863
|
+
// that cannot take one read `arguments[1]`.
|
|
20864
|
+
function renderCallScopeParam(node, ctx) {
|
|
20865
|
+
const params = node.params || [];
|
|
20866
|
+
const statements = node.body?.body || [];
|
|
20867
|
+
const strictBody = statements.some(
|
|
20868
|
+
(statement) => statement.type === 'ExpressionStatement' && statement.directive === 'use strict',
|
|
20869
|
+
);
|
|
20870
|
+
if (
|
|
20871
|
+
params.length > 1 ||
|
|
20872
|
+
strictBody ||
|
|
20873
|
+
params.some(
|
|
20874
|
+
(param) =>
|
|
20875
|
+
param.type === 'RestElement' || (param.type === 'Identifier' && param.name === 'this'),
|
|
20876
|
+
)
|
|
20877
|
+
) {
|
|
20878
|
+
return { params, scope: inheritOriginLoc(secondArgument(node), node) };
|
|
20879
|
+
}
|
|
20880
|
+
const scope = inheritOriginLoc(b.id(allocCompilerName(ctx, '__renderScope')), node);
|
|
20881
|
+
const spare = (identifier) => inheritOriginLoc(b.assignment_pattern(identifier, b.void0), node);
|
|
20882
|
+
return {
|
|
20883
|
+
params:
|
|
20884
|
+
params.length === 0
|
|
20885
|
+
? [spare(inheritOriginLoc(b.id(allocCompilerName(ctx, '__props')), node)), spare(scope)]
|
|
20886
|
+
: [...params, spare(scope)],
|
|
20887
|
+
scope,
|
|
20888
|
+
};
|
|
20889
|
+
}
|
|
20890
|
+
|
|
20535
20891
|
// Lower JSX at return position. Host roots always use the compiled-fragment
|
|
20536
20892
|
// path. Any other root whose subtree contains template-only syntax uses it too.
|
|
20537
20893
|
// Ordinary component/Fragment values retain descriptor lowering and its identity
|
|
@@ -22096,18 +22452,19 @@ function jsxNameToExpr(name) {
|
|
|
22096
22452
|
// hit the TDZ, while a member, coercion, spread, or computed key can invoke
|
|
22097
22453
|
// user code without containing a call. Function expressions are values here;
|
|
22098
22454
|
// their bodies still run only when an event/render-prop consumer invokes them.
|
|
22099
|
-
function isStaticJsxValueExpression(expression) {
|
|
22455
|
+
function isStaticJsxValueExpression(expression, stableNames = null) {
|
|
22100
22456
|
const value = unwrapTsExpr(expression);
|
|
22101
22457
|
return (
|
|
22102
22458
|
isInvariantLiteral(value) ||
|
|
22103
22459
|
value?.type === 'ArrowFunctionExpression' ||
|
|
22104
|
-
value?.type === 'FunctionExpression'
|
|
22460
|
+
value?.type === 'FunctionExpression' ||
|
|
22461
|
+
(stableNames !== null && value?.type === 'Identifier' && stableNames.has(value.name))
|
|
22105
22462
|
);
|
|
22106
22463
|
}
|
|
22107
22464
|
|
|
22108
22465
|
// A root member tag, spread, or dynamic prop can invoke user code before its
|
|
22109
22466
|
// descriptor exists. Defer the complete record rather than just its children.
|
|
22110
|
-
function jsxValueRootNeedsRenderScope(node) {
|
|
22467
|
+
function jsxValueRootNeedsRenderScope(node, stableNames = null) {
|
|
22111
22468
|
const name = node.openingElement?.name || node.id;
|
|
22112
22469
|
if (
|
|
22113
22470
|
name?.type === 'MemberExpression' ||
|
|
@@ -22120,7 +22477,7 @@ function jsxValueRootNeedsRenderScope(node) {
|
|
|
22120
22477
|
if (attr.type === 'SpreadAttribute' || attr.type === 'JSXSpreadAttribute') return true;
|
|
22121
22478
|
if (attr.type !== 'Attribute' && attr.type !== 'JSXAttribute') continue;
|
|
22122
22479
|
if (attr.value?.type !== 'JSXExpressionContainer') continue;
|
|
22123
|
-
if (!isStaticJsxValueExpression(attr.value.expression)) return true;
|
|
22480
|
+
if (!isStaticJsxValueExpression(attr.value.expression, stableNames)) return true;
|
|
22124
22481
|
}
|
|
22125
22482
|
return false;
|
|
22126
22483
|
}
|
|
@@ -22129,21 +22486,27 @@ function jsxValueRootNeedsRenderScope(node) {
|
|
|
22129
22486
|
// syntax is effectful. Nested component/tag resolution and dynamic attributes
|
|
22130
22487
|
// belong to their represented parent, so they make that parent's children lazy
|
|
22131
22488
|
// even when the nested element has no expression children of its own.
|
|
22132
|
-
function jsxValueChildrenNeedRenderScope(
|
|
22489
|
+
function jsxValueChildrenNeedRenderScope(
|
|
22490
|
+
node,
|
|
22491
|
+
descendantElementsOwnChildren = false,
|
|
22492
|
+
stableNames = null,
|
|
22493
|
+
) {
|
|
22133
22494
|
for (const child of node.children || []) {
|
|
22134
22495
|
if (child == null || child.type === 'JSXText' || child.type === 'Text') continue;
|
|
22135
22496
|
if (child.type === 'JSXExpressionContainer') {
|
|
22136
22497
|
if (
|
|
22137
22498
|
child.expression &&
|
|
22138
22499
|
child.expression.type !== 'JSXEmptyExpression' &&
|
|
22139
|
-
!isStaticJsxValueExpression(child.expression)
|
|
22500
|
+
!isStaticJsxValueExpression(child.expression, stableNames)
|
|
22140
22501
|
) {
|
|
22141
22502
|
return true;
|
|
22142
22503
|
}
|
|
22143
22504
|
continue;
|
|
22144
22505
|
}
|
|
22145
22506
|
if (child.type === 'Fragment' || child.type === 'JSXFragment') {
|
|
22146
|
-
if (jsxValueChildrenNeedRenderScope(child, descendantElementsOwnChildren))
|
|
22507
|
+
if (jsxValueChildrenNeedRenderScope(child, descendantElementsOwnChildren, stableNames)) {
|
|
22508
|
+
return true;
|
|
22509
|
+
}
|
|
22147
22510
|
continue;
|
|
22148
22511
|
}
|
|
22149
22512
|
if (child.type !== 'Element' && child.type !== 'JSXElement') return true;
|
|
@@ -22152,11 +22515,16 @@ function jsxValueChildrenNeedRenderScope(node, descendantElementsOwnChildren = f
|
|
|
22152
22515
|
if (attr.type === 'SpreadAttribute' || attr.type === 'JSXSpreadAttribute') return true;
|
|
22153
22516
|
if (attr.type !== 'Attribute' && attr.type !== 'JSXAttribute') return true;
|
|
22154
22517
|
if (attr.value?.type !== 'JSXExpressionContainer') continue;
|
|
22155
|
-
if (!isStaticJsxValueExpression(attr.value.expression)) return true;
|
|
22518
|
+
if (!isStaticJsxValueExpression(attr.value.expression, stableNames)) return true;
|
|
22156
22519
|
}
|
|
22157
22520
|
// A fragment can retain its inspectable positional array when only a nested
|
|
22158
22521
|
// element's descendants are dynamic: that element already owns their scope.
|
|
22159
|
-
if (
|
|
22522
|
+
if (
|
|
22523
|
+
!descendantElementsOwnChildren &&
|
|
22524
|
+
jsxValueChildrenNeedRenderScope(child, false, stableNames)
|
|
22525
|
+
) {
|
|
22526
|
+
return true;
|
|
22527
|
+
}
|
|
22160
22528
|
}
|
|
22161
22529
|
return false;
|
|
22162
22530
|
}
|