octane 0.16.3 → 0.16.5
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/README.md +1 -1
- package/dist/cjs/dom-focused-move.cjs +4 -2
- package/dist/cjs/error-codes.client.generated.cjs +5 -0
- package/dist/cjs/runtime/drivers.cjs +7 -4
- package/dist/cjs/runtime/effects.cjs +22 -0
- package/dist/cjs/runtime/engine.cjs +50 -7
- package/dist/cjs/runtime/hooks.cjs +6 -0
- package/dist/cjs/runtime/suspense.cjs +7 -2
- package/dist/cjs/runtime/transitions.cjs +14 -4
- package/dist/cjs/runtime.server.cjs +1 -2
- package/dist/cjs/version.cjs +1 -1
- package/dist/compiler/arm-exits.js +48 -1
- package/dist/compiler/bare-holes.js +84 -0
- package/dist/compiler/bundler.js +29 -22
- package/dist/compiler/compile-universal.js +114 -16
- package/dist/compiler/compile-valdi.js +161 -39
- package/dist/compiler/compile.js +245 -145
- package/dist/compiler/descriptor-lowering.js +29 -0
- package/dist/compiler/for-headers.js +9 -3
- package/dist/compiler/hook-deps.js +5 -2
- package/dist/compiler/hook-methods.js +5 -2
- package/dist/compiler/native-attribute-reads.js +10 -4
- package/dist/compiler/native-read-diagnostics.js +4 -1
- package/dist/compiler/server-context.js +5 -2
- package/dist/compiler/signal-attempt-reads.js +12 -6
- package/dist/compiler/volar.js +126 -15
- package/dist/context-identity.d.ts +15 -0
- package/dist/dom-focused-move.d.ts +6 -0
- package/dist/dom-focused-move.js +2 -1
- package/dist/error-codes.client.generated.d.ts +1 -0
- package/dist/error-codes.client.generated.js +5 -0
- package/dist/node/dom-focused-move.js +2 -1
- package/dist/node/error-codes.client.generated.js +5 -0
- package/dist/node/react/index.js +2 -0
- package/dist/node/react/react-compat.js +16 -2
- package/dist/node/react/server.js +2 -0
- package/dist/node/react/shared.js +2 -0
- package/dist/node/runtime/drivers.js +8 -4
- package/dist/node/runtime/effects.js +21 -0
- package/dist/node/runtime/engine.js +49 -7
- package/dist/node/runtime/hooks.js +5 -0
- package/dist/node/runtime/suspense.js +7 -2
- package/dist/node/runtime/transitions.js +16 -4
- package/dist/node/runtime.server.js +5 -3
- package/dist/node/tsrx-boundary.js +3 -1
- package/dist/node/version.js +1 -1
- package/dist/react/index.js +2 -0
- package/dist/react/react-compat-shared.d.ts +1 -1
- package/dist/react/react-compat.js +16 -2
- package/dist/react/server.js +2 -0
- package/dist/react/shared.d.ts +8 -0
- package/dist/react/shared.js +2 -0
- package/dist/runtime/drivers.js +8 -4
- package/dist/runtime/effects.d.ts +1 -0
- package/dist/runtime/effects.js +21 -0
- package/dist/runtime/engine.d.ts +10 -1
- package/dist/runtime/engine.js +49 -7
- package/dist/runtime/hooks.d.ts +14 -7
- package/dist/runtime/hooks.js +5 -0
- package/dist/runtime/suspense.d.ts +6 -5
- package/dist/runtime/suspense.js +7 -2
- package/dist/runtime/transitions.d.ts +11 -7
- package/dist/runtime/transitions.js +16 -4
- package/dist/runtime.server.d.ts +13 -18
- package/dist/runtime.server.js +5 -3
- package/dist/strong.d.ts +91 -0
- package/dist/tsrx-boundary.d.ts +8 -0
- package/dist/tsrx-boundary.js +3 -1
- package/dist/universal-core.d.ts +6 -0
- package/dist/version.js +1 -1
- package/package.json +6 -3
package/README.md
CHANGED
|
@@ -21,7 +21,7 @@ To use the compiler in Node, including through the Vite, Rspack, or Rsbuild
|
|
|
21
21
|
integrations, install its optional parser peer in your project:
|
|
22
22
|
|
|
23
23
|
```bash
|
|
24
|
-
pnpm add @tsrx/oxc@0.
|
|
24
|
+
pnpm add @tsrx/oxc@0.23.0
|
|
25
25
|
```
|
|
26
26
|
|
|
27
27
|
Applications that use only the Octane runtime do not need this peer.
|
|
@@ -19,7 +19,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
19
19
|
var dom_focused_move_exports = {};
|
|
20
20
|
__export(dom_focused_move_exports, {
|
|
21
21
|
isChildOf: () => isChildOf,
|
|
22
|
-
moveNativeNodeBefore: () => moveNativeNodeBefore
|
|
22
|
+
moveNativeNodeBefore: () => moveNativeNodeBefore,
|
|
23
|
+
nodeProto: () => nodeProto
|
|
23
24
|
});
|
|
24
25
|
module.exports = __toCommonJS(dom_focused_move_exports);
|
|
25
26
|
function moveNativeNodeBefore(parent, node, anchor, focused, contentEditable) {
|
|
@@ -96,5 +97,6 @@ function containsFocus(node, focused) {
|
|
|
96
97
|
// Annotate the CommonJS export names for ESM import in node:
|
|
97
98
|
0 && (module.exports = {
|
|
98
99
|
isChildOf,
|
|
99
|
-
moveNativeNodeBefore
|
|
100
|
+
moveNativeNodeBefore,
|
|
101
|
+
nodeProto
|
|
100
102
|
});
|
|
@@ -1128,6 +1128,11 @@ function formatClientError(code, ...args) {
|
|
|
1128
1128
|
"This container already has a behavior root; pass replace: true to replace it.",
|
|
1129
1129
|
args
|
|
1130
1130
|
);
|
|
1131
|
+
case 362:
|
|
1132
|
+
return (0, import_error_message.formatDevErrorMessage)(
|
|
1133
|
+
"A hook was called outside a component render. If the call is inside a component, the app probably loads more than one copy of Octane, possibly with the same version. Check that the renderer (`createRoot`), the hooks, and `octane/internal/client` all resolve to one installed `octane` package; a custom bundler may need to deduplicate `octane` and its subpaths.",
|
|
1134
|
+
args
|
|
1135
|
+
);
|
|
1131
1136
|
default:
|
|
1132
1137
|
return (0, import_error_message.formatUnknownDevErrorMessage)(code);
|
|
1133
1138
|
}
|
|
@@ -100,7 +100,7 @@ module.exports = __toCommonJS(drivers_exports);
|
|
|
100
100
|
var import_hydration_flag = require("../hydration-flag.cjs");
|
|
101
101
|
var import_event_names = require("../event-names.cjs");
|
|
102
102
|
var import_devtools_hook = require("../devtools-hook.cjs");
|
|
103
|
-
var
|
|
103
|
+
var import_error_codes_client_generated = require("../error-codes.client.generated.cjs");
|
|
104
104
|
var import_native_read_client = require("../signals/native-read-client.cjs");
|
|
105
105
|
var import_read_protocol = require("../signals/read-protocol.cjs");
|
|
106
106
|
var import_owner_context = require("../signals/owner-context.cjs");
|
|
@@ -232,7 +232,10 @@ function installEffectDrivers() {
|
|
|
232
232
|
schedulePassiveFlush = import_effects.scheduleRegisteredPassiveFlush;
|
|
233
233
|
}
|
|
234
234
|
let NATIVE_READ_DRIVER = null;
|
|
235
|
-
let resolveSlot = (slot) =>
|
|
235
|
+
let resolveSlot = (slot) => {
|
|
236
|
+
if (__octaneDev && slot !== void 0) (0, import_hooks.checkHookOwner)();
|
|
237
|
+
return slot;
|
|
238
|
+
};
|
|
236
239
|
let CONTROLLED_RESTORE_DRIVER = null;
|
|
237
240
|
let drainControlledSyncs = noop;
|
|
238
241
|
let publishManualFormPending = noop;
|
|
@@ -277,7 +280,7 @@ let reportUncaughtError = () => false;
|
|
|
277
280
|
let publishInlineCaughtErrorReports = noop;
|
|
278
281
|
let SIGNAL_BINDINGS_ENABLED = false;
|
|
279
282
|
function enableSignalBindings(abi = 1, potentialOnly = false) {
|
|
280
|
-
if (abi !== 1) throw new TypeError(
|
|
283
|
+
if (abi !== 1) throw new TypeError((0, import_error_codes_client_generated.formatClientError)(74));
|
|
281
284
|
SIGNAL_BINDINGS_ENABLED = true;
|
|
282
285
|
import_owner_context.signalOwnerUse.active = true;
|
|
283
286
|
SIGNAL_CHILD = import_signal_bindings.bindImplicitSignalChild;
|
|
@@ -448,7 +451,7 @@ function useEffectEvent(fn, slot) {
|
|
|
448
451
|
const cell = s;
|
|
449
452
|
return ((...args) => {
|
|
450
453
|
if (import_render.CURRENT_SCOPE !== null && import_engine.EFFECT_EVENT_LIFECYCLE_DEPTH === 0) {
|
|
451
|
-
throw new Error(
|
|
454
|
+
throw new Error((0, import_error_codes_client_generated.formatClientError)(11));
|
|
452
455
|
}
|
|
453
456
|
EFFECT_EVENT_INVOCATION_DEPTH++;
|
|
454
457
|
try {
|
|
@@ -41,6 +41,7 @@ __export(effects_exports, {
|
|
|
41
41
|
nativeEffectPublicationCurrent: () => nativeEffectPublicationCurrent,
|
|
42
42
|
passiveScheduled: () => passiveScheduled,
|
|
43
43
|
pendingPassiveUnmounts: () => pendingPassiveUnmounts,
|
|
44
|
+
postOrderHostRefs: () => postOrderHostRefs,
|
|
44
45
|
releaseDeferredPassives: () => releaseDeferredPassives,
|
|
45
46
|
renderWritesForbidden: () => renderWritesForbidden,
|
|
46
47
|
restoreDeferredPassives: () => restoreDeferredPassives,
|
|
@@ -49,6 +50,7 @@ __export(effects_exports, {
|
|
|
49
50
|
});
|
|
50
51
|
module.exports = __toCommonJS(effects_exports);
|
|
51
52
|
var import_engine = require("./engine.cjs");
|
|
53
|
+
var import_dom_focused_move = require("../dom-focused-move.cjs");
|
|
52
54
|
var import_hydration_flag = require("../hydration-flag.cjs");
|
|
53
55
|
var import_profiling = require("../profiling.cjs");
|
|
54
56
|
var import_drivers = require("./drivers.cjs");
|
|
@@ -169,6 +171,25 @@ function compareEffectPostOrder(a, b) {
|
|
|
169
171
|
function compareRefPostOrder(a, b) {
|
|
170
172
|
return comparePostOrder(a.block, 0, b.block, 0);
|
|
171
173
|
}
|
|
174
|
+
function postOrderHostRefs(q) {
|
|
175
|
+
for (let i = 1; i < q.length; i++) {
|
|
176
|
+
const entry = q[i];
|
|
177
|
+
let j = i;
|
|
178
|
+
while (j > 0 && q[j - 1].block === entry.block && compareHostRefs(q[j - 1], entry) > 0) {
|
|
179
|
+
q[j] = q[j - 1];
|
|
180
|
+
j--;
|
|
181
|
+
}
|
|
182
|
+
q[j] = entry;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
function compareHostRefs(a, b) {
|
|
186
|
+
const from = refPosition(a);
|
|
187
|
+
const position = (0, import_dom_focused_move.nodeProto)(from).compareDocumentPosition.call(from, refPosition(b));
|
|
188
|
+
return position & 16 || (position & 10) === 2 ? 1 : position === 0 ? 0 : -1;
|
|
189
|
+
}
|
|
190
|
+
function refPosition(entry) {
|
|
191
|
+
return entry.el._startMarker ?? entry.el;
|
|
192
|
+
}
|
|
172
193
|
function fireEffectCleanup(e) {
|
|
173
194
|
const slot = e.scope.hooks?.get(e.slot);
|
|
174
195
|
if (slot === void 0 || slot.revision !== e.revision) return;
|
|
@@ -369,6 +390,7 @@ function schedulePostPaint(cb) {
|
|
|
369
390
|
nativeEffectPublicationCurrent,
|
|
370
391
|
passiveScheduled,
|
|
371
392
|
pendingPassiveUnmounts,
|
|
393
|
+
postOrderHostRefs,
|
|
372
394
|
releaseDeferredPassives,
|
|
373
395
|
renderWritesForbidden,
|
|
374
396
|
restoreDeferredPassives,
|
|
@@ -126,6 +126,7 @@ __export(engine_exports, {
|
|
|
126
126
|
retireRendererSignalOwner: () => retireRendererSignalOwner,
|
|
127
127
|
retireRootBlock: () => retireRootBlock,
|
|
128
128
|
retiringHostsSince: () => retiringHostsSince,
|
|
129
|
+
retryRootRequest: () => retryRootRequest,
|
|
129
130
|
retryTransitionBatch: () => retryTransitionBatch,
|
|
130
131
|
retryTransitionHolder: () => retryTransitionHolder,
|
|
131
132
|
rollbackRootRender: () => rollbackRootRender,
|
|
@@ -145,6 +146,7 @@ __export(engine_exports, {
|
|
|
145
146
|
setIsOctaneActEnvironment: () => setIsOctaneActEnvironment,
|
|
146
147
|
settleTransitionFalls: () => settleTransitionFalls,
|
|
147
148
|
spawnDeferredSwap: () => spawnDeferredSwap,
|
|
149
|
+
suspendingTransitionHold: () => suspendingTransitionHold,
|
|
148
150
|
syncFlush: () => syncFlush,
|
|
149
151
|
tickTransitionCount: () => tickTransitionCount,
|
|
150
152
|
undoCreatedInRootRender: () => undoCreatedInRootRender,
|
|
@@ -383,20 +385,41 @@ let TRANSITION_PENDING_COUNT = 0;
|
|
|
383
385
|
let TRANSITION_HOLDERS = null;
|
|
384
386
|
let WOKEN_TRANSITION_HOLDERS = null;
|
|
385
387
|
let RETRIED_TRANSITION_BATCHES = null;
|
|
386
|
-
|
|
388
|
+
let RETRIED_ROOT_REQUESTS = null;
|
|
389
|
+
function suspendingTransitionHold(holder) {
|
|
387
390
|
const holders = TRANSITION_HOLDERS ??= /* @__PURE__ */ new Map();
|
|
388
391
|
let hold = holders.get(holder);
|
|
389
|
-
if (hold === void 0)
|
|
392
|
+
if (hold === void 0)
|
|
393
|
+
holders.set(holder, hold = { batches: /* @__PURE__ */ new Set(), suspends: true, request: -1 });
|
|
390
394
|
else if (!hold.suspends) {
|
|
391
395
|
hold.suspends = true;
|
|
392
396
|
for (const held of hold.batches) held.suspended++;
|
|
393
397
|
}
|
|
398
|
+
return hold;
|
|
399
|
+
}
|
|
400
|
+
function holdTransitionBatch(holder, batch) {
|
|
401
|
+
const hold = suspendingTransitionHold(holder);
|
|
394
402
|
if (hold.batches.has(batch)) return;
|
|
395
403
|
hold.batches.add(batch);
|
|
396
404
|
batch.pendingHolds = (batch.pendingHolds ?? 0) + 1;
|
|
397
405
|
if (hold.suspends) batch.suspended++;
|
|
398
406
|
(0, import_transitions.raiseHeldTransitionBatch)(batch);
|
|
399
407
|
}
|
|
408
|
+
function retryRootRequest(owner, generation) {
|
|
409
|
+
if (owner.disposed || owner.generation !== generation) return false;
|
|
410
|
+
if (inFlush || import_render.CURRENT_BLOCK !== null) {
|
|
411
|
+
(RETRIED_ROOT_REQUESTS ??= []).push(owner, generation);
|
|
412
|
+
scheduleTransitionTask();
|
|
413
|
+
return true;
|
|
414
|
+
}
|
|
415
|
+
TRANSITION_DEPTH++;
|
|
416
|
+
try {
|
|
417
|
+
owner.retry();
|
|
418
|
+
} finally {
|
|
419
|
+
TRANSITION_DEPTH--;
|
|
420
|
+
}
|
|
421
|
+
return true;
|
|
422
|
+
}
|
|
400
423
|
function retryTransitionBatch(batch, render, fall) {
|
|
401
424
|
if (inFlush || import_render.CURRENT_BLOCK !== null) {
|
|
402
425
|
(RETRIED_TRANSITION_BATCHES ??= []).push(batch, render, fall);
|
|
@@ -423,6 +446,13 @@ function unsuspendTransitionHolder(holder) {
|
|
|
423
446
|
(RETRIED_TRANSITION_BATCHES ??= []).push(batch, true, false);
|
|
424
447
|
scheduleTransitionTask();
|
|
425
448
|
}
|
|
449
|
+
if (hold.request !== -1) {
|
|
450
|
+
(RETRIED_ROOT_REQUESTS ??= []).push(
|
|
451
|
+
holder.parentBlock.idState.renderOwner,
|
|
452
|
+
hold.request
|
|
453
|
+
);
|
|
454
|
+
scheduleTransitionTask();
|
|
455
|
+
}
|
|
426
456
|
}
|
|
427
457
|
let TRANSITION_HOOK_PUBLISH_DEPTH = 0;
|
|
428
458
|
function scheduleHookPublication(block) {
|
|
@@ -552,6 +582,11 @@ function retryWokenTransitions() {
|
|
|
552
582
|
retried[i + 2]
|
|
553
583
|
);
|
|
554
584
|
}
|
|
585
|
+
const requests = RETRIED_ROOT_REQUESTS;
|
|
586
|
+
RETRIED_ROOT_REQUESTS = null;
|
|
587
|
+
if (requests !== null)
|
|
588
|
+
for (let i = 0; i < requests.length; i += 2)
|
|
589
|
+
retryRootRequest(requests[i], requests[i + 1]);
|
|
555
590
|
}
|
|
556
591
|
let COMMITTING_OWNER = null;
|
|
557
592
|
let COMMITTING_GENERATION = 0;
|
|
@@ -1259,7 +1294,8 @@ function scheduleTransitionTask() {
|
|
|
1259
1294
|
if (transitionTask !== id) return;
|
|
1260
1295
|
TRANSITION_TASK_ACTIVE = true;
|
|
1261
1296
|
try {
|
|
1262
|
-
if (WOKEN_TRANSITION_HOLDERS || RETRIED_TRANSITION_BATCHES
|
|
1297
|
+
if (WOKEN_TRANSITION_HOLDERS || RETRIED_TRANSITION_BATCHES || RETRIED_ROOT_REQUESTS)
|
|
1298
|
+
retryWokenTransitions();
|
|
1263
1299
|
adoptTransitionQueue(true);
|
|
1264
1300
|
flush();
|
|
1265
1301
|
} finally {
|
|
@@ -1276,7 +1312,8 @@ function adoptTransitionQueue(drain) {
|
|
|
1276
1312
|
if (drain === true) import_drivers.TRANSITION_ROOT_DRIVER.armFalls();
|
|
1277
1313
|
else scheduleTransitionTask();
|
|
1278
1314
|
}
|
|
1279
|
-
if (WOKEN_TRANSITION_HOLDERS || RETRIED_TRANSITION_BATCHES
|
|
1315
|
+
if (WOKEN_TRANSITION_HOLDERS || RETRIED_TRANSITION_BATCHES || RETRIED_ROOT_REQUESTS)
|
|
1316
|
+
scheduleTransitionTask();
|
|
1280
1317
|
}
|
|
1281
1318
|
function settleTransitionFalls() {
|
|
1282
1319
|
const armed = ARMED_TRANSITION_FALLS;
|
|
@@ -2288,6 +2325,7 @@ function drainQueuedRefAttaches() {
|
|
|
2288
2325
|
break;
|
|
2289
2326
|
}
|
|
2290
2327
|
}
|
|
2328
|
+
(0, import_effects.postOrderHostRefs)(q);
|
|
2291
2329
|
}
|
|
2292
2330
|
for (const r of q) {
|
|
2293
2331
|
if ((0, import_refs.blockSubtreeDisposed)(r.block)) continue;
|
|
@@ -2965,10 +3003,10 @@ function countLayoutSnapshotChange(cell, block) {
|
|
|
2965
3003
|
let DID_WARN_UNCACHED_SNAPSHOT = false;
|
|
2966
3004
|
function useSyncExternalStore(subscribe, getSnapshot, serverSnapshotOrSlot = void 0, lastSlot) {
|
|
2967
3005
|
const count = arguments.length;
|
|
2968
|
-
|
|
3006
|
+
const getServerSnapshot = typeof serverSnapshotOrSlot === "function" ? serverSnapshotOrSlot : void 0;
|
|
3007
|
+
let slot = count > 4 ? arguments[count - 1] : count === 4 ? lastSlot : getServerSnapshot ? void 0 : serverSnapshotOrSlot;
|
|
2969
3008
|
slot = (0, import_drivers.resolveSlot)(slot);
|
|
2970
3009
|
if (slot === void 0) (0, import_hooks.missingSlot)("useSyncExternalStore");
|
|
2971
|
-
const getServerSnapshot = count >= 4 ? serverSnapshotOrSlot : void 0;
|
|
2972
3010
|
const subs = (0, import_hooks.usesSubslots)(slot);
|
|
2973
3011
|
const readSnapshot = import_hydration_flag.hydrating && import_hydration.CURSOR !== null && getServerSnapshot !== void 0 ? getServerSnapshot : getSnapshot;
|
|
2974
3012
|
const value = readSnapshot();
|
|
@@ -3008,7 +3046,10 @@ function useSyncExternalStore(subscribe, getSnapshot, serverSnapshotOrSlot = voi
|
|
|
3008
3046
|
(0, import_hooks.ensureHooks)(scope).set(subs.inst, inst);
|
|
3009
3047
|
(0, import_hooks.enqueueStoreSync)(inst, value, subscribe);
|
|
3010
3048
|
} else {
|
|
3011
|
-
inst.getSnapshot
|
|
3049
|
+
if (inst.getSnapshot !== getSnapshot) {
|
|
3050
|
+
journalRootProperty(inst, "getSnapshot", inst.getSnapshot);
|
|
3051
|
+
inst.getSnapshot = getSnapshot;
|
|
3052
|
+
}
|
|
3012
3053
|
if (!Object.is(value, inst.value) || subscribe !== inst.subscribe) {
|
|
3013
3054
|
(0, import_hooks.enqueueStoreSync)(inst, value, subscribe);
|
|
3014
3055
|
}
|
|
@@ -3819,6 +3860,7 @@ function makeRoot(container, rootBlock, currentBody, currentKey, idState, output
|
|
|
3819
3860
|
retireRendererSignalOwner,
|
|
3820
3861
|
retireRootBlock,
|
|
3821
3862
|
retiringHostsSince,
|
|
3863
|
+
retryRootRequest,
|
|
3822
3864
|
retryTransitionBatch,
|
|
3823
3865
|
retryTransitionHolder,
|
|
3824
3866
|
rollbackRootRender,
|
|
@@ -3838,6 +3880,7 @@ function makeRoot(container, rootBlock, currentBody, currentKey, idState, output
|
|
|
3838
3880
|
setIsOctaneActEnvironment,
|
|
3839
3881
|
settleTransitionFalls,
|
|
3840
3882
|
spawnDeferredSwap,
|
|
3883
|
+
suspendingTransitionHold,
|
|
3841
3884
|
syncFlush,
|
|
3842
3885
|
tickTransitionCount,
|
|
3843
3886
|
undoCreatedInRootRender,
|
|
@@ -26,6 +26,7 @@ __export(hooks_exports, {
|
|
|
26
26
|
adoptMemoEntry: () => adoptMemoEntry,
|
|
27
27
|
callWithReceiver: () => callWithReceiver,
|
|
28
28
|
cancelHiddenRevealAction: () => cancelHiddenRevealAction,
|
|
29
|
+
checkHookOwner: () => checkHookOwner,
|
|
29
30
|
commitHookCells: () => commitHookCells,
|
|
30
31
|
compilerMemoRegion: () => compilerMemoRegion,
|
|
31
32
|
compilerMemoWitness: () => compilerMemoWitness,
|
|
@@ -120,6 +121,9 @@ function hookSlots(count) {
|
|
|
120
121
|
function missingSlot(name) {
|
|
121
122
|
throw new Error((0, import_error_codes_client_generated.formatClientError)(15, name));
|
|
122
123
|
}
|
|
124
|
+
function checkHookOwner() {
|
|
125
|
+
if (import_render.CURRENT_SCOPE === null) throw new Error((0, import_error_codes_client_generated.formatClientError)(362));
|
|
126
|
+
}
|
|
123
127
|
const slotStack = [];
|
|
124
128
|
function manualHook(fn, name) {
|
|
125
129
|
function provider() {
|
|
@@ -139,6 +143,7 @@ function appendSlotKey(key, slot) {
|
|
|
139
143
|
}
|
|
140
144
|
function resolveCustomSlot(slot) {
|
|
141
145
|
const n = slotStack.length;
|
|
146
|
+
if (__octaneDev && (slot !== void 0 || n !== 0)) checkHookOwner();
|
|
142
147
|
if (n === 0) return slot;
|
|
143
148
|
if (slot === void 0 && n === 1) return slotStack[0];
|
|
144
149
|
const resolved = (0, import_hook_slot_cache.resolveHookPath)(slotStack, slot, false);
|
|
@@ -911,6 +916,7 @@ function useId(slot) {
|
|
|
911
916
|
adoptMemoEntry,
|
|
912
917
|
callWithReceiver,
|
|
913
918
|
cancelHiddenRevealAction,
|
|
919
|
+
checkHookOwner,
|
|
914
920
|
commitHookCells,
|
|
915
921
|
compilerMemoRegion,
|
|
916
922
|
compilerMemoWitness,
|
|
@@ -787,9 +787,12 @@ function mountErrorBoundary(state, hydration) {
|
|
|
787
787
|
return state.block;
|
|
788
788
|
};
|
|
789
789
|
state.block = body;
|
|
790
|
+
if (freshBoundary) hydration.suspend(() => renderErrorBody(state, body, hydration));
|
|
791
|
+
else renderErrorBody(state, body, hydration);
|
|
792
|
+
}
|
|
793
|
+
function renderErrorBody(state, body, hydration) {
|
|
790
794
|
try {
|
|
791
|
-
if (
|
|
792
|
-
else if (hydration !== null) hydration.renderTryBody(body, true);
|
|
795
|
+
if (hydration !== null) hydration.renderTryBody(body, true);
|
|
793
796
|
else (0, import_signal_owners.renderBlock)(body);
|
|
794
797
|
state.hasResolved = true;
|
|
795
798
|
} catch (error) {
|
|
@@ -815,6 +818,8 @@ function switchErrorToCatchInner(state, error, reportInline) {
|
|
|
815
818
|
const previous = state.block;
|
|
816
819
|
if (previous !== null) {
|
|
817
820
|
state.block = null;
|
|
821
|
+
const transaction = import_render.ROOT_RENDER_TRANSACTION;
|
|
822
|
+
if (transaction !== null && !transaction.aborted) dropBodyOps(transaction, previous);
|
|
818
823
|
(0, import_block.unmountBlock)(previous, hydration === null);
|
|
819
824
|
if (state.parentBlock.disposed || state.block !== null) return;
|
|
820
825
|
}
|
|
@@ -287,6 +287,8 @@ function releaseTransitionHookHolder(holder, retry = true) {
|
|
|
287
287
|
if (unblocked || settled) (0, import_engine.retryTransitionBatch)(batch, unblocked, settled);
|
|
288
288
|
} else if (settled) finishTransitionHookBatch(batch);
|
|
289
289
|
}
|
|
290
|
+
if (hold.request !== -1 && hold.suspends && retry)
|
|
291
|
+
return (0, import_engine.retryRootRequest)(holder.parentBlock.idState.renderOwner, hold.request) || hold.batches.size !== 0;
|
|
290
292
|
return true;
|
|
291
293
|
}
|
|
292
294
|
const HELD_TRANSITIONS = /* @__PURE__ */ new Set();
|
|
@@ -379,12 +381,14 @@ function noteTransitionBatch(transaction, batch) {
|
|
|
379
381
|
function dropTransitionRender(transaction) {
|
|
380
382
|
const holders = transaction.holders;
|
|
381
383
|
transaction.holders = null;
|
|
384
|
+
const owner = transaction.owner;
|
|
382
385
|
const origin = import_engine.TRANSITION_ORIGIN;
|
|
383
|
-
const batches = origin === null ? transaction.batches : transaction.batches?.filter((batch) => batch.origin === origin) ??
|
|
384
|
-
|
|
386
|
+
const batches = (origin === null ? transaction.batches : transaction.batches?.filter((batch) => batch.origin === origin)) ?? [];
|
|
387
|
+
const request = transaction.rootRequest && origin !== null && origin === owner.current && origin.currentRenderMode === "transition";
|
|
388
|
+
if (batches.length === 0 && !request || owner.disposed) return false;
|
|
385
389
|
let live = false;
|
|
386
390
|
for (const holder of holders)
|
|
387
|
-
if (holder.__kind
|
|
391
|
+
if (holder.__kind === "trySlotSlot" ? holder.transitionHeld : batches.length !== 0)
|
|
388
392
|
live = true;
|
|
389
393
|
if (!live) return false;
|
|
390
394
|
if (typeof __OCTANE_PROFILE_ENABLED__ !== "undefined" && __OCTANE_PROFILE_ENABLED__)
|
|
@@ -399,7 +403,11 @@ function dropTransitionRender(transaction) {
|
|
|
399
403
|
for (const holder of holders) {
|
|
400
404
|
if (holder.__kind === "trySlotSlot") {
|
|
401
405
|
if (!holder.transitionHeld) continue;
|
|
402
|
-
|
|
406
|
+
if (request) (0, import_engine.suspendingTransitionHold)(holder).request = owner.generation;
|
|
407
|
+
} else {
|
|
408
|
+
if (batches.length === 0) continue;
|
|
409
|
+
if (import_engine.TRANSITION_HOLDERS?.has(holder) !== true) (0, import_engine.tickTransitionCount)(1);
|
|
410
|
+
}
|
|
403
411
|
for (const batch of batches) (0, import_engine.holdTransitionBatch)(holder, batch);
|
|
404
412
|
}
|
|
405
413
|
for (const other of import_engine.ROOT_RENDER_TRANSACTIONS)
|
|
@@ -425,6 +433,8 @@ function holdsUnrenderedTransition(state) {
|
|
|
425
433
|
const hold = import_engine.TRANSITION_HOLDERS.get(state);
|
|
426
434
|
if (hold === void 0) return false;
|
|
427
435
|
const transaction = import_render.ROOT_RENDER_TRANSACTION;
|
|
436
|
+
if (hold.request !== -1 && (transaction === null || !transaction.rootRequest) && state.parentBlock.idState.renderOwner.generation === hold.request)
|
|
437
|
+
return true;
|
|
428
438
|
for (const batch of hold.batches)
|
|
429
439
|
if (transaction === null || batch.stamp !== transaction.createdStamp) return true;
|
|
430
440
|
return false;
|
|
@@ -4894,8 +4894,7 @@ function useDeferredValue(value, initialValueOrSlot = void 0, _slot) {
|
|
|
4894
4894
|
function useSyncExternalStore(_subscribe, getSnapshot, serverSnapshotOrSlot = void 0, _slot) {
|
|
4895
4895
|
if (SHELL_WITNESS !== null && __octaneDev)
|
|
4896
4896
|
witnessShellHook("useSyncExternalStore", useSyncExternalStore);
|
|
4897
|
-
|
|
4898
|
-
return getServerSnapshot ? getServerSnapshot() : getSnapshot();
|
|
4897
|
+
return typeof serverSnapshotOrSlot === "function" ? serverSnapshotOrSlot() : getSnapshot();
|
|
4899
4898
|
}
|
|
4900
4899
|
function useActionState(_action, initialState) {
|
|
4901
4900
|
return [initialState, NOOP, false];
|
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.16.
|
|
24
|
+
const version = "0.16.5";
|
|
25
25
|
// Annotate the CommonJS export names for ESM import in node:
|
|
26
26
|
0 && (module.exports = {
|
|
27
27
|
version
|
|
@@ -82,6 +82,50 @@ const LOOP_TYPES = new Set([
|
|
|
82
82
|
'DoWhileStatement',
|
|
83
83
|
]);
|
|
84
84
|
|
|
85
|
+
/**
|
|
86
|
+
* Replace each exit that a directive arm's setup owns, anywhere in `ast`, with
|
|
87
|
+
* `exit(node)`, copy-on-write. Nested functions and `@{ … }` blocks own their
|
|
88
|
+
* jumps, and a nested directive's arms are arms of their own. The type-only
|
|
89
|
+
* view uses this; each compiler walks its arms itself.
|
|
90
|
+
*/
|
|
91
|
+
export function mapArmExits(ast, exit) {
|
|
92
|
+
const visit = (node, arm, loop, breakable) => {
|
|
93
|
+
if (Array.isArray(node)) {
|
|
94
|
+
let out = null;
|
|
95
|
+
for (let i = 0; i < node.length; i++) {
|
|
96
|
+
const child = node[i];
|
|
97
|
+
const mapped =
|
|
98
|
+
child !== null && typeof child === 'object' ? visit(child, arm, loop, breakable) : child;
|
|
99
|
+
if (out === null && mapped !== child) out = node.slice(0, i);
|
|
100
|
+
if (out !== null) out.push(mapped);
|
|
101
|
+
}
|
|
102
|
+
return out ?? node;
|
|
103
|
+
}
|
|
104
|
+
const type = node.type;
|
|
105
|
+
if (arm && armJump(node, loop, breakable) === 'exit') return exit(node);
|
|
106
|
+
if (DIRECTIVE_TYPES.has(type)) {
|
|
107
|
+
arm = true;
|
|
108
|
+
loop = breakable = false;
|
|
109
|
+
} else if (FUNCTION_TYPES.has(type) || type === 'JSXCodeBlock') {
|
|
110
|
+
arm = false;
|
|
111
|
+
} else if (LOOP_TYPES.has(type)) {
|
|
112
|
+
loop = breakable = true;
|
|
113
|
+
} else if (type === 'SwitchStatement') {
|
|
114
|
+
breakable = true;
|
|
115
|
+
}
|
|
116
|
+
let out = null;
|
|
117
|
+
for (const key in node) {
|
|
118
|
+
if (WALK_SKIP_KEYS.has(key)) continue;
|
|
119
|
+
const child = node[key];
|
|
120
|
+
if (child === null || typeof child !== 'object') continue;
|
|
121
|
+
const mapped = visit(child, arm, loop, breakable);
|
|
122
|
+
if (mapped !== child) (out ??= { ...node })[key] = mapped;
|
|
123
|
+
}
|
|
124
|
+
return out ?? node;
|
|
125
|
+
};
|
|
126
|
+
return visit(ast, false, false, false);
|
|
127
|
+
}
|
|
128
|
+
|
|
85
129
|
// The template region a statement sits in. Outside every template, jumps are
|
|
86
130
|
// ordinary JavaScript and the parser resolves them.
|
|
87
131
|
const OUTSIDE = 0;
|
|
@@ -125,7 +169,10 @@ export function assertTemplateJumps(ast, source, filename) {
|
|
|
125
169
|
: region === BLOCK && !(type === 'ContinueStatement' ? loop : breakable);
|
|
126
170
|
if (leaves) {
|
|
127
171
|
const at = node.loc ? ` (${file}:${node.loc.start.line}:${node.loc.start.column})` : '';
|
|
128
|
-
throw
|
|
172
|
+
throw Object.assign(
|
|
173
|
+
new Error((region === BLOCK ? BLOCK_JUMP_MESSAGE : ARM_LABEL_MESSAGE) + at),
|
|
174
|
+
{ code: region === BLOCK ? 'OCTANE_BLOCK_JUMP' : 'OCTANE_ARM_LABELED_JUMP' },
|
|
175
|
+
);
|
|
129
176
|
}
|
|
130
177
|
return;
|
|
131
178
|
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A `@{ … }` body and every directive arm hold setup statements, then one
|
|
3
|
+
* output node: an element, a fragment, a `@{ … }` block, or a directive. In
|
|
4
|
+
* statement position `{children}` is therefore a JavaScript block around a
|
|
5
|
+
* dead expression, not a hole, and the body renders nothing in its place. It
|
|
6
|
+
* reads as a hole, so assertNoBareHoles rejects it once on the authored module,
|
|
7
|
+
* ahead of every compiler. Braces around one expression statement do nothing
|
|
8
|
+
* in JavaScript, so setup code never needs this shape. `@case` arms are the
|
|
9
|
+
* exception: the parser reads a `{` there as a hole, and it renders.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const BARE_HOLE_MESSAGE =
|
|
13
|
+
'`{…}` in a `@{ … }` body or directive arm is a JavaScript block, not a hole, so it ' +
|
|
14
|
+
'renders nothing. Wrap it in a fragment to render it, as in `<>{children}</>`, or ' +
|
|
15
|
+
'remove the braces to keep it as setup code.';
|
|
16
|
+
|
|
17
|
+
const WALK_SKIP_KEYS = new Set(['type', 'loc', 'start', 'end', 'range', 'metadata', 'parent']);
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Reject the first block statement holding a single expression statement among
|
|
21
|
+
* the statements of a `@{ … }` body or an `@if`/`@else`, `@for`/`@empty`, or
|
|
22
|
+
* `@try`/`@pending`/`@catch` arm. Runs once per module, on the authored AST,
|
|
23
|
+
* for every target.
|
|
24
|
+
*/
|
|
25
|
+
export function assertNoBareHoles(ast, source, filename) {
|
|
26
|
+
if (!/@(?:\{|(?:if|for|try)\b)/.test(source)) return;
|
|
27
|
+
const file = filename.split(/[\\/]/).pop();
|
|
28
|
+
const check = (body) => {
|
|
29
|
+
if (body == null) return;
|
|
30
|
+
// An `@else if` chain continues as a plain IfStatement.
|
|
31
|
+
if (body.type === 'IfStatement') {
|
|
32
|
+
check(body.consequent);
|
|
33
|
+
check(body.alternate);
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
// The compilers also accept an arm that is a single node, or an `@else`
|
|
37
|
+
// that is a JSXIfExpression, which the walk below checks on its own.
|
|
38
|
+
if (!Array.isArray(body.body)) return;
|
|
39
|
+
for (const statement of body.body) {
|
|
40
|
+
if (
|
|
41
|
+
statement.type === 'BlockStatement' &&
|
|
42
|
+
statement.body.length === 1 &&
|
|
43
|
+
statement.body[0].type === 'ExpressionStatement'
|
|
44
|
+
) {
|
|
45
|
+
const at = statement.loc
|
|
46
|
+
? ` (${file}:${statement.loc.start.line}:${statement.loc.start.column})`
|
|
47
|
+
: '';
|
|
48
|
+
throw Object.assign(new Error(BARE_HOLE_MESSAGE + at), { code: 'OCTANE_BARE_HOLE' });
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
const visit = (node) => {
|
|
53
|
+
if (Array.isArray(node)) {
|
|
54
|
+
for (const child of node) {
|
|
55
|
+
if (child !== null && typeof child === 'object') visit(child);
|
|
56
|
+
}
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
switch (node.type) {
|
|
60
|
+
case 'JSXCodeBlock':
|
|
61
|
+
check(node);
|
|
62
|
+
break;
|
|
63
|
+
case 'JSXIfExpression':
|
|
64
|
+
check(node.consequent);
|
|
65
|
+
check(node.alternate);
|
|
66
|
+
break;
|
|
67
|
+
case 'JSXForExpression':
|
|
68
|
+
check(node.body);
|
|
69
|
+
check(node.empty);
|
|
70
|
+
break;
|
|
71
|
+
case 'JSXTryExpression':
|
|
72
|
+
check(node.block);
|
|
73
|
+
check(node.pending);
|
|
74
|
+
check(node.handler?.body);
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
for (const key in node) {
|
|
78
|
+
if (WALK_SKIP_KEYS.has(key)) continue;
|
|
79
|
+
const child = node[key];
|
|
80
|
+
if (child !== null && typeof child === 'object') visit(child);
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
visit(ast);
|
|
84
|
+
}
|
package/dist/compiler/bundler.js
CHANGED
|
@@ -316,10 +316,10 @@ function normalizeHmrDialect(value) {
|
|
|
316
316
|
/**
|
|
317
317
|
* Classify direct function exports whose production TSRX body has no renderable
|
|
318
318
|
* JavaScript return. A direct `memo(LocalComponent)` export preserves that
|
|
319
|
-
* contract, as
|
|
320
|
-
*
|
|
321
|
-
* source they loaded. Re-exports and
|
|
322
|
-
* unknown.
|
|
319
|
+
* contract, as does a default export of such a binding, and so do null-only
|
|
320
|
+
* early-return guards that compile to template control flow. Bundler adapters
|
|
321
|
+
* attach this fact after compiling the exact source they loaded. Re-exports and
|
|
322
|
+
* indirect bindings remain deliberately unknown.
|
|
323
323
|
*/
|
|
324
324
|
export function findVoidComponentExports(source, id) {
|
|
325
325
|
let ast;
|
|
@@ -357,6 +357,17 @@ export function findVoidComponentExports(source, id) {
|
|
|
357
357
|
if (declaration) declarations.push(declaration);
|
|
358
358
|
}
|
|
359
359
|
|
|
360
|
+
// The local a direct `memo(Local)` call wraps, or null. The imported memo
|
|
361
|
+
// identity is lexical proof; method calls, comparators, and arbitrary
|
|
362
|
+
// wrappers stay unknown.
|
|
363
|
+
const memoTarget = (node) =>
|
|
364
|
+
node?.type === 'CallExpression' &&
|
|
365
|
+
node.callee?.type === 'Identifier' &&
|
|
366
|
+
memoLocals.has(node.callee.name) &&
|
|
367
|
+
node.arguments?.length === 1 &&
|
|
368
|
+
node.arguments[0]?.type === 'Identifier'
|
|
369
|
+
? node.arguments[0].name
|
|
370
|
+
: null;
|
|
360
371
|
const voidBindings = new Set();
|
|
361
372
|
const memoDependents = new Map();
|
|
362
373
|
const hasLowerableJsxReturnBranches = createJsxReturnBranchClassifier(ast.body || []);
|
|
@@ -375,10 +386,9 @@ export function findVoidComponentExports(source, id) {
|
|
|
375
386
|
continue;
|
|
376
387
|
}
|
|
377
388
|
if (declaration.type !== 'VariableDeclaration' || declaration.kind !== 'const') continue;
|
|
378
|
-
// Resolve only the exact, immutable `const Export = memo(Local)` form.
|
|
379
|
-
//
|
|
380
|
-
//
|
|
381
|
-
// declared outermost-first does not rescan every declaration per link.
|
|
389
|
+
// Resolve only the exact, immutable `const Export = memo(Local)` form.
|
|
390
|
+
// Index the reverse edges once so a chain declared outermost-first does
|
|
391
|
+
// not rescan every declaration per link.
|
|
382
392
|
for (const item of declaration.declarations || []) {
|
|
383
393
|
const init = item.init;
|
|
384
394
|
if (
|
|
@@ -389,17 +399,9 @@ export function findVoidComponentExports(source, id) {
|
|
|
389
399
|
) {
|
|
390
400
|
voidBindings.add(item.id.name);
|
|
391
401
|
}
|
|
392
|
-
|
|
393
|
-
item.id?.type
|
|
394
|
-
|
|
395
|
-
init?.type !== 'CallExpression' ||
|
|
396
|
-
init.callee?.type !== 'Identifier' ||
|
|
397
|
-
!memoLocals.has(init.callee.name) ||
|
|
398
|
-
init.arguments?.length !== 1 ||
|
|
399
|
-
init.arguments[0]?.type !== 'Identifier'
|
|
400
|
-
)
|
|
401
|
-
continue;
|
|
402
|
-
const target = init.arguments[0].name;
|
|
402
|
+
const target =
|
|
403
|
+
item.id?.type === 'Identifier' && !reassigned.has(item.id) ? memoTarget(init) : null;
|
|
404
|
+
if (target === null) continue;
|
|
403
405
|
let dependents = memoDependents.get(target);
|
|
404
406
|
if (dependents === undefined) memoDependents.set(target, (dependents = []));
|
|
405
407
|
dependents.push(item.id.name);
|
|
@@ -418,12 +420,17 @@ export function findVoidComponentExports(source, id) {
|
|
|
418
420
|
for (const node of ast.body || []) {
|
|
419
421
|
if (node.type === 'ExportDefaultDeclaration') {
|
|
420
422
|
const declaration = node.declaration;
|
|
423
|
+
// React's `export default Local` and `export default memo(Local)` export
|
|
424
|
+
// a local binding's value, so they carry that binding's proof.
|
|
421
425
|
if (
|
|
422
|
-
(declaration?.type === 'FunctionDeclaration' ||
|
|
426
|
+
((declaration?.type === 'FunctionDeclaration' ||
|
|
423
427
|
declaration?.type === 'FunctionExpression' ||
|
|
424
428
|
declaration?.type === 'ArrowFunctionExpression') &&
|
|
425
|
-
|
|
426
|
-
|
|
429
|
+
(declaration.id == null || !reassigned.has(declaration.id)) &&
|
|
430
|
+
isVoidFunction(declaration)) ||
|
|
431
|
+
voidBindings.has(
|
|
432
|
+
declaration?.type === 'Identifier' ? declaration.name : memoTarget(declaration),
|
|
433
|
+
)
|
|
427
434
|
) {
|
|
428
435
|
exports.push('default');
|
|
429
436
|
}
|