Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
daab9e33b2 | ||
|
|
e33b13795d | ||
|
|
4beb1fd8ba | ||
|
|
047d95e85f | ||
|
|
92c0f5f85f | ||
|
|
053b3cb050 | ||
|
|
7dd6b9e68a | ||
|
|
d8afd1c82e | ||
|
|
0480cdb58c | ||
|
|
0f3c62b466 | ||
|
|
858633f900 | ||
|
|
c09402aa2f | ||
|
|
4972718c26 | ||
|
|
3720870a97 | ||
|
|
e1ef8c9515 | ||
|
|
8a41d6ceab | ||
|
|
63cde684f5 | ||
|
|
b01722d585 | ||
|
|
c13986da78 | ||
|
|
4686872159 | ||
|
|
5d89471ca6 | ||
|
|
3c15d219aa | ||
|
|
3644f0bd21 | ||
|
|
8657869999 | ||
|
|
b15135b9f5 |
4
.github/workflows/runtime_build_and_test.yml
vendored
4
.github/workflows/runtime_build_and_test.yml
vendored
@@ -3,10 +3,6 @@ name: (Runtime) Build and Test
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
tags:
|
||||
# To get CI for backport releases.
|
||||
# This will duplicate CI for releases from main which is acceptable
|
||||
- "v*"
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- compiler/**
|
||||
|
||||
@@ -27,7 +27,7 @@ jobs:
|
||||
# because this used to be called the "next" channel and some
|
||||
# downstream consumers might still expect that tag. We can remove this
|
||||
# after some time has elapsed and the change has been communicated.
|
||||
dist_tag: canary,next,rc
|
||||
dist_tag: canary,next
|
||||
secrets:
|
||||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ jobs:
|
||||
with:
|
||||
commit_sha: ${{ github.sha }}
|
||||
release_channel: stable
|
||||
dist_tag: canary,next,rc
|
||||
dist_tag: canary,next
|
||||
secrets:
|
||||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
|
||||
|
||||
@@ -7,18 +7,18 @@
|
||||
//
|
||||
// The @latest channel uses the version as-is, e.g.:
|
||||
//
|
||||
// 19.0.5
|
||||
// 19.0.0
|
||||
//
|
||||
// The @canary channel appends additional information, with the scheme
|
||||
// <version>-<label>-<commit_sha>, e.g.:
|
||||
//
|
||||
// 19.0.5-canary-a1c2d3e4
|
||||
// 19.0.0-canary-a1c2d3e4
|
||||
//
|
||||
// The @experimental channel doesn't include a version, only a date and a sha, e.g.:
|
||||
//
|
||||
// 0.0.0-experimental-241c4467e-20200129
|
||||
|
||||
const ReactVersion = '19.0.5';
|
||||
const ReactVersion = '19.0.0';
|
||||
|
||||
// The label used by the @canary channel. Represents the upcoming release's
|
||||
// stability. Most of the time, this will be "canary", but we may temporarily
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
"main": "dist/index.js",
|
||||
"license": "MIT",
|
||||
"files": [
|
||||
"dist"
|
||||
"dist",
|
||||
"!*.tsbuildinfo"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "rimraf dist && rollup --config --bundleConfigAsCjs",
|
||||
|
||||
@@ -28,6 +28,7 @@ const DEV_ROLLUP_CONFIG = {
|
||||
plugins: [
|
||||
typescript({
|
||||
tsconfig: './tsconfig.json',
|
||||
outputToFilesystem: true,
|
||||
compilerOptions: {
|
||||
noEmit: true,
|
||||
},
|
||||
|
||||
@@ -3186,7 +3186,13 @@ function lowerJsxMemberExpression(
|
||||
loc: object.node.loc ?? null,
|
||||
suggestions: null,
|
||||
});
|
||||
objectPlace = lowerIdentifier(builder, object);
|
||||
|
||||
const kind = getLoadKind(builder, object);
|
||||
objectPlace = lowerValueToTemporary(builder, {
|
||||
kind: kind,
|
||||
place: lowerIdentifier(builder, object),
|
||||
loc: exprPath.node.loc ?? GeneratedSource,
|
||||
});
|
||||
}
|
||||
const property = exprPath.get('property').node.name;
|
||||
return lowerValueToTemporary(builder, {
|
||||
|
||||
@@ -231,6 +231,8 @@ const EnvironmentConfigSchema = z.object({
|
||||
*/
|
||||
enableUseTypeAnnotations: z.boolean().default(false),
|
||||
|
||||
enableFunctionDependencyRewrite: z.boolean().default(true),
|
||||
|
||||
/**
|
||||
* Enables inlining ReactElement object literals in place of JSX
|
||||
* An alternative to the standard JSX transform which replaces JSX with React's jsxProd() runtime
|
||||
@@ -455,9 +457,10 @@ const EnvironmentConfigSchema = z.object({
|
||||
throwUnknownException__testonly: z.boolean().default(false),
|
||||
|
||||
/**
|
||||
* Enables deps of a function epxression to be treated as conditional. This
|
||||
* makes sure we don't load a dep when it's a property (to check if it has
|
||||
* changed) and instead check the receiver.
|
||||
* Enables deps of a function expression to be treated as conditional. This
|
||||
* makes sure we don't hoist property loads from function expressions when we
|
||||
* don't know that the property load source object is safe to access in the
|
||||
* outer context
|
||||
*
|
||||
* This makes sure we don't end up throwing when the reciver is null. Consider
|
||||
* this code:
|
||||
@@ -473,8 +476,14 @@ const EnvironmentConfigSchema = z.object({
|
||||
*
|
||||
* This does cause the memoization to now be coarse grained, which is
|
||||
* non-ideal.
|
||||
*
|
||||
* This is safe to toggle off for a codebase that has no sources of
|
||||
* unsoundness. This includes:
|
||||
* - typing array accesses / other unknown keys as TValue | undefined
|
||||
* (typescript's noUncheckedIndexedAccess)
|
||||
* - enabling and monitoring warnings for explicit and inferred `any`
|
||||
*/
|
||||
enableTreatFunctionDepsAsConditional: z.boolean().default(false),
|
||||
enableTreatFunctionDepsAsConditional: z.boolean().default(true),
|
||||
|
||||
/**
|
||||
* When true, always act as though the dependencies of a memoized value
|
||||
|
||||
@@ -440,14 +440,6 @@ class Context {
|
||||
|
||||
// Checks if identifier is a valid dependency in the current scope
|
||||
#checkValidDependency(maybeDependency: ReactiveScopeDependency): boolean {
|
||||
// ref.current access is not a valid dep
|
||||
if (
|
||||
isUseRefType(maybeDependency.identifier) &&
|
||||
maybeDependency.path.at(0)?.property === 'current'
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// ref value is not a valid dep
|
||||
if (isRefValueType(maybeDependency.identifier)) {
|
||||
return false;
|
||||
@@ -549,6 +541,16 @@ class Context {
|
||||
});
|
||||
}
|
||||
|
||||
// ref.current access is not a valid dep
|
||||
if (
|
||||
isUseRefType(maybeDependency.identifier) &&
|
||||
maybeDependency.path.at(0)?.property === 'current'
|
||||
) {
|
||||
maybeDependency = {
|
||||
identifier: maybeDependency.identifier,
|
||||
path: [],
|
||||
};
|
||||
}
|
||||
if (this.#checkValidDependency(maybeDependency)) {
|
||||
this.#dependencies.value!.push(maybeDependency);
|
||||
}
|
||||
@@ -661,35 +663,54 @@ function collectDependencies(
|
||||
|
||||
const scopeTraversal = new ScopeBlockTraversal();
|
||||
|
||||
for (const [blockId, block] of fn.body.blocks) {
|
||||
scopeTraversal.recordScopes(block);
|
||||
const scopeBlockInfo = scopeTraversal.blockInfos.get(blockId);
|
||||
if (scopeBlockInfo?.kind === 'begin') {
|
||||
context.enterScope(scopeBlockInfo.scope);
|
||||
} else if (scopeBlockInfo?.kind === 'end') {
|
||||
context.exitScope(scopeBlockInfo.scope, scopeBlockInfo?.pruned);
|
||||
}
|
||||
const handleFunction = (fn: HIRFunction): void => {
|
||||
for (const [blockId, block] of fn.body.blocks) {
|
||||
scopeTraversal.recordScopes(block);
|
||||
const scopeBlockInfo = scopeTraversal.blockInfos.get(blockId);
|
||||
if (scopeBlockInfo?.kind === 'begin') {
|
||||
context.enterScope(scopeBlockInfo.scope);
|
||||
} else if (scopeBlockInfo?.kind === 'end') {
|
||||
context.exitScope(scopeBlockInfo.scope, scopeBlockInfo.pruned);
|
||||
}
|
||||
// Record referenced optional chains in phis
|
||||
for (const phi of block.phis) {
|
||||
for (const operand of phi.operands) {
|
||||
const maybeOptionalChain = temporaries.get(operand[1].identifier.id);
|
||||
if (maybeOptionalChain) {
|
||||
context.visitDependency(maybeOptionalChain);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const instr of block.instructions) {
|
||||
if (
|
||||
fn.env.config.enableFunctionDependencyRewrite &&
|
||||
(instr.value.kind === 'FunctionExpression' ||
|
||||
instr.value.kind === 'ObjectMethod')
|
||||
) {
|
||||
context.declare(instr.lvalue.identifier, {
|
||||
id: instr.id,
|
||||
scope: context.currentScope,
|
||||
});
|
||||
/**
|
||||
* Recursively visit the inner function to extract dependencies there
|
||||
*/
|
||||
const wasInInnerFn = context.inInnerFn;
|
||||
context.inInnerFn = true;
|
||||
handleFunction(instr.value.loweredFunc.func);
|
||||
context.inInnerFn = wasInInnerFn;
|
||||
} else if (!processedInstrsInOptional.has(instr)) {
|
||||
handleInstruction(instr, context);
|
||||
}
|
||||
}
|
||||
|
||||
// Record referenced optional chains in phis
|
||||
for (const phi of block.phis) {
|
||||
for (const operand of phi.operands) {
|
||||
const maybeOptionalChain = temporaries.get(operand[1].identifier.id);
|
||||
if (maybeOptionalChain) {
|
||||
context.visitDependency(maybeOptionalChain);
|
||||
if (!processedInstrsInOptional.has(block.terminal)) {
|
||||
for (const place of eachTerminalOperand(block.terminal)) {
|
||||
context.visitOperand(place);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const instr of block.instructions) {
|
||||
if (!processedInstrsInOptional.has(instr)) {
|
||||
handleInstruction(instr, context);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (!processedInstrsInOptional.has(block.terminal)) {
|
||||
for (const place of eachTerminalOperand(block.terminal)) {
|
||||
context.visitOperand(place);
|
||||
}
|
||||
}
|
||||
}
|
||||
handleFunction(fn);
|
||||
return context.deps;
|
||||
}
|
||||
|
||||
@@ -58,6 +58,14 @@ export function deadCodeElimination(fn: HIRFunction): void {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constant propagation and DCE may have deleted or rewritten instructions
|
||||
* that reference context variables.
|
||||
*/
|
||||
retainWhere(fn.context, contextVar =>
|
||||
state.isIdOrNameUsed(contextVar.identifier),
|
||||
);
|
||||
}
|
||||
|
||||
class State {
|
||||
|
||||
@@ -559,28 +559,45 @@ function createPropsProperties(
|
||||
propAttributes.forEach(prop => {
|
||||
switch (prop.kind) {
|
||||
case 'JsxAttribute': {
|
||||
if (prop.name === 'ref') {
|
||||
refProperty = {
|
||||
kind: 'ObjectProperty',
|
||||
key: {name: 'ref', kind: 'string'},
|
||||
type: 'property',
|
||||
place: {...prop.place},
|
||||
};
|
||||
} else if (prop.name === 'key') {
|
||||
keyProperty = {
|
||||
kind: 'ObjectProperty',
|
||||
key: {name: 'key', kind: 'string'},
|
||||
type: 'property',
|
||||
place: {...prop.place},
|
||||
};
|
||||
} else {
|
||||
const attributeProperty: ObjectProperty = {
|
||||
kind: 'ObjectProperty',
|
||||
key: {name: prop.name, kind: 'string'},
|
||||
type: 'property',
|
||||
place: {...prop.place},
|
||||
};
|
||||
props.push(attributeProperty);
|
||||
switch (prop.name) {
|
||||
case 'key': {
|
||||
keyProperty = {
|
||||
kind: 'ObjectProperty',
|
||||
key: {name: 'key', kind: 'string'},
|
||||
type: 'property',
|
||||
place: {...prop.place},
|
||||
};
|
||||
break;
|
||||
}
|
||||
case 'ref': {
|
||||
/**
|
||||
* In the current JSX implementation, ref is both
|
||||
* a property on the element and a property on props.
|
||||
*/
|
||||
refProperty = {
|
||||
kind: 'ObjectProperty',
|
||||
key: {name: 'ref', kind: 'string'},
|
||||
type: 'property',
|
||||
place: {...prop.place},
|
||||
};
|
||||
const refPropProperty: ObjectProperty = {
|
||||
kind: 'ObjectProperty',
|
||||
key: {name: 'ref', kind: 'string'},
|
||||
type: 'property',
|
||||
place: {...prop.place},
|
||||
};
|
||||
props.push(refPropProperty);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
const attributeProperty: ObjectProperty = {
|
||||
kind: 'ObjectProperty',
|
||||
key: {name: prop.name, kind: 'string'},
|
||||
type: 'property',
|
||||
place: {...prop.place},
|
||||
};
|
||||
props.push(attributeProperty);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -12,6 +12,8 @@ import {
|
||||
PrunedReactiveScopeBlock,
|
||||
ReactiveFunction,
|
||||
isPrimitiveType,
|
||||
isUseRefType,
|
||||
Identifier,
|
||||
} from '../HIR/HIR';
|
||||
import {ReactiveFunctionVisitor, visitReactiveFunction} from './visitors';
|
||||
|
||||
@@ -50,13 +52,21 @@ class Visitor extends ReactiveFunctionVisitor<Set<IdentifierId>> {
|
||||
this.traversePrunedScope(scopeBlock, state);
|
||||
|
||||
for (const [id, decl] of scopeBlock.scope.declarations) {
|
||||
if (!isPrimitiveType(decl.identifier)) {
|
||||
if (
|
||||
!isPrimitiveType(decl.identifier) &&
|
||||
!isStableRefType(decl.identifier, state)
|
||||
) {
|
||||
state.add(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function isStableRefType(
|
||||
identifier: Identifier,
|
||||
reactiveIdentifiers: Set<IdentifierId>,
|
||||
): boolean {
|
||||
return isUseRefType(identifier) && !reactiveIdentifiers.has(identifier.id);
|
||||
}
|
||||
/*
|
||||
* Computes a set of identifiers which are reactive, using the analysis previously performed
|
||||
* in `InferReactivePlaces`.
|
||||
|
||||
@@ -28,7 +28,7 @@ function Component() {
|
||||
t0 = () => {
|
||||
"worklet";
|
||||
|
||||
setCount((count_0) => count_0 + 1);
|
||||
setCount(_temp);
|
||||
};
|
||||
$[0] = t0;
|
||||
} else {
|
||||
@@ -45,6 +45,9 @@ function Component() {
|
||||
}
|
||||
return t1;
|
||||
}
|
||||
function _temp(count_0) {
|
||||
return count_0 + 1;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
@@ -75,9 +75,9 @@ function useFoo(t0) {
|
||||
arrayPush(x, y);
|
||||
const y_alias = y;
|
||||
let t2;
|
||||
if ($[3] !== y_alias.value) {
|
||||
if ($[3] !== y_alias) {
|
||||
t2 = () => y_alias.value;
|
||||
$[3] = y_alias.value;
|
||||
$[3] = y_alias;
|
||||
$[4] = t2;
|
||||
} else {
|
||||
t2 = $[4];
|
||||
|
||||
@@ -56,9 +56,9 @@ function useFoo(t0) {
|
||||
setPropertyByKey(obj, "arr", arr);
|
||||
const obj_alias = obj;
|
||||
let t2;
|
||||
if ($[2] !== obj_alias.arr.length) {
|
||||
if ($[2] !== obj_alias) {
|
||||
t2 = () => obj_alias.arr.length;
|
||||
$[2] = obj_alias.arr.length;
|
||||
$[2] = obj_alias;
|
||||
$[3] = t2;
|
||||
} else {
|
||||
t2 = $[3];
|
||||
|
||||
@@ -1,89 +0,0 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
import {useRef} from 'react';
|
||||
import {Stringify} from 'shared-runtime';
|
||||
|
||||
/**
|
||||
* Bug: we're currently filtering out `ref.current` dependencies in
|
||||
* `propagateScopeDependencies:checkValidDependency`. This is incorrect.
|
||||
* Instead, we should always take a dependency on ref values (the outer box) as
|
||||
* they may be reactive. Pruning should be done in
|
||||
* `pruneNonReactiveDependencies`
|
||||
*
|
||||
* Found differences in evaluator results
|
||||
* Non-forget (expected):
|
||||
* (kind: ok)
|
||||
* <div>{"cb":{"kind":"Function","result":1},"shouldInvokeFns":true}</div>
|
||||
* <div>{"cb":{"kind":"Function","result":2},"shouldInvokeFns":true}</div>
|
||||
* Forget:
|
||||
* (kind: ok)
|
||||
* <div>{"cb":{"kind":"Function","result":1},"shouldInvokeFns":true}</div>
|
||||
* <div>{"cb":{"kind":"Function","result":1},"shouldInvokeFns":true}</div>
|
||||
*/
|
||||
function Component({cond}) {
|
||||
const ref1 = useRef(1);
|
||||
const ref2 = useRef(2);
|
||||
const ref = cond ? ref1 : ref2;
|
||||
const cb = () => ref.current;
|
||||
return <Stringify cb={cb} shouldInvokeFns={true} />;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{cond: true}],
|
||||
sequentialRenders: [{cond: true}, {cond: false}],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
import { useRef } from "react";
|
||||
import { Stringify } from "shared-runtime";
|
||||
|
||||
/**
|
||||
* Bug: we're currently filtering out `ref.current` dependencies in
|
||||
* `propagateScopeDependencies:checkValidDependency`. This is incorrect.
|
||||
* Instead, we should always take a dependency on ref values (the outer box) as
|
||||
* they may be reactive. Pruning should be done in
|
||||
* `pruneNonReactiveDependencies`
|
||||
*
|
||||
* Found differences in evaluator results
|
||||
* Non-forget (expected):
|
||||
* (kind: ok)
|
||||
* <div>{"cb":{"kind":"Function","result":1},"shouldInvokeFns":true}</div>
|
||||
* <div>{"cb":{"kind":"Function","result":2},"shouldInvokeFns":true}</div>
|
||||
* Forget:
|
||||
* (kind: ok)
|
||||
* <div>{"cb":{"kind":"Function","result":1},"shouldInvokeFns":true}</div>
|
||||
* <div>{"cb":{"kind":"Function","result":1},"shouldInvokeFns":true}</div>
|
||||
*/
|
||||
function Component(t0) {
|
||||
const $ = _c(1);
|
||||
const { cond } = t0;
|
||||
const ref1 = useRef(1);
|
||||
const ref2 = useRef(2);
|
||||
const ref = cond ? ref1 : ref2;
|
||||
let t1;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
const cb = () => ref.current;
|
||||
t1 = <Stringify cb={cb} shouldInvokeFns={true} />;
|
||||
$[0] = t1;
|
||||
} else {
|
||||
t1 = $[0];
|
||||
}
|
||||
return t1;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{ cond: true }],
|
||||
sequentialRenders: [{ cond: true }, { cond: false }],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
import {useRef} from 'react';
|
||||
import {Stringify} from 'shared-runtime';
|
||||
|
||||
/**
|
||||
* Bug: we're currently filtering out `ref.current` dependencies in
|
||||
* `propagateScopeDependencies:checkValidDependency`. This is incorrect.
|
||||
* Instead, we should always take a dependency on ref values (the outer box) as
|
||||
* they may be reactive. Pruning should be done in
|
||||
* `pruneNonReactiveDependencies`
|
||||
*
|
||||
* Found differences in evaluator results
|
||||
* Non-forget (expected):
|
||||
* (kind: ok)
|
||||
* <div>{"cb":{"kind":"Function","result":1},"shouldInvokeFns":true}</div>
|
||||
* <div>{"cb":{"kind":"Function","result":2},"shouldInvokeFns":true}</div>
|
||||
* Forget:
|
||||
* (kind: ok)
|
||||
* <div>{"cb":{"kind":"Function","result":1},"shouldInvokeFns":true}</div>
|
||||
* <div>{"cb":{"kind":"Function","result":1},"shouldInvokeFns":true}</div>
|
||||
*/
|
||||
function Component({cond}) {
|
||||
const ref1 = useRef(1);
|
||||
const ref2 = useRef(2);
|
||||
const ref = cond ? ref1 : ref2;
|
||||
const cb = () => ref.current;
|
||||
return <Stringify cb={cb} shouldInvokeFns={true} />;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{cond: true}],
|
||||
sequentialRenders: [{cond: true}, {cond: false}],
|
||||
};
|
||||
@@ -0,0 +1,114 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
import {arrayPush, CONST_NUMBER0, mutate} from 'shared-runtime';
|
||||
|
||||
/**
|
||||
* Repro for bug in our type inference system. We currently propagate inferred
|
||||
* types through control flow / potential type guards. Note that this is
|
||||
* inconsistent with both Flow and Typescript.
|
||||
* https://flow.org/try/#1N4Igxg9gdgZglgcxALlAIwIZoKYBsD6uEEAztvhgE6UYCe+JADpdhgCYowa5kA0I2KAFcAtiRQAXSkOz9sADwxgJ+NPTbYuQ3BMnTZA+Y2yU4IwRO4A6SFBIrGVDGM7c+h46fNRLuKxJIGWh8MeT0ZfhYlCStpHzNsFBAMIQkIEQwJODAQfiEyfBE4eWw2fDgofDBMsAALfAA3KjgsXGxxZC4eAw0G-GhcWn9aY3wWZldu-g1mbGqJUoBaCRHEzrcDEgBrbAk62kXhXFxJ923d-cPRHEpTgyEoMDaqZdW7vKgoOfaSKgOKpqmDA+d4gB5fMA-P6LCCMLLQbiLOoYCqgh6-GDYRYIXYLSgkRZkCR4jpddwPfJLZjpOBkO4AX34kA0SRWxgABAAxYjsgC87OAAB0oOzReythU2Mh2YKQNyILLeMKxeymrgZNLhCIbsL6QBuYVs7DsgBCVD5AuVYolUClMpAZsoiqtorVGvZWpuSqg9OFMAeyjg0HZdTmW3lAAp5NKAPJoABWcwkAEppWZGLg4O12fJ2bSuTyhSKxSwJEJKCKAOQ2tiVvMi3MAMkbOasNb5vP5svlsoNPuFfoD8JFGQqUel8vZAB9TVReCHoHa0MRnlBUwWIJbi6K4DB2RHbGxk1uVSrd-uAIShsDh4hR5PHoun5-siS1SgQADuHuw34AotQECUBGsqysmfYvuyvrbqepblg2EFitBKpwRWOZ9vSuQgA0JgkEGUBJBk9gmCA9JAA
|
||||
* https://www.typescriptlang.org/play/?#code/C4TwDgpgBAYg9nKBeKBvAUFLUDWBLAOwBMAuKAInjnIBpNsA3AQwBsBXCMgtgWwCMIAJ3QBfANzpQkKACEmg5GnpZ8xMuTmDayqM3aco3fkLoj0AMzYEAxsDxwCUawAsI1nFQAUADzJw+AFZuwACUZEwAzhFCwBFQ3lB4cVRK2InmUJ4AhJ4A5KpEuYmOCQBkpfEAdAXISCiUCOQhIalp2MDOgnAA7oYQvQCigl2CnuRWEN6QthBETTpmZhZWtvaOPEyEPmQpAD6y8jRODqRQfAgsEEwEYbAIrVh4GZ7WJy0Ybdgubh4IPiEST5YQQQYBsQQlQHYMxpEFgiHxCQiIA
|
||||
*
|
||||
* Found differences in evaluator results
|
||||
* Non-forget (expected):
|
||||
* (kind: ok)
|
||||
* [2]
|
||||
* [3]
|
||||
* Forget:
|
||||
* (kind: ok)
|
||||
* [2]
|
||||
* [2,3]
|
||||
*/
|
||||
function useFoo({cond, value}: {cond: boolean; value: number}) {
|
||||
const x = {value: cond ? CONST_NUMBER0 : []};
|
||||
mutate(x);
|
||||
|
||||
const xValue = x.value;
|
||||
let result;
|
||||
if (typeof xValue === 'number') {
|
||||
result = xValue + 1; // (1) here we infer xValue is a primitive
|
||||
} else {
|
||||
result = arrayPush(xValue, value); // (2) and propagate it to all other xValue references
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: useFoo,
|
||||
params: [{cond: true}],
|
||||
sequentialRenders: [
|
||||
{cond: false, value: 2},
|
||||
{cond: false, value: 3},
|
||||
],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
import { arrayPush, CONST_NUMBER0, mutate } from "shared-runtime";
|
||||
|
||||
/**
|
||||
* Repro for bug in our type inference system. We currently propagate inferred
|
||||
* types through control flow / potential type guards. Note that this is
|
||||
* inconsistent with both Flow and Typescript.
|
||||
* https://flow.org/try/#1N4Igxg9gdgZglgcxALlAIwIZoKYBsD6uEEAztvhgE6UYCe+JADpdhgCYowa5kA0I2KAFcAtiRQAXSkOz9sADwxgJ+NPTbYuQ3BMnTZA+Y2yU4IwRO4A6SFBIrGVDGM7c+h46fNRLuKxJIGWh8MeT0ZfhYlCStpHzNsFBAMIQkIEQwJODAQfiEyfBE4eWw2fDgofDBMsAALfAA3KjgsXGxxZC4eAw0G-GhcWn9aY3wWZldu-g1mbGqJUoBaCRHEzrcDEgBrbAk62kXhXFxJ923d-cPRHEpTgyEoMDaqZdW7vKgoOfaSKgOKpqmDA+d4gB5fMA-P6LCCMLLQbiLOoYCqgh6-GDYRYIXYLSgkRZkCR4jpddwPfJLZjpOBkO4AX34kA0SRWxgABAAxYjsgC87OAAB0oOzReythU2Mh2YKQNyILLeMKxeymrgZNLhCIbsL6QBuYVs7DsgBCVD5AuVYolUClMpAZsoiqtorVGvZWpuSqg9OFMAeyjg0HZdTmW3lAAp5NKAPJoABWcwkAEppWZGLg4O12fJ2bSuTyhSKxSwJEJKCKAOQ2tiVvMi3MAMkbOasNb5vP5svlsoNPuFfoD8JFGQqUel8vZAB9TVReCHoHa0MRnlBUwWIJbi6K4DB2RHbGxk1uVSrd-uAIShsDh4hR5PHoun5-siS1SgQADuHuw34AotQECUBGsqysmfYvuyvrbqepblg2EFitBKpwRWOZ9vSuQgA0JgkEGUBJBk9gmCA9JAA
|
||||
* https://www.typescriptlang.org/play/?#code/C4TwDgpgBAYg9nKBeKBvAUFLUDWBLAOwBMAuKAInjnIBpNsA3AQwBsBXCMgtgWwCMIAJ3QBfANzpQkKACEmg5GnpZ8xMuTmDayqM3aco3fkLoj0AMzYEAxsDxwCUawAsI1nFQAUADzJw+AFZuwACUZEwAzhFCwBFQ3lB4cVRK2InmUJ4AhJ4A5KpEuYmOCQBkpfEAdAXISCiUCOQhIalp2MDOgnAA7oYQvQCigl2CnuRWEN6QthBETTpmZhZWtvaOPEyEPmQpAD6y8jRODqRQfAgsEEwEYbAIrVh4GZ7WJy0Ybdgubh4IPiEST5YQQQYBsQQlQHYMxpEFgiHxCQiIA
|
||||
*
|
||||
* Found differences in evaluator results
|
||||
* Non-forget (expected):
|
||||
* (kind: ok)
|
||||
* [2]
|
||||
* [3]
|
||||
* Forget:
|
||||
* (kind: ok)
|
||||
* [2]
|
||||
* [2,3]
|
||||
*/
|
||||
function useFoo(t0) {
|
||||
const $ = _c(5);
|
||||
const { cond, value } = t0;
|
||||
let x;
|
||||
if ($[0] !== cond) {
|
||||
x = { value: cond ? CONST_NUMBER0 : [] };
|
||||
mutate(x);
|
||||
$[0] = cond;
|
||||
$[1] = x;
|
||||
} else {
|
||||
x = $[1];
|
||||
}
|
||||
|
||||
const xValue = x.value;
|
||||
let result;
|
||||
if (typeof xValue === "number") {
|
||||
result = xValue + 1;
|
||||
} else {
|
||||
let t1;
|
||||
if ($[2] !== value || $[3] !== xValue) {
|
||||
t1 = arrayPush(xValue, value);
|
||||
$[2] = value;
|
||||
$[3] = xValue;
|
||||
$[4] = t1;
|
||||
} else {
|
||||
t1 = $[4];
|
||||
}
|
||||
result = t1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: useFoo,
|
||||
params: [{ cond: true }],
|
||||
sequentialRenders: [
|
||||
{ cond: false, value: 2 },
|
||||
{ cond: false, value: 3 },
|
||||
],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
import {arrayPush, CONST_NUMBER0, mutate} from 'shared-runtime';
|
||||
|
||||
/**
|
||||
* Repro for bug in our type inference system. We currently propagate inferred
|
||||
* types through control flow / potential type guards. Note that this is
|
||||
* inconsistent with both Flow and Typescript.
|
||||
* https://flow.org/try/#1N4Igxg9gdgZglgcxALlAIwIZoKYBsD6uEEAztvhgE6UYCe+JADpdhgCYowa5kA0I2KAFcAtiRQAXSkOz9sADwxgJ+NPTbYuQ3BMnTZA+Y2yU4IwRO4A6SFBIrGVDGM7c+h46fNRLuKxJIGWh8MeT0ZfhYlCStpHzNsFBAMIQkIEQwJODAQfiEyfBE4eWw2fDgofDBMsAALfAA3KjgsXGxxZC4eAw0G-GhcWn9aY3wWZldu-g1mbGqJUoBaCRHEzrcDEgBrbAk62kXhXFxJ923d-cPRHEpTgyEoMDaqZdW7vKgoOfaSKgOKpqmDA+d4gB5fMA-P6LCCMLLQbiLOoYCqgh6-GDYRYIXYLSgkRZkCR4jpddwPfJLZjpOBkO4AX34kA0SRWxgABAAxYjsgC87OAAB0oOzReythU2Mh2YKQNyILLeMKxeymrgZNLhCIbsL6QBuYVs7DsgBCVD5AuVYolUClMpAZsoiqtorVGvZWpuSqg9OFMAeyjg0HZdTmW3lAAp5NKAPJoABWcwkAEppWZGLg4O12fJ2bSuTyhSKxSwJEJKCKAOQ2tiVvMi3MAMkbOasNb5vP5svlsoNPuFfoD8JFGQqUel8vZAB9TVReCHoHa0MRnlBUwWIJbi6K4DB2RHbGxk1uVSrd-uAIShsDh4hR5PHoun5-siS1SgQADuHuw34AotQECUBGsqysmfYvuyvrbqepblg2EFitBKpwRWOZ9vSuQgA0JgkEGUBJBk9gmCA9JAA
|
||||
* https://www.typescriptlang.org/play/?#code/C4TwDgpgBAYg9nKBeKBvAUFLUDWBLAOwBMAuKAInjnIBpNsA3AQwBsBXCMgtgWwCMIAJ3QBfANzpQkKACEmg5GnpZ8xMuTmDayqM3aco3fkLoj0AMzYEAxsDxwCUawAsI1nFQAUADzJw+AFZuwACUZEwAzhFCwBFQ3lB4cVRK2InmUJ4AhJ4A5KpEuYmOCQBkpfEAdAXISCiUCOQhIalp2MDOgnAA7oYQvQCigl2CnuRWEN6QthBETTpmZhZWtvaOPEyEPmQpAD6y8jRODqRQfAgsEEwEYbAIrVh4GZ7WJy0Ybdgubh4IPiEST5YQQQYBsQQlQHYMxpEFgiHxCQiIA
|
||||
*
|
||||
* Found differences in evaluator results
|
||||
* Non-forget (expected):
|
||||
* (kind: ok)
|
||||
* [2]
|
||||
* [3]
|
||||
* Forget:
|
||||
* (kind: ok)
|
||||
* [2]
|
||||
* [2,3]
|
||||
*/
|
||||
function useFoo({cond, value}: {cond: boolean; value: number}) {
|
||||
const x = {value: cond ? CONST_NUMBER0 : []};
|
||||
mutate(x);
|
||||
|
||||
const xValue = x.value;
|
||||
let result;
|
||||
if (typeof xValue === 'number') {
|
||||
result = xValue + 1; // (1) here we infer xValue is a primitive
|
||||
} else {
|
||||
result = arrayPush(xValue, value); // (2) and propagate it to all other xValue references
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: useFoo,
|
||||
params: [{cond: true}],
|
||||
sequentialRenders: [
|
||||
{cond: false, value: 2},
|
||||
{cond: false, value: 3},
|
||||
],
|
||||
};
|
||||
@@ -55,11 +55,7 @@ function getNativeLogFunction(level) {
|
||||
if (arguments.length === 1 && typeof arguments[0] === "string") {
|
||||
str = arguments[0];
|
||||
} else {
|
||||
str = Array.prototype.map
|
||||
.call(arguments, function (arg) {
|
||||
return inspect(arg, { depth: 10 });
|
||||
})
|
||||
.join(", ");
|
||||
str = Array.prototype.map.call(arguments, _temp).join(", ");
|
||||
}
|
||||
|
||||
const firstArg = arguments[0];
|
||||
@@ -92,6 +88,9 @@ function getNativeLogFunction(level) {
|
||||
}
|
||||
return t0;
|
||||
}
|
||||
function _temp(arg) {
|
||||
return inspect(arg, { depth: 10 });
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
@@ -2,39 +2,55 @@
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
function component(foo, bar) {
|
||||
import {mutate} from 'shared-runtime';
|
||||
|
||||
function Component({foo, bar}) {
|
||||
let x = {foo};
|
||||
let y = {bar};
|
||||
const f0 = function () {
|
||||
let a = {y};
|
||||
let a = [y];
|
||||
let b = x;
|
||||
a.x = b;
|
||||
// this writes y.x = x
|
||||
a[0].x = b;
|
||||
};
|
||||
f0();
|
||||
mutate(y);
|
||||
mutate(y.x);
|
||||
return y;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{foo: 3, bar: 4}],
|
||||
sequentialRenders: [
|
||||
{foo: 3, bar: 4},
|
||||
{foo: 3, bar: 5},
|
||||
],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
function component(foo, bar) {
|
||||
import { mutate } from "shared-runtime";
|
||||
|
||||
function Component(t0) {
|
||||
const $ = _c(3);
|
||||
const { foo, bar } = t0;
|
||||
let y;
|
||||
if ($[0] !== bar || $[1] !== foo) {
|
||||
const x = { foo };
|
||||
y = { bar };
|
||||
const f0 = function () {
|
||||
const a = { y };
|
||||
const a = [y];
|
||||
const b = x;
|
||||
a.x = b;
|
||||
|
||||
a[0].x = b;
|
||||
};
|
||||
|
||||
f0();
|
||||
mutate(y);
|
||||
mutate(y.x);
|
||||
$[0] = bar;
|
||||
$[1] = foo;
|
||||
$[2] = y;
|
||||
@@ -44,5 +60,17 @@ function component(foo, bar) {
|
||||
return y;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{ foo: 3, bar: 4 }],
|
||||
sequentialRenders: [
|
||||
{ foo: 3, bar: 4 },
|
||||
{ foo: 3, bar: 5 },
|
||||
],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
|
||||
### Eval output
|
||||
(kind: ok) {"bar":4,"x":{"foo":3,"wat0":"joe"}}
|
||||
{"bar":5,"x":{"foo":3,"wat0":"joe"}}
|
||||
@@ -1,12 +1,24 @@
|
||||
function component(foo, bar) {
|
||||
import {mutate} from 'shared-runtime';
|
||||
|
||||
function Component({foo, bar}) {
|
||||
let x = {foo};
|
||||
let y = {bar};
|
||||
const f0 = function () {
|
||||
let a = {y};
|
||||
let a = [y];
|
||||
let b = x;
|
||||
a.x = b;
|
||||
// this writes y.x = x
|
||||
a[0].x = b;
|
||||
};
|
||||
f0();
|
||||
mutate(y);
|
||||
mutate(y.x);
|
||||
return y;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{foo: 3, bar: 4}],
|
||||
sequentialRenders: [
|
||||
{foo: 3, bar: 4},
|
||||
{foo: 3, bar: 5},
|
||||
],
|
||||
};
|
||||
|
||||
@@ -26,29 +26,20 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
function component(a, b) {
|
||||
const $ = _c(5);
|
||||
let t0;
|
||||
if ($[0] !== b) {
|
||||
t0 = { b };
|
||||
$[0] = b;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t0 = $[1];
|
||||
}
|
||||
const y = t0;
|
||||
const $ = _c(2);
|
||||
const y = { b };
|
||||
let z;
|
||||
if ($[2] !== a || $[3] !== y) {
|
||||
if ($[0] !== a) {
|
||||
z = { a };
|
||||
const x = function () {
|
||||
z.a = 2;
|
||||
};
|
||||
|
||||
x();
|
||||
$[2] = a;
|
||||
$[3] = y;
|
||||
$[4] = z;
|
||||
$[0] = a;
|
||||
$[1] = z;
|
||||
} else {
|
||||
z = $[4];
|
||||
z = $[1];
|
||||
}
|
||||
return z;
|
||||
}
|
||||
|
||||
@@ -2,21 +2,28 @@
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
function component(a, b) {
|
||||
import {mutate} from 'shared-runtime';
|
||||
|
||||
function Component({a, b}) {
|
||||
let z = {a};
|
||||
let y = {b};
|
||||
let y = {b: {b}};
|
||||
let x = function () {
|
||||
z.a = 2;
|
||||
console.log(y.b);
|
||||
mutate(y.b);
|
||||
};
|
||||
x();
|
||||
return z;
|
||||
return [y, z];
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: component,
|
||||
params: ['TodoAdd'],
|
||||
isComponent: 'TodoAdd',
|
||||
fn: Component,
|
||||
params: [{a: 2, b: 3}],
|
||||
sequentialRenders: [
|
||||
{a: 2, b: 3},
|
||||
{a: 2, b: 3},
|
||||
{a: 4, b: 3},
|
||||
{a: 4, b: 5},
|
||||
],
|
||||
};
|
||||
|
||||
```
|
||||
@@ -25,32 +32,46 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
function component(a, b) {
|
||||
import { mutate } from "shared-runtime";
|
||||
|
||||
function Component(t0) {
|
||||
const $ = _c(3);
|
||||
let z;
|
||||
const { a, b } = t0;
|
||||
let t1;
|
||||
if ($[0] !== a || $[1] !== b) {
|
||||
z = { a };
|
||||
const y = { b };
|
||||
const z = { a };
|
||||
const y = { b: { b } };
|
||||
const x = function () {
|
||||
z.a = 2;
|
||||
console.log(y.b);
|
||||
mutate(y.b);
|
||||
};
|
||||
|
||||
x();
|
||||
t1 = [y, z];
|
||||
$[0] = a;
|
||||
$[1] = b;
|
||||
$[2] = z;
|
||||
$[2] = t1;
|
||||
} else {
|
||||
z = $[2];
|
||||
t1 = $[2];
|
||||
}
|
||||
return z;
|
||||
return t1;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: component,
|
||||
params: ["TodoAdd"],
|
||||
isComponent: "TodoAdd",
|
||||
fn: Component,
|
||||
params: [{ a: 2, b: 3 }],
|
||||
sequentialRenders: [
|
||||
{ a: 2, b: 3 },
|
||||
{ a: 2, b: 3 },
|
||||
{ a: 4, b: 3 },
|
||||
{ a: 4, b: 5 },
|
||||
],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
|
||||
### Eval output
|
||||
(kind: ok) [{"b":{"b":3,"wat0":"joe"}},{"a":2}]
|
||||
[{"b":{"b":3,"wat0":"joe"}},{"a":2}]
|
||||
[{"b":{"b":3,"wat0":"joe"}},{"a":2}]
|
||||
[{"b":{"b":5,"wat0":"joe"}},{"a":2}]
|
||||
@@ -1,16 +1,23 @@
|
||||
function component(a, b) {
|
||||
import {mutate} from 'shared-runtime';
|
||||
|
||||
function Component({a, b}) {
|
||||
let z = {a};
|
||||
let y = {b};
|
||||
let y = {b: {b}};
|
||||
let x = function () {
|
||||
z.a = 2;
|
||||
console.log(y.b);
|
||||
mutate(y.b);
|
||||
};
|
||||
x();
|
||||
return z;
|
||||
return [y, z];
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: component,
|
||||
params: ['TodoAdd'],
|
||||
isComponent: 'TodoAdd',
|
||||
fn: Component,
|
||||
params: [{a: 2, b: 3}],
|
||||
sequentialRenders: [
|
||||
{a: 2, b: 3},
|
||||
{a: 2, b: 3},
|
||||
{a: 4, b: 3},
|
||||
{a: 4, b: 5},
|
||||
],
|
||||
};
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
function Component({a, b}) {
|
||||
let z = {a};
|
||||
let y = {b};
|
||||
let x = function () {
|
||||
z.a = 2;
|
||||
return Math.max(y.b, 0);
|
||||
};
|
||||
x();
|
||||
return z;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{a: 2, b: 3}],
|
||||
sequentialRenders: [
|
||||
{a: 2, b: 3},
|
||||
{a: 2, b: 3},
|
||||
{a: 4, b: 3},
|
||||
{a: 4, b: 5},
|
||||
],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
function Component(t0) {
|
||||
const $ = _c(3);
|
||||
const { a, b } = t0;
|
||||
let z;
|
||||
if ($[0] !== a || $[1] !== b) {
|
||||
z = { a };
|
||||
const y = { b };
|
||||
const x = function () {
|
||||
z.a = 2;
|
||||
return Math.max(y.b, 0);
|
||||
};
|
||||
|
||||
x();
|
||||
$[0] = a;
|
||||
$[1] = b;
|
||||
$[2] = z;
|
||||
} else {
|
||||
z = $[2];
|
||||
}
|
||||
return z;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{ a: 2, b: 3 }],
|
||||
sequentialRenders: [
|
||||
{ a: 2, b: 3 },
|
||||
{ a: 2, b: 3 },
|
||||
{ a: 4, b: 3 },
|
||||
{ a: 4, b: 5 },
|
||||
],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
### Eval output
|
||||
(kind: ok) {"a":2}
|
||||
{"a":2}
|
||||
{"a":2}
|
||||
{"a":2}
|
||||
@@ -0,0 +1,21 @@
|
||||
function Component({a, b}) {
|
||||
let z = {a};
|
||||
let y = {b};
|
||||
let x = function () {
|
||||
z.a = 2;
|
||||
return Math.max(y.b, 0);
|
||||
};
|
||||
x();
|
||||
return z;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{a: 2, b: 3}],
|
||||
sequentialRenders: [
|
||||
{a: 2, b: 3},
|
||||
{a: 2, b: 3},
|
||||
{a: 4, b: 3},
|
||||
{a: 4, b: 5},
|
||||
],
|
||||
};
|
||||
@@ -22,11 +22,11 @@ import { c as _c } from "react/compiler-runtime";
|
||||
function Foo(props) {
|
||||
const $ = _c(2);
|
||||
let t0;
|
||||
if ($[0] !== props.router.location) {
|
||||
if ($[0] !== props.router) {
|
||||
t0 = (reason) => {
|
||||
log(props.router.location);
|
||||
};
|
||||
$[0] = props.router.location;
|
||||
$[0] = props.router;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t0 = $[1];
|
||||
|
||||
@@ -35,11 +35,11 @@ function component(t0) {
|
||||
}
|
||||
const poke = t1;
|
||||
let t2;
|
||||
if ($[2] !== mutator.user) {
|
||||
if ($[2] !== mutator) {
|
||||
t2 = () => {
|
||||
mutator.user.hide();
|
||||
};
|
||||
$[2] = mutator.user;
|
||||
$[2] = mutator;
|
||||
$[3] = t2;
|
||||
} else {
|
||||
t2 = $[3];
|
||||
|
||||
@@ -34,11 +34,11 @@ function component(a) {
|
||||
}
|
||||
const z = t0;
|
||||
let t1;
|
||||
if ($[2] !== z.a) {
|
||||
if ($[2] !== z) {
|
||||
t1 = function () {
|
||||
console.log(z.a);
|
||||
};
|
||||
$[2] = z.a;
|
||||
$[2] = z;
|
||||
$[3] = t1;
|
||||
} else {
|
||||
t1 = $[3];
|
||||
|
||||
@@ -36,13 +36,13 @@ function component(a) {
|
||||
}
|
||||
const z = t0;
|
||||
let t1;
|
||||
if ($[2] !== z.a.a) {
|
||||
if ($[2] !== z) {
|
||||
t1 = function () {
|
||||
(function () {
|
||||
console.log(z.a.a);
|
||||
})();
|
||||
};
|
||||
$[2] = z.a.a;
|
||||
$[2] = z;
|
||||
$[3] = t1;
|
||||
} else {
|
||||
t1 = $[3];
|
||||
|
||||
@@ -34,11 +34,11 @@ function component(a) {
|
||||
}
|
||||
const z = t0;
|
||||
let t1;
|
||||
if ($[2] !== z.a.a) {
|
||||
if ($[2] !== z) {
|
||||
t1 = function () {
|
||||
console.log(z.a.a);
|
||||
};
|
||||
$[2] = z.a.a;
|
||||
$[2] = z;
|
||||
$[3] = t1;
|
||||
} else {
|
||||
t1 = $[3];
|
||||
|
||||
@@ -97,7 +97,7 @@ function Component(props) {
|
||||
}
|
||||
const urls = t5;
|
||||
let t6;
|
||||
if ($[6] !== comments.length) {
|
||||
if ($[6] !== comments) {
|
||||
t6 = (e) => {
|
||||
if (!comments.length) {
|
||||
return;
|
||||
@@ -105,7 +105,7 @@ function Component(props) {
|
||||
|
||||
console.log(comments.length);
|
||||
};
|
||||
$[6] = comments.length;
|
||||
$[6] = comments;
|
||||
$[7] = t6;
|
||||
} else {
|
||||
t6 = $[7];
|
||||
|
||||
@@ -56,7 +56,7 @@ function Component(props) {
|
||||
|
||||
const { media, comments, urls } = post;
|
||||
let t1;
|
||||
if ($[2] !== comments.length) {
|
||||
if ($[2] !== comments) {
|
||||
t1 = (e) => {
|
||||
if (!comments.length) {
|
||||
return;
|
||||
@@ -64,7 +64,7 @@ function Component(props) {
|
||||
|
||||
console.log(comments.length);
|
||||
};
|
||||
$[2] = comments.length;
|
||||
$[2] = comments;
|
||||
$[3] = t1;
|
||||
} else {
|
||||
t1 = $[3];
|
||||
|
||||
@@ -34,7 +34,7 @@ function Component() {
|
||||
t0 = function update() {
|
||||
"worklet";
|
||||
|
||||
setCount((count_0) => count_0 + 1);
|
||||
setCount(_temp);
|
||||
};
|
||||
$[0] = t0;
|
||||
} else {
|
||||
@@ -51,6 +51,9 @@ function Component() {
|
||||
}
|
||||
return t1;
|
||||
}
|
||||
function _temp(count_0) {
|
||||
return count_0 + 1;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
|
||||
@@ -23,11 +23,11 @@ import { c as _c } from "react/compiler-runtime";
|
||||
function Component(props) {
|
||||
const $ = _c(4);
|
||||
let t0;
|
||||
if ($[0] !== props.name) {
|
||||
if ($[0] !== props) {
|
||||
t0 = function () {
|
||||
return <div>{props.name}</div>;
|
||||
};
|
||||
$[0] = props.name;
|
||||
$[0] = props;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t0 = $[1];
|
||||
|
||||
@@ -91,7 +91,7 @@ function Parent(t0) {
|
||||
type: "div",
|
||||
ref: ref,
|
||||
key: null,
|
||||
props: { children: children },
|
||||
props: { ref: ref, children: children },
|
||||
};
|
||||
}
|
||||
$[0] = children;
|
||||
@@ -180,7 +180,7 @@ function ParentAndRefAndKey(props) {
|
||||
type: Parent,
|
||||
ref: testRef,
|
||||
key: "testKey",
|
||||
props: { a: "a", b: { b: "b" }, c: C },
|
||||
props: { a: "a", b: { b: "b" }, c: C, ref: testRef },
|
||||
};
|
||||
}
|
||||
$[0] = t0;
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
import {Throw} from 'shared-runtime';
|
||||
|
||||
/**
|
||||
* Note: this is disabled in the evaluator due to different devmode errors.
|
||||
* Found differences in evaluator results
|
||||
* Non-forget (expected):
|
||||
* (kind: ok) <invalidtag val="[object Object]"></invalidtag>
|
||||
* logs: ['Warning: <%s /> is using incorrect casing. Use PascalCase for React components, or lowercase for HTML elements.%s','invalidTag']
|
||||
*
|
||||
* Forget:
|
||||
* (kind: ok) <invalidtag val="[object Object]"></invalidtag>
|
||||
* logs: [
|
||||
* 'Warning: <%s /> is using incorrect casing. Use PascalCase for React components, or lowercase for HTML elements.%s','invalidTag',
|
||||
* 'Warning: The tag <%s> is unrecognized in this browser. If you meant to render a React component, start its name with an uppercase letter.%s','invalidTag',
|
||||
* ]
|
||||
*/
|
||||
function useFoo() {
|
||||
const invalidTag = Throw;
|
||||
/**
|
||||
* Need to be careful to not parse `invalidTag` as a localVar (i.e. render
|
||||
* Throw). Note that the jsx transform turns this into a string tag:
|
||||
* `jsx("invalidTag"...
|
||||
*/
|
||||
return <invalidTag val={{val: 2}} />;
|
||||
}
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: useFoo,
|
||||
params: [],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
import { Throw } from "shared-runtime";
|
||||
|
||||
/**
|
||||
* Note: this is disabled in the evaluator due to different devmode errors.
|
||||
* Found differences in evaluator results
|
||||
* Non-forget (expected):
|
||||
* (kind: ok) <invalidtag val="[object Object]"></invalidtag>
|
||||
* logs: ['Warning: <%s /> is using incorrect casing. Use PascalCase for React components, or lowercase for HTML elements.%s','invalidTag']
|
||||
*
|
||||
* Forget:
|
||||
* (kind: ok) <invalidtag val="[object Object]"></invalidtag>
|
||||
* logs: [
|
||||
* 'Warning: <%s /> is using incorrect casing. Use PascalCase for React components, or lowercase for HTML elements.%s','invalidTag',
|
||||
* 'Warning: The tag <%s> is unrecognized in this browser. If you meant to render a React component, start its name with an uppercase letter.%s','invalidTag',
|
||||
* ]
|
||||
*/
|
||||
function useFoo() {
|
||||
const $ = _c(1);
|
||||
let t0;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t0 = <invalidTag val={{ val: 2 }} />;
|
||||
$[0] = t0;
|
||||
} else {
|
||||
t0 = $[0];
|
||||
}
|
||||
return t0;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: useFoo,
|
||||
params: [],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
import {Throw} from 'shared-runtime';
|
||||
|
||||
/**
|
||||
* Note: this is disabled in the evaluator due to different devmode errors.
|
||||
* Found differences in evaluator results
|
||||
* Non-forget (expected):
|
||||
* (kind: ok) <invalidtag val="[object Object]"></invalidtag>
|
||||
* logs: ['Warning: <%s /> is using incorrect casing. Use PascalCase for React components, or lowercase for HTML elements.%s','invalidTag']
|
||||
*
|
||||
* Forget:
|
||||
* (kind: ok) <invalidtag val="[object Object]"></invalidtag>
|
||||
* logs: [
|
||||
* 'Warning: <%s /> is using incorrect casing. Use PascalCase for React components, or lowercase for HTML elements.%s','invalidTag',
|
||||
* 'Warning: The tag <%s> is unrecognized in this browser. If you meant to render a React component, start its name with an uppercase letter.%s','invalidTag',
|
||||
* ]
|
||||
*/
|
||||
function useFoo() {
|
||||
const invalidTag = Throw;
|
||||
/**
|
||||
* Need to be careful to not parse `invalidTag` as a localVar (i.e. render
|
||||
* Throw). Note that the jsx transform turns this into a string tag:
|
||||
* `jsx("invalidTag"...
|
||||
*/
|
||||
return <invalidTag val={{val: 2}} />;
|
||||
}
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: useFoo,
|
||||
params: [],
|
||||
};
|
||||
@@ -27,11 +27,10 @@ import * as SharedRuntime from "shared-runtime";
|
||||
function useFoo(t0) {
|
||||
const $ = _c(1);
|
||||
const { cond } = t0;
|
||||
const MyLocal = SharedRuntime;
|
||||
if (cond) {
|
||||
let t1;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t1 = <MyLocal.Text value={4} />;
|
||||
t1 = <SharedRuntime.Text value={4} />;
|
||||
$[0] = t1;
|
||||
} else {
|
||||
t1 = $[0];
|
||||
|
||||
@@ -22,10 +22,9 @@ import { c as _c } from "react/compiler-runtime";
|
||||
import * as SharedRuntime from "shared-runtime";
|
||||
function useFoo() {
|
||||
const $ = _c(1);
|
||||
const MyLocal = SharedRuntime;
|
||||
let t0;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t0 = <MyLocal.Text value={4} />;
|
||||
t0 = <SharedRuntime.Text value={4} />;
|
||||
$[0] = t0;
|
||||
} else {
|
||||
t0 = $[0];
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
import * as SharedRuntime from 'shared-runtime';
|
||||
import {invoke} from 'shared-runtime';
|
||||
function useComponentFactory({name}) {
|
||||
const localVar = SharedRuntime;
|
||||
const cb = () => <localVar.Stringify>hello world {name}</localVar.Stringify>;
|
||||
return invoke(cb);
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: useComponentFactory,
|
||||
params: [{name: 'sathya'}],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
import * as SharedRuntime from "shared-runtime";
|
||||
import { invoke } from "shared-runtime";
|
||||
function useComponentFactory(t0) {
|
||||
const $ = _c(4);
|
||||
const { name } = t0;
|
||||
let t1;
|
||||
if ($[0] !== name) {
|
||||
t1 = () => (
|
||||
<SharedRuntime.Stringify>hello world {name}</SharedRuntime.Stringify>
|
||||
);
|
||||
$[0] = name;
|
||||
$[1] = t1;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
}
|
||||
const cb = t1;
|
||||
let t2;
|
||||
if ($[2] !== cb) {
|
||||
t2 = invoke(cb);
|
||||
$[2] = cb;
|
||||
$[3] = t2;
|
||||
} else {
|
||||
t2 = $[3];
|
||||
}
|
||||
return t2;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: useComponentFactory,
|
||||
params: [{ name: "sathya" }],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
### Eval output
|
||||
(kind: ok) <div>{"children":["hello world ","sathya"]}</div>
|
||||
@@ -0,0 +1,12 @@
|
||||
import * as SharedRuntime from 'shared-runtime';
|
||||
import {invoke} from 'shared-runtime';
|
||||
function useComponentFactory({name}) {
|
||||
const localVar = SharedRuntime;
|
||||
const cb = () => <localVar.Stringify>hello world {name}</localVar.Stringify>;
|
||||
return invoke(cb);
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: useComponentFactory,
|
||||
params: [{name: 'sathya'}],
|
||||
};
|
||||
@@ -0,0 +1,45 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
import * as SharedRuntime from 'shared-runtime';
|
||||
function Component({name}) {
|
||||
const localVar = SharedRuntime;
|
||||
return <localVar.Stringify>hello world {name}</localVar.Stringify>;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{name: 'sathya'}],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
import * as SharedRuntime from "shared-runtime";
|
||||
function Component(t0) {
|
||||
const $ = _c(2);
|
||||
const { name } = t0;
|
||||
let t1;
|
||||
if ($[0] !== name) {
|
||||
t1 = <SharedRuntime.Stringify>hello world {name}</SharedRuntime.Stringify>;
|
||||
$[0] = name;
|
||||
$[1] = t1;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
}
|
||||
return t1;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{ name: "sathya" }],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
### Eval output
|
||||
(kind: ok) <div>{"children":["hello world ","sathya"]}</div>
|
||||
@@ -0,0 +1,10 @@
|
||||
import * as SharedRuntime from 'shared-runtime';
|
||||
function Component({name}) {
|
||||
const localVar = SharedRuntime;
|
||||
return <localVar.Stringify>hello world {name}</localVar.Stringify>;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{name: 'sathya'}],
|
||||
};
|
||||
@@ -0,0 +1,44 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
import * as SharedRuntime from 'shared-runtime';
|
||||
function Component({name}) {
|
||||
return <SharedRuntime.Stringify>hello world {name}</SharedRuntime.Stringify>;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{name: 'sathya'}],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
import * as SharedRuntime from "shared-runtime";
|
||||
function Component(t0) {
|
||||
const $ = _c(2);
|
||||
const { name } = t0;
|
||||
let t1;
|
||||
if ($[0] !== name) {
|
||||
t1 = <SharedRuntime.Stringify>hello world {name}</SharedRuntime.Stringify>;
|
||||
$[0] = name;
|
||||
$[1] = t1;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
}
|
||||
return t1;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{ name: "sathya" }],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
### Eval output
|
||||
(kind: ok) <div>{"children":["hello world ","sathya"]}</div>
|
||||
@@ -0,0 +1,9 @@
|
||||
import * as SharedRuntime from 'shared-runtime';
|
||||
function Component({name}) {
|
||||
return <SharedRuntime.Stringify>hello world {name}</SharedRuntime.Stringify>;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{name: 'sathya'}],
|
||||
};
|
||||
@@ -25,10 +25,9 @@ import { c as _c } from "react/compiler-runtime";
|
||||
import * as SharedRuntime from "shared-runtime";
|
||||
function useFoo() {
|
||||
const $ = _c(1);
|
||||
const MyLocal = SharedRuntime;
|
||||
let t0;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
const callback = () => <MyLocal.Text value={4} />;
|
||||
const callback = () => <SharedRuntime.Text value={4} />;
|
||||
|
||||
t0 = callback();
|
||||
$[0] = t0;
|
||||
|
||||
@@ -32,7 +32,7 @@ function Component() {
|
||||
let t0;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t0 = () => {
|
||||
setState((s) => s + 1);
|
||||
setState(_temp);
|
||||
};
|
||||
$[0] = t0;
|
||||
} else {
|
||||
@@ -61,6 +61,9 @@ function Component() {
|
||||
}
|
||||
return t2;
|
||||
}
|
||||
function _temp(s) {
|
||||
return s + 1;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @validatePreserveExistingMemoizationGuarantees
|
||||
import {useCallback} from 'react';
|
||||
|
||||
function useHook(maybeRef) {
|
||||
return useCallback(() => {
|
||||
return [maybeRef.current];
|
||||
}, [maybeRef]);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
## Error
|
||||
|
||||
```
|
||||
3 |
|
||||
4 | function useHook(maybeRef) {
|
||||
> 5 | return useCallback(() => {
|
||||
| ^^^^^^^
|
||||
> 6 | return [maybeRef.current];
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
> 7 | }, [maybeRef]);
|
||||
| ^^^^ CannotPreserveMemoization: React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected (5:7)
|
||||
8 | }
|
||||
9 |
|
||||
```
|
||||
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @validatePreserveExistingMemoizationGuarantees
|
||||
import {useMemo} from 'react';
|
||||
|
||||
function useHook(maybeRef, shouldRead) {
|
||||
return useMemo(() => {
|
||||
return () => [maybeRef.current];
|
||||
}, [shouldRead, maybeRef]);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
## Error
|
||||
|
||||
```
|
||||
3 |
|
||||
4 | function useHook(maybeRef, shouldRead) {
|
||||
> 5 | return useMemo(() => {
|
||||
| ^^^^^^^
|
||||
> 6 | return () => [maybeRef.current];
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
> 7 | }, [shouldRead, maybeRef]);
|
||||
| ^^^^ CannotPreserveMemoization: React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected (5:7)
|
||||
8 | }
|
||||
9 |
|
||||
```
|
||||
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @validatePreserveExistingMemoizationGuarantees
|
||||
import {useCallback} from 'react';
|
||||
import {Stringify} from 'shared-runtime';
|
||||
|
||||
/**
|
||||
* TODO: we're currently bailing out because `contextVar` is a context variable
|
||||
* and not recorded into the PropagateScopeDeps LoadLocal / PropertyLoad
|
||||
* sidemap. Previously, we were able to avoid this as `BuildHIR` hoisted
|
||||
* `LoadContext` and `PropertyLoad` instructions into the outer function, which
|
||||
* we took as eligible dependencies.
|
||||
*
|
||||
* One solution is to simply record `LoadContext` identifiers into the
|
||||
* temporaries sidemap when the instruction occurs *after* the context
|
||||
* variable's mutable range.
|
||||
*/
|
||||
function Foo(props) {
|
||||
let contextVar;
|
||||
if (props.cond) {
|
||||
contextVar = {val: 2};
|
||||
} else {
|
||||
contextVar = {};
|
||||
}
|
||||
|
||||
const cb = useCallback(() => [contextVar.val], [contextVar.val]);
|
||||
|
||||
return <Stringify cb={cb} shouldInvokeFns={true} />;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Foo,
|
||||
params: [{cond: true}],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
|
||||
## Error
|
||||
|
||||
```
|
||||
22 | }
|
||||
23 |
|
||||
> 24 | const cb = useCallback(() => [contextVar.val], [contextVar.val]);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ CannotPreserveMemoization: React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected (24:24)
|
||||
25 |
|
||||
26 | return <Stringify cb={cb} shouldInvokeFns={true} />;
|
||||
27 | }
|
||||
```
|
||||
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
// @validatePreserveExistingMemoizationGuarantees
|
||||
import {useCallback} from 'react';
|
||||
import {Stringify} from 'shared-runtime';
|
||||
|
||||
/**
|
||||
* TODO: we're currently bailing out because `contextVar` is a context variable
|
||||
* and not recorded into the PropagateScopeDeps LoadLocal / PropertyLoad
|
||||
* sidemap. Previously, we were able to avoid this as `BuildHIR` hoisted
|
||||
* `LoadContext` and `PropertyLoad` instructions into the outer function, which
|
||||
* we took as eligible dependencies.
|
||||
*
|
||||
* One solution is to simply record `LoadContext` identifiers into the
|
||||
* temporaries sidemap when the instruction occurs *after* the context
|
||||
* variable's mutable range.
|
||||
*/
|
||||
function Foo(props) {
|
||||
let contextVar;
|
||||
if (props.cond) {
|
||||
contextVar = {val: 2};
|
||||
} else {
|
||||
contextVar = {};
|
||||
}
|
||||
|
||||
const cb = useCallback(() => [contextVar.val], [contextVar.val]);
|
||||
|
||||
return <Stringify cb={cb} shouldInvokeFns={true} />;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Foo,
|
||||
params: [{cond: true}],
|
||||
};
|
||||
@@ -44,8 +44,6 @@ function Component({propA, propB}) {
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
> 14 | }, [propA?.a, propB.x.y]);
|
||||
| ^^^^ CannotPreserveMemoization: React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected (6:14)
|
||||
|
||||
CannotPreserveMemoization: React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected (6:14)
|
||||
15 | }
|
||||
16 |
|
||||
```
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @validatePreserveExistingMemoizationGuarantees
|
||||
import {useCallback} from 'react';
|
||||
|
||||
function useHook(maybeRef) {
|
||||
return useCallback(() => {
|
||||
return [maybeRef.current];
|
||||
}, [maybeRef]);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime"; // @validatePreserveExistingMemoizationGuarantees
|
||||
import { useCallback } from "react";
|
||||
|
||||
function useHook(maybeRef) {
|
||||
const $ = _c(2);
|
||||
let t0;
|
||||
if ($[0] !== maybeRef) {
|
||||
t0 = () => [maybeRef.current];
|
||||
$[0] = maybeRef;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t0 = $[1];
|
||||
}
|
||||
return t0;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### Eval output
|
||||
(kind: exception) Fixture not implemented
|
||||
@@ -0,0 +1,40 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @validatePreserveExistingMemoizationGuarantees
|
||||
import {useMemo} from 'react';
|
||||
|
||||
function useHook(maybeRef) {
|
||||
return useMemo(() => {
|
||||
return () => [maybeRef.current];
|
||||
}, [maybeRef]);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime"; // @validatePreserveExistingMemoizationGuarantees
|
||||
import { useMemo } from "react";
|
||||
|
||||
function useHook(maybeRef) {
|
||||
const $ = _c(2);
|
||||
let t0;
|
||||
let t1;
|
||||
if ($[0] !== maybeRef) {
|
||||
t1 = () => [maybeRef.current];
|
||||
$[0] = maybeRef;
|
||||
$[1] = t1;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
}
|
||||
t0 = t1;
|
||||
return t0;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### Eval output
|
||||
(kind: exception) Fixture not implemented
|
||||
@@ -1,8 +1,8 @@
|
||||
// @validatePreserveExistingMemoizationGuarantees
|
||||
import {useMemo} from 'react';
|
||||
|
||||
function useHook(maybeRef, shouldRead) {
|
||||
function useHook(maybeRef) {
|
||||
return useMemo(() => {
|
||||
return () => [maybeRef.current];
|
||||
}, [shouldRead, maybeRef]);
|
||||
}, [maybeRef]);
|
||||
}
|
||||
@@ -9,13 +9,13 @@ import {sum} from 'shared-runtime';
|
||||
function Component({propA, propB}) {
|
||||
const x = propB.x.y;
|
||||
return useCallback(() => {
|
||||
return sum(propA.x, x);
|
||||
}, [propA.x, x]);
|
||||
return sum(propA, x);
|
||||
}, [propA, x]);
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{propA: {x: 2}, propB: {x: {y: 3}}}],
|
||||
params: [{propA: 2, propB: {x: {y: 3}}}],
|
||||
};
|
||||
|
||||
```
|
||||
@@ -32,9 +32,9 @@ function Component(t0) {
|
||||
const { propA, propB } = t0;
|
||||
const x = propB.x.y;
|
||||
let t1;
|
||||
if ($[0] !== propA.x || $[1] !== x) {
|
||||
t1 = () => sum(propA.x, x);
|
||||
$[0] = propA.x;
|
||||
if ($[0] !== propA || $[1] !== x) {
|
||||
t1 = () => sum(propA, x);
|
||||
$[0] = propA;
|
||||
$[1] = x;
|
||||
$[2] = t1;
|
||||
} else {
|
||||
@@ -45,7 +45,7 @@ function Component(t0) {
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{ propA: { x: 2 }, propB: { x: { y: 3 } } }],
|
||||
params: [{ propA: 2, propB: { x: { y: 3 } } }],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
@@ -5,11 +5,11 @@ import {sum} from 'shared-runtime';
|
||||
function Component({propA, propB}) {
|
||||
const x = propB.x.y;
|
||||
return useCallback(() => {
|
||||
return sum(propA.x, x);
|
||||
}, [propA.x, x]);
|
||||
return sum(propA, x);
|
||||
}, [propA, x]);
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{propA: {x: 2}, propB: {x: {y: 3}}}],
|
||||
params: [{propA: 2, propB: {x: {y: 3}}}],
|
||||
};
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @validatePreserveExistingMemoizationGuarantees
|
||||
import {useCallback} from 'react';
|
||||
import {Stringify} from 'shared-runtime';
|
||||
|
||||
function Foo(props) {
|
||||
let contextVar;
|
||||
if (props.cond) {
|
||||
contextVar = {val: 2};
|
||||
} else {
|
||||
contextVar = {};
|
||||
}
|
||||
|
||||
const cb = useCallback(() => [contextVar.val], [contextVar.val]);
|
||||
|
||||
return <Stringify cb={cb} shouldInvokeFns={true} />;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Foo,
|
||||
params: [{cond: true}],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime"; // @validatePreserveExistingMemoizationGuarantees
|
||||
import { useCallback } from "react";
|
||||
import { Stringify } from "shared-runtime";
|
||||
|
||||
function Foo(props) {
|
||||
const $ = _c(6);
|
||||
let contextVar;
|
||||
if ($[0] !== props.cond) {
|
||||
if (props.cond) {
|
||||
contextVar = { val: 2 };
|
||||
} else {
|
||||
contextVar = {};
|
||||
}
|
||||
$[0] = props.cond;
|
||||
$[1] = contextVar;
|
||||
} else {
|
||||
contextVar = $[1];
|
||||
}
|
||||
|
||||
const t0 = contextVar;
|
||||
let t1;
|
||||
if ($[2] !== t0.val) {
|
||||
t1 = () => [contextVar.val];
|
||||
$[2] = t0.val;
|
||||
$[3] = t1;
|
||||
} else {
|
||||
t1 = $[3];
|
||||
}
|
||||
contextVar;
|
||||
const cb = t1;
|
||||
let t2;
|
||||
if ($[4] !== cb) {
|
||||
t2 = <Stringify cb={cb} shouldInvokeFns={true} />;
|
||||
$[4] = cb;
|
||||
$[5] = t2;
|
||||
} else {
|
||||
t2 = $[5];
|
||||
}
|
||||
return t2;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Foo,
|
||||
params: [{ cond: true }],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
### Eval output
|
||||
(kind: ok) <div>{"cb":{"kind":"Function","result":[2]},"shouldInvokeFns":true}</div>
|
||||
@@ -1,21 +0,0 @@
|
||||
// @validatePreserveExistingMemoizationGuarantees
|
||||
import {useCallback} from 'react';
|
||||
import {Stringify} from 'shared-runtime';
|
||||
|
||||
function Foo(props) {
|
||||
let contextVar;
|
||||
if (props.cond) {
|
||||
contextVar = {val: 2};
|
||||
} else {
|
||||
contextVar = {};
|
||||
}
|
||||
|
||||
const cb = useCallback(() => [contextVar.val], [contextVar.val]);
|
||||
|
||||
return <Stringify cb={cb} shouldInvokeFns={true} />;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Foo,
|
||||
params: [{cond: true}],
|
||||
};
|
||||
@@ -45,18 +45,16 @@ function Foo(props) {
|
||||
} else {
|
||||
x = $[1];
|
||||
}
|
||||
|
||||
const t0 = x;
|
||||
let t1;
|
||||
if ($[2] !== t0) {
|
||||
t1 = () => [x];
|
||||
$[2] = t0;
|
||||
$[3] = t1;
|
||||
let t0;
|
||||
if ($[2] !== x) {
|
||||
t0 = () => [x];
|
||||
$[2] = x;
|
||||
$[3] = t0;
|
||||
} else {
|
||||
t1 = $[3];
|
||||
t0 = $[3];
|
||||
}
|
||||
x;
|
||||
const cb = t1;
|
||||
const cb = t0;
|
||||
return cb;
|
||||
}
|
||||
|
||||
|
||||
@@ -70,28 +70,26 @@ function useBar(t0, cond) {
|
||||
if (cond) {
|
||||
x = b;
|
||||
}
|
||||
|
||||
const t2 = x;
|
||||
let t3;
|
||||
if ($[1] !== a || $[2] !== t2) {
|
||||
t3 = () => [a, x];
|
||||
let t2;
|
||||
if ($[1] !== a || $[2] !== x) {
|
||||
t2 = () => [a, x];
|
||||
$[1] = a;
|
||||
$[2] = t2;
|
||||
$[3] = t3;
|
||||
$[2] = x;
|
||||
$[3] = t2;
|
||||
} else {
|
||||
t3 = $[3];
|
||||
t2 = $[3];
|
||||
}
|
||||
x;
|
||||
const cb = t3;
|
||||
let t4;
|
||||
const cb = t2;
|
||||
let t3;
|
||||
if ($[4] !== cb) {
|
||||
t4 = <Stringify cb={cb} shouldInvoke={true} />;
|
||||
t3 = <Stringify cb={cb} shouldInvoke={true} />;
|
||||
$[4] = cb;
|
||||
$[5] = t4;
|
||||
$[5] = t3;
|
||||
} else {
|
||||
t4 = $[5];
|
||||
t3 = $[5];
|
||||
}
|
||||
return t4;
|
||||
return t3;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
|
||||
@@ -37,9 +37,9 @@ import { useCallback } from "react";
|
||||
function useHook(x) {
|
||||
const $ = _c(2);
|
||||
let t0;
|
||||
if ($[0] !== x.y.z) {
|
||||
if ($[0] !== x) {
|
||||
t0 = () => [x.y.z];
|
||||
$[0] = x.y.z;
|
||||
$[0] = x;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t0 = $[1];
|
||||
|
||||
@@ -29,9 +29,9 @@ function useFoo(t0) {
|
||||
const $ = _c(2);
|
||||
const { a } = t0;
|
||||
let t1;
|
||||
if ($[0] !== a.b.c) {
|
||||
if ($[0] !== a) {
|
||||
t1 = <Stringify fn={() => a.b.c} shouldInvokeFns={true} />;
|
||||
$[0] = a.b.c;
|
||||
$[0] = a;
|
||||
$[1] = t1;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
|
||||
@@ -51,12 +51,12 @@ function Foo(t0) {
|
||||
const fn = t1;
|
||||
useIdentity(null);
|
||||
let x;
|
||||
if ($[2] !== a.b.c || $[3] !== cond) {
|
||||
if ($[2] !== a || $[3] !== cond) {
|
||||
x = makeArray();
|
||||
if (cond) {
|
||||
x.push(identity(a.b.c));
|
||||
}
|
||||
$[2] = a.b.c;
|
||||
$[2] = a;
|
||||
$[3] = cond;
|
||||
$[4] = x;
|
||||
} else {
|
||||
|
||||
@@ -41,9 +41,9 @@ function useFoo(t0) {
|
||||
local = $[1];
|
||||
}
|
||||
let t1;
|
||||
if ($[2] !== local.b.c) {
|
||||
if ($[2] !== local) {
|
||||
t1 = () => local.b.c;
|
||||
$[2] = local.b.c;
|
||||
$[2] = local;
|
||||
$[3] = t1;
|
||||
} else {
|
||||
t1 = $[3];
|
||||
|
||||
@@ -50,12 +50,12 @@ function Foo(t0) {
|
||||
const fn = t1;
|
||||
useIdentity(null);
|
||||
let arr;
|
||||
if ($[2] !== a.b?.c.e || $[3] !== cond) {
|
||||
if ($[2] !== a || $[3] !== cond) {
|
||||
arr = makeArray();
|
||||
if (cond) {
|
||||
arr.push(identity(a.b?.c.e));
|
||||
}
|
||||
$[2] = a.b?.c.e;
|
||||
$[2] = a;
|
||||
$[3] = cond;
|
||||
$[4] = arr;
|
||||
} else {
|
||||
|
||||
@@ -41,9 +41,9 @@ function useFoo(t0) {
|
||||
local = $[1];
|
||||
}
|
||||
let t1;
|
||||
if ($[2] !== local.b.c) {
|
||||
if ($[2] !== local) {
|
||||
t1 = () => [() => local.b.c];
|
||||
$[2] = local.b.c;
|
||||
$[2] = local;
|
||||
$[3] = t1;
|
||||
} else {
|
||||
t1 = $[3];
|
||||
|
||||
@@ -34,9 +34,9 @@ function useFoo(t0) {
|
||||
const $ = _c(4);
|
||||
const { a } = t0;
|
||||
let t1;
|
||||
if ($[0] !== a.b.c) {
|
||||
if ($[0] !== a) {
|
||||
t1 = () => () => ({ value: a.b.c });
|
||||
$[0] = a.b.c;
|
||||
$[0] = a;
|
||||
$[1] = t1;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
|
||||
@@ -34,13 +34,13 @@ function useFoo(t0) {
|
||||
const $ = _c(4);
|
||||
const { a } = t0;
|
||||
let t1;
|
||||
if ($[0] !== a.b.c) {
|
||||
if ($[0] !== a) {
|
||||
t1 = {
|
||||
fn() {
|
||||
return identity(a.b.c);
|
||||
},
|
||||
};
|
||||
$[0] = a.b.c;
|
||||
$[0] = a;
|
||||
$[1] = t1;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
|
||||
@@ -34,9 +34,9 @@ function useFoo(t0) {
|
||||
const $ = _c(2);
|
||||
const { a } = t0;
|
||||
let t1;
|
||||
if ($[0] !== a.b) {
|
||||
if ($[0] !== a) {
|
||||
t1 = <Stringify fn={() => a.b?.c.d?.e} shouldInvokeFns={true} />;
|
||||
$[0] = a.b;
|
||||
$[0] = a;
|
||||
$[1] = t1;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
|
||||
@@ -29,9 +29,9 @@ function Foo(t0) {
|
||||
const $ = _c(5);
|
||||
const { data } = t0;
|
||||
let t1;
|
||||
if ($[0] !== data.a.d) {
|
||||
if ($[0] !== data.a) {
|
||||
t1 = () => data.a.d;
|
||||
$[0] = data.a.d;
|
||||
$[0] = data.a;
|
||||
$[1] = t1;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
|
||||
@@ -51,7 +51,7 @@ import { identity } from "shared-runtime";
|
||||
function Component(props) {
|
||||
const $ = _c(4);
|
||||
let x;
|
||||
if ($[0] !== props.cond) {
|
||||
if ($[0] !== props) {
|
||||
const f = () => {
|
||||
if (props.cond) {
|
||||
x = 1;
|
||||
@@ -62,7 +62,7 @@ function Component(props) {
|
||||
|
||||
const f2 = identity(f);
|
||||
f2();
|
||||
$[0] = props.cond;
|
||||
$[0] = props;
|
||||
$[1] = x;
|
||||
} else {
|
||||
x = $[1];
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
import {useRef, forwardRef} from 'react';
|
||||
import {Stringify} from 'shared-runtime';
|
||||
|
||||
/**
|
||||
* Fixture showing that Ref types may be reactive.
|
||||
* We should always take a dependency on ref values (the outer box) as
|
||||
* they may be reactive. Pruning should be done in
|
||||
* `pruneNonReactiveDependencies`
|
||||
*/
|
||||
|
||||
function Parent({cond}) {
|
||||
const ref1 = useRef(1);
|
||||
const ref2 = useRef(2);
|
||||
const ref = cond ? ref1 : ref2;
|
||||
return <Child ref={ref} />;
|
||||
}
|
||||
|
||||
function ChildImpl(_props, ref) {
|
||||
const cb = () => ref.current;
|
||||
return <Stringify cb={cb} shouldInvokeFns={true} />;
|
||||
}
|
||||
|
||||
const Child = forwardRef(ChildImpl);
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Parent,
|
||||
params: [{cond: true}],
|
||||
sequentialRenders: [{cond: true}, {cond: false}],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
import { useRef, forwardRef } from "react";
|
||||
import { Stringify } from "shared-runtime";
|
||||
|
||||
/**
|
||||
* Fixture showing that Ref types may be reactive.
|
||||
* We should always take a dependency on ref values (the outer box) as
|
||||
* they may be reactive. Pruning should be done in
|
||||
* `pruneNonReactiveDependencies`
|
||||
*/
|
||||
|
||||
function Parent(t0) {
|
||||
const $ = _c(2);
|
||||
const { cond } = t0;
|
||||
const ref1 = useRef(1);
|
||||
const ref2 = useRef(2);
|
||||
const ref = cond ? ref1 : ref2;
|
||||
let t1;
|
||||
if ($[0] !== ref) {
|
||||
t1 = <Child ref={ref} />;
|
||||
$[0] = ref;
|
||||
$[1] = t1;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
}
|
||||
return t1;
|
||||
}
|
||||
|
||||
function ChildImpl(_props, ref) {
|
||||
const $ = _c(4);
|
||||
let t0;
|
||||
if ($[0] !== ref) {
|
||||
t0 = () => ref.current;
|
||||
$[0] = ref;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t0 = $[1];
|
||||
}
|
||||
const cb = t0;
|
||||
let t1;
|
||||
if ($[2] !== cb) {
|
||||
t1 = <Stringify cb={cb} shouldInvokeFns={true} />;
|
||||
$[2] = cb;
|
||||
$[3] = t1;
|
||||
} else {
|
||||
t1 = $[3];
|
||||
}
|
||||
return t1;
|
||||
}
|
||||
|
||||
const Child = forwardRef(ChildImpl);
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Parent,
|
||||
params: [{ cond: true }],
|
||||
sequentialRenders: [{ cond: true }, { cond: false }],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
### Eval output
|
||||
(kind: ok) <div>{"cb":{"kind":"Function","result":1},"shouldInvokeFns":true}</div>
|
||||
<div>{"cb":{"kind":"Function","result":2},"shouldInvokeFns":true}</div>
|
||||
@@ -0,0 +1,29 @@
|
||||
import {useRef, forwardRef} from 'react';
|
||||
import {Stringify} from 'shared-runtime';
|
||||
|
||||
/**
|
||||
* Fixture showing that Ref types may be reactive.
|
||||
* We should always take a dependency on ref values (the outer box) as
|
||||
* they may be reactive. Pruning should be done in
|
||||
* `pruneNonReactiveDependencies`
|
||||
*/
|
||||
|
||||
function Parent({cond}) {
|
||||
const ref1 = useRef(1);
|
||||
const ref2 = useRef(2);
|
||||
const ref = cond ? ref1 : ref2;
|
||||
return <Child ref={ref} />;
|
||||
}
|
||||
|
||||
function ChildImpl(_props, ref) {
|
||||
const cb = () => ref.current;
|
||||
return <Stringify cb={cb} shouldInvokeFns={true} />;
|
||||
}
|
||||
|
||||
const Child = forwardRef(ChildImpl);
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Parent,
|
||||
params: [{cond: true}],
|
||||
sequentialRenders: [{cond: true}, {cond: false}],
|
||||
};
|
||||
@@ -0,0 +1,79 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
import {useRef} from 'react';
|
||||
import {Stringify} from 'shared-runtime';
|
||||
|
||||
/**
|
||||
* Fixture showing that Ref types may be reactive.
|
||||
* We should always take a dependency on ref values (the outer box) as
|
||||
* they may be reactive. Pruning should be done in
|
||||
* `pruneNonReactiveDependencies`
|
||||
*/
|
||||
function Component({cond}) {
|
||||
const ref1 = useRef(1);
|
||||
const ref2 = useRef(2);
|
||||
const ref = cond ? ref1 : ref2;
|
||||
const cb = () => ref.current;
|
||||
return <Stringify cb={cb} shouldInvokeFns={true} />;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{cond: true}],
|
||||
sequentialRenders: [{cond: true}, {cond: false}],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
import { useRef } from "react";
|
||||
import { Stringify } from "shared-runtime";
|
||||
|
||||
/**
|
||||
* Fixture showing that Ref types may be reactive.
|
||||
* We should always take a dependency on ref values (the outer box) as
|
||||
* they may be reactive. Pruning should be done in
|
||||
* `pruneNonReactiveDependencies`
|
||||
*/
|
||||
function Component(t0) {
|
||||
const $ = _c(4);
|
||||
const { cond } = t0;
|
||||
const ref1 = useRef(1);
|
||||
const ref2 = useRef(2);
|
||||
const ref = cond ? ref1 : ref2;
|
||||
let t1;
|
||||
if ($[0] !== ref) {
|
||||
t1 = () => ref.current;
|
||||
$[0] = ref;
|
||||
$[1] = t1;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
}
|
||||
const cb = t1;
|
||||
let t2;
|
||||
if ($[2] !== cb) {
|
||||
t2 = <Stringify cb={cb} shouldInvokeFns={true} />;
|
||||
$[2] = cb;
|
||||
$[3] = t2;
|
||||
} else {
|
||||
t2 = $[3];
|
||||
}
|
||||
return t2;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{ cond: true }],
|
||||
sequentialRenders: [{ cond: true }, { cond: false }],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
### Eval output
|
||||
(kind: ok) <div>{"cb":{"kind":"Function","result":1},"shouldInvokeFns":true}</div>
|
||||
<div>{"cb":{"kind":"Function","result":2},"shouldInvokeFns":true}</div>
|
||||
@@ -0,0 +1,22 @@
|
||||
import {useRef} from 'react';
|
||||
import {Stringify} from 'shared-runtime';
|
||||
|
||||
/**
|
||||
* Fixture showing that Ref types may be reactive.
|
||||
* We should always take a dependency on ref values (the outer box) as
|
||||
* they may be reactive. Pruning should be done in
|
||||
* `pruneNonReactiveDependencies`
|
||||
*/
|
||||
function Component({cond}) {
|
||||
const ref1 = useRef(1);
|
||||
const ref2 = useRef(2);
|
||||
const ref = cond ? ref1 : ref2;
|
||||
const cb = () => ref.current;
|
||||
return <Stringify cb={cb} shouldInvokeFns={true} />;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{cond: true}],
|
||||
sequentialRenders: [{cond: true}, {cond: false}],
|
||||
};
|
||||
@@ -31,9 +31,9 @@ function useFoo(t0) {
|
||||
const $ = _c(2);
|
||||
const { a } = t0;
|
||||
let t1;
|
||||
if ($[0] !== a.b) {
|
||||
if ($[0] !== a) {
|
||||
t1 = <Stringify fn={() => a.b?.c.d?.e} shouldInvokeFns={true} />;
|
||||
$[0] = a.b;
|
||||
$[0] = a;
|
||||
$[1] = t1;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
|
||||
@@ -13,7 +13,7 @@ function Foo(props, ref) {
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Foo,
|
||||
params: [{bar: 'foo'}, {ref: {cuurrent: 1}}],
|
||||
params: [{bar: 'foo'}, {ref: {current: 1}}],
|
||||
isComponent: true,
|
||||
};
|
||||
|
||||
@@ -26,35 +26,39 @@ import { c as _c } from "react/compiler-runtime";
|
||||
import { useEffect } from "react";
|
||||
|
||||
function Foo(props, ref) {
|
||||
const $ = _c(4);
|
||||
const $ = _c(5);
|
||||
let t0;
|
||||
let t1;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
if ($[0] !== ref) {
|
||||
t0 = () => {
|
||||
ref.current = 2;
|
||||
};
|
||||
t1 = [];
|
||||
$[0] = t0;
|
||||
$[1] = t1;
|
||||
$[0] = ref;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t0 = $[0];
|
||||
t1 = $[1];
|
||||
t0 = $[1];
|
||||
}
|
||||
let t1;
|
||||
if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t1 = [];
|
||||
$[2] = t1;
|
||||
} else {
|
||||
t1 = $[2];
|
||||
}
|
||||
useEffect(t0, t1);
|
||||
let t2;
|
||||
if ($[2] !== props.bar) {
|
||||
if ($[3] !== props.bar) {
|
||||
t2 = <div>{props.bar}</div>;
|
||||
$[2] = props.bar;
|
||||
$[3] = t2;
|
||||
$[3] = props.bar;
|
||||
$[4] = t2;
|
||||
} else {
|
||||
t2 = $[3];
|
||||
t2 = $[4];
|
||||
}
|
||||
return t2;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Foo,
|
||||
params: [{ bar: "foo" }, { ref: { cuurrent: 1 } }],
|
||||
params: [{ bar: "foo" }, { ref: { current: 1 } }],
|
||||
isComponent: true,
|
||||
};
|
||||
|
||||
|
||||
@@ -9,6 +9,6 @@ function Foo(props, ref) {
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Foo,
|
||||
params: [{bar: 'foo'}, {ref: {cuurrent: 1}}],
|
||||
params: [{bar: 'foo'}, {ref: {current: 1}}],
|
||||
isComponent: true,
|
||||
};
|
||||
|
||||
@@ -42,7 +42,7 @@ const t0 = "module_t0";
|
||||
const c_0 = "module_c_0";
|
||||
function useFoo(props) {
|
||||
const $0 = _c(4);
|
||||
const c_00 = $0[0] !== props.value;
|
||||
const c_00 = $0[0] !== props;
|
||||
let t1;
|
||||
if (c_00) {
|
||||
t1 = () => {
|
||||
@@ -57,7 +57,7 @@ function useFoo(props) {
|
||||
};
|
||||
return b;
|
||||
};
|
||||
$0[0] = props.value;
|
||||
$0[0] = props;
|
||||
$0[1] = t1;
|
||||
} else {
|
||||
t1 = $0[1];
|
||||
|
||||
@@ -43,7 +43,7 @@ const t0 = "module_t0";
|
||||
const c_0 = "module_c_0";
|
||||
function useFoo(props) {
|
||||
const $0 = _c(2);
|
||||
const c_00 = $0[0] !== props.value;
|
||||
const c_00 = $0[0] !== props;
|
||||
let t1;
|
||||
if (c_00) {
|
||||
const a = {
|
||||
@@ -61,7 +61,7 @@ function useFoo(props) {
|
||||
};
|
||||
|
||||
t1 = a.foo().bar();
|
||||
$0[0] = props.value;
|
||||
$0[0] = props;
|
||||
$0[1] = t1;
|
||||
} else {
|
||||
t1 = $0[1];
|
||||
|
||||
@@ -39,7 +39,7 @@ function Component() {
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime"; // @enableAssumeHooksFollowRulesOfReact @enableTransitivelyFreezeFunctionExpressions
|
||||
function Component() {
|
||||
const $ = _c(8);
|
||||
const $ = _c(7);
|
||||
const items = useItems();
|
||||
let t0;
|
||||
let t1;
|
||||
@@ -47,35 +47,25 @@ function Component() {
|
||||
if ($[0] !== items) {
|
||||
t2 = Symbol.for("react.early_return_sentinel");
|
||||
bb0: {
|
||||
let t3;
|
||||
if ($[4] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t3 = (t4) => {
|
||||
const [item] = t4;
|
||||
return item.name != null;
|
||||
};
|
||||
$[4] = t3;
|
||||
} else {
|
||||
t3 = $[4];
|
||||
}
|
||||
t0 = items.filter(t3);
|
||||
t0 = items.filter(_temp);
|
||||
const filteredItems = t0;
|
||||
if (filteredItems.length === 0) {
|
||||
let t4;
|
||||
if ($[5] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t4 = (
|
||||
let t3;
|
||||
if ($[4] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t3 = (
|
||||
<div>
|
||||
<span />
|
||||
</div>
|
||||
);
|
||||
$[5] = t4;
|
||||
$[4] = t3;
|
||||
} else {
|
||||
t4 = $[5];
|
||||
t3 = $[4];
|
||||
}
|
||||
t2 = t4;
|
||||
t2 = t3;
|
||||
break bb0;
|
||||
}
|
||||
|
||||
t1 = filteredItems.map(_temp);
|
||||
t1 = filteredItems.map(_temp2);
|
||||
}
|
||||
$[0] = items;
|
||||
$[1] = t1;
|
||||
@@ -90,19 +80,23 @@ function Component() {
|
||||
return t2;
|
||||
}
|
||||
let t3;
|
||||
if ($[6] !== t1) {
|
||||
if ($[5] !== t1) {
|
||||
t3 = <>{t1}</>;
|
||||
$[6] = t1;
|
||||
$[7] = t3;
|
||||
$[5] = t1;
|
||||
$[6] = t3;
|
||||
} else {
|
||||
t3 = $[7];
|
||||
t3 = $[6];
|
||||
}
|
||||
return t3;
|
||||
}
|
||||
function _temp(t0) {
|
||||
function _temp2(t0) {
|
||||
const [item_0] = t0;
|
||||
return <Stringify item={item_0} />;
|
||||
}
|
||||
function _temp(t0) {
|
||||
const [item] = t0;
|
||||
return item.name != null;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ function Component() {
|
||||
let t0;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t0 = () => {
|
||||
setState((s) => s + 1);
|
||||
setState(_temp);
|
||||
};
|
||||
$[0] = t0;
|
||||
} else {
|
||||
@@ -67,6 +67,9 @@ function Component() {
|
||||
}
|
||||
return t2;
|
||||
}
|
||||
function _temp(s) {
|
||||
return s + 1;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
|
||||
@@ -41,11 +41,11 @@ function Component(props) {
|
||||
const $ = _c(5);
|
||||
const Foo = useContext(FooContext);
|
||||
let t0;
|
||||
if ($[0] !== Foo.current) {
|
||||
if ($[0] !== Foo) {
|
||||
t0 = () => {
|
||||
mutate(Foo.current);
|
||||
};
|
||||
$[0] = Foo.current;
|
||||
$[0] = Foo;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t0 = $[1];
|
||||
|
||||
@@ -42,7 +42,7 @@ function Component(props) {
|
||||
const $ = _c(6);
|
||||
const foo = useContext(FooContext);
|
||||
let t0;
|
||||
if ($[0] !== foo.current) {
|
||||
if ($[0] !== foo) {
|
||||
t0 = () => {
|
||||
if (foo.current) {
|
||||
return {};
|
||||
@@ -50,7 +50,7 @@ function Component(props) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
$[0] = foo.current;
|
||||
$[0] = foo;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t0 = $[1];
|
||||
|
||||
@@ -34,11 +34,11 @@ function Component(props) {
|
||||
const $ = _c(5);
|
||||
const foo = useContext(FooContext);
|
||||
let t0;
|
||||
if ($[0] !== foo.current) {
|
||||
if ($[0] !== foo) {
|
||||
t0 = () => {
|
||||
console.log(foo.current);
|
||||
};
|
||||
$[0] = foo.current;
|
||||
$[0] = foo;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t0 = $[1];
|
||||
|
||||
@@ -35,7 +35,7 @@ function Component(props) {
|
||||
import { c as _c } from "react/compiler-runtime"; // @enableTransitivelyFreezeFunctionExpressions:false
|
||||
|
||||
function Component(props) {
|
||||
const $ = _c(9);
|
||||
const $ = _c(7);
|
||||
const item = useMutable(props.itemId);
|
||||
const dispatch = useDispatch();
|
||||
useFreeze(dispatch);
|
||||
@@ -51,7 +51,8 @@ function Component(props) {
|
||||
}
|
||||
const exit = t0;
|
||||
let t1;
|
||||
if ($[2] !== exit || $[3] !== item.value) {
|
||||
let t2;
|
||||
if ($[2] !== exit || $[3] !== item) {
|
||||
t1 = () => {
|
||||
const cleanup = GlobalEventEmitter.addListener("onInput", () => {
|
||||
if (item.value) {
|
||||
@@ -60,30 +61,24 @@ function Component(props) {
|
||||
});
|
||||
return () => cleanup.remove();
|
||||
};
|
||||
t2 = [exit, item];
|
||||
$[2] = exit;
|
||||
$[3] = item.value;
|
||||
$[3] = item;
|
||||
$[4] = t1;
|
||||
$[5] = t2;
|
||||
} else {
|
||||
t1 = $[4];
|
||||
}
|
||||
let t2;
|
||||
if ($[5] !== exit || $[6] !== item) {
|
||||
t2 = [exit, item];
|
||||
$[5] = exit;
|
||||
$[6] = item;
|
||||
$[7] = t2;
|
||||
} else {
|
||||
t2 = $[7];
|
||||
t2 = $[5];
|
||||
}
|
||||
useEffect(t1, t2);
|
||||
|
||||
maybeMutate(item);
|
||||
let t3;
|
||||
if ($[8] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
if ($[6] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t3 = <div />;
|
||||
$[8] = t3;
|
||||
$[6] = t3;
|
||||
} else {
|
||||
t3 = $[8];
|
||||
t3 = $[6];
|
||||
}
|
||||
return t3;
|
||||
}
|
||||
|
||||
@@ -34,7 +34,6 @@ const skipFilter = new Set([
|
||||
'capturing-arrow-function-1',
|
||||
'capturing-func-mutate-3',
|
||||
'capturing-func-mutate-nested',
|
||||
'capturing-func-mutate',
|
||||
'capturing-function-1',
|
||||
'capturing-function-alias-computed-load',
|
||||
'capturing-function-decl',
|
||||
@@ -236,7 +235,6 @@ const skipFilter = new Set([
|
||||
'capturing-fun-alias-captured-mutate-2',
|
||||
'capturing-fun-alias-captured-mutate-arr-2',
|
||||
'capturing-func-alias-captured-mutate-arr',
|
||||
'capturing-func-alias-captured-mutate',
|
||||
'capturing-func-alias-computed-mutate',
|
||||
'capturing-func-alias-mutate',
|
||||
'capturing-func-alias-receiver-computed-mutate',
|
||||
@@ -475,6 +473,9 @@ const skipFilter = new Set([
|
||||
'rules-of-hooks/rules-of-hooks-93dc5d5e538a',
|
||||
'rules-of-hooks/rules-of-hooks-69521d94fa03',
|
||||
|
||||
// false positives
|
||||
'invalid-jsx-lowercase-localvar',
|
||||
|
||||
// bugs
|
||||
'fbt/bug-fbt-plural-multiple-function-calls',
|
||||
'fbt/bug-fbt-plural-multiple-mixed-call-tag',
|
||||
@@ -484,7 +485,7 @@ const skipFilter = new Set([
|
||||
'bug-aliased-capture-mutate',
|
||||
'bug-functiondecl-hoisting',
|
||||
'bug-try-catch-maybe-null-dependency',
|
||||
'bug-nonreactive-ref',
|
||||
'bug-type-inference-control-flow',
|
||||
'reduce-reactive-deps/bug-infer-function-cond-access-not-hoisted',
|
||||
'bug-invalid-phi-as-dependency',
|
||||
'reduce-reactive-deps/bug-merge-uncond-optional-chain-and-cond',
|
||||
|
||||
@@ -107,8 +107,9 @@ export function setPropertyByKey<
|
||||
return arg;
|
||||
}
|
||||
|
||||
export function arrayPush<T>(arr: Array<T>, ...values: Array<T>): void {
|
||||
export function arrayPush<T>(arr: Array<T>, ...values: Array<T>): Array<T> {
|
||||
arr.push(...values);
|
||||
return arr;
|
||||
}
|
||||
|
||||
export function graphql(value: string): string {
|
||||
@@ -252,6 +253,9 @@ export function Stringify(props: any): React.ReactElement {
|
||||
toJSON(props, props?.shouldInvokeFns),
|
||||
);
|
||||
}
|
||||
export function Throw() {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
export function ValidateMemoization({
|
||||
inputs,
|
||||
|
||||
@@ -111,7 +111,7 @@
|
||||
},
|
||||
"scripts": {
|
||||
"build": "node ./scripts/rollup/build-all-release-channels.js",
|
||||
"build-for-devtools": "cross-env yarn build react/index,react/jsx,react/compiler-runtime,react-dom/index,react-dom/client,react-dom/unstable_testing,react-dom/test-utils,react-is,react-debug-tools,scheduler,react-test-renderer,react-refresh,react-art --type=NODE --release-channel=experimental",
|
||||
"build-for-devtools": "cross-env RELEASE_CHANNEL=experimental yarn build react/index,react/jsx,react/compiler-runtime,react-dom/index,react-dom/client,react-dom/unstable_testing,react-dom/test-utils,react-is,react-debug-tools,scheduler,react-test-renderer,react-refresh,react-art --type=NODE",
|
||||
"build-for-devtools-dev": "yarn build-for-devtools --type=NODE_DEV",
|
||||
"build-for-devtools-prod": "yarn build-for-devtools --type=NODE_PROD",
|
||||
"build-for-flight-dev": "cross-env RELEASE_CHANNEL=experimental node ./scripts/rollup/build.js react/index,react/jsx,react.react-server,react-dom/index,react-dom/client,react-dom/server,react-dom.react-server,react-dom-server.node,react-dom-server-legacy.node,scheduler,react-server-dom-webpack/ --type=NODE_DEV,ESM_PROD,NODE_ES2015 && mv ./build/node_modules ./build/oss-experimental",
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
"homepage": "https://react.dev/",
|
||||
"peerDependencies": {
|
||||
"jest": "^23.0.1 || ^24.0.0 || ^25.1.0 || ^26.0.0 || ^27.0.0 || ^28.0.0 || ^29.0.0",
|
||||
"react": "^19.0.5",
|
||||
"react-test-renderer": "^19.0.5"
|
||||
"react": "^19.0.0",
|
||||
"react-test-renderer": "^19.0.0"
|
||||
},
|
||||
"files": [
|
||||
"LICENSE",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "react-art",
|
||||
"description": "React ART is a JavaScript library for drawing vector graphics using React. It provides declarative and reactive bindings to the ART library. Using the same declarative API you can render the output to either Canvas, SVG or VML (IE8).",
|
||||
"version": "19.0.5",
|
||||
"version": "19.0.0",
|
||||
"main": "index.js",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -27,7 +27,7 @@
|
||||
"scheduler": "^0.23.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^19.0.5"
|
||||
"react": "^19.0.0"
|
||||
},
|
||||
"files": [
|
||||
"LICENSE",
|
||||
|
||||
@@ -363,6 +363,8 @@ export function resolveUpdatePriority(): EventPriority {
|
||||
return currentUpdatePriority || DefaultEventPriority;
|
||||
}
|
||||
|
||||
export function trackSchedulerEvent(): void {}
|
||||
|
||||
export function resolveEventType(): null | string {
|
||||
return null;
|
||||
}
|
||||
|
||||
54
packages/react-client/src/ReactFlightClient.js
vendored
54
packages/react-client/src/ReactFlightClient.js
vendored
@@ -79,8 +79,6 @@ import getComponentNameFromType from 'shared/getComponentNameFromType';
|
||||
|
||||
import {getOwnerStackByComponentInfoInDev} from 'shared/ReactComponentInfoStack';
|
||||
|
||||
import hasOwnProperty from 'shared/hasOwnProperty';
|
||||
|
||||
import {injectInternals} from './ReactFlightClientDevToolsHook';
|
||||
|
||||
import ReactVersion from 'shared/ReactVersion';
|
||||
@@ -137,8 +135,6 @@ const RESOLVED_MODULE = 'resolved_module';
|
||||
const INITIALIZED = 'fulfilled';
|
||||
const ERRORED = 'rejected';
|
||||
|
||||
const __PROTO__ = '__proto__';
|
||||
|
||||
type PendingChunk<T> = {
|
||||
status: 'pending',
|
||||
value: null | Array<(T) => mixed>,
|
||||
@@ -928,21 +924,10 @@ function waitForReference<T>(
|
||||
return;
|
||||
}
|
||||
}
|
||||
const name = path[i];
|
||||
if (
|
||||
typeof value === 'object' &&
|
||||
value !== null &&
|
||||
hasOwnProperty.call(value, name)
|
||||
) {
|
||||
value = value[name];
|
||||
} else {
|
||||
throw new Error('Invalid reference.');
|
||||
}
|
||||
value = value[path[i]];
|
||||
}
|
||||
const mappedValue = map(response, value, parentObject, key);
|
||||
if (key !== __PROTO__) {
|
||||
parentObject[key] = mappedValue;
|
||||
}
|
||||
parentObject[key] = mappedValue;
|
||||
|
||||
// If this is the root object for a model reference, where `handler.value`
|
||||
// is a stale `null`, the resolved value can be used directly.
|
||||
@@ -1108,9 +1093,7 @@ function loadServerReference<A: Iterable<any>, T>(
|
||||
resolvedValue = resolvedValue.bind.apply(resolvedValue, boundArgs);
|
||||
}
|
||||
|
||||
if (key !== __PROTO__) {
|
||||
parentObject[key] = resolvedValue;
|
||||
}
|
||||
parentObject[key] = resolvedValue;
|
||||
|
||||
// If this is the root object for a model reference, where `handler.value`
|
||||
// is a stale `null`, the resolved value can be used directly.
|
||||
@@ -1389,7 +1372,7 @@ function parseModelString(
|
||||
// Symbol
|
||||
return Symbol.for(value.slice(2));
|
||||
}
|
||||
case 'h': {
|
||||
case 'F': {
|
||||
// Server Reference
|
||||
const ref = value.slice(2);
|
||||
return getOutlinedModel(
|
||||
@@ -1516,20 +1499,18 @@ function parseModelString(
|
||||
// In DEV mode we encode omitted objects in logs as a getter that throws
|
||||
// so that when you try to access it on the client, you know why that
|
||||
// happened.
|
||||
if (key !== __PROTO__) {
|
||||
Object.defineProperty(parentObject, key, {
|
||||
get: function () {
|
||||
// TODO: We should ideally throw here to indicate a difference.
|
||||
return (
|
||||
'This object has been omitted by React in the console log ' +
|
||||
'to avoid sending too much data from the server. Try logging smaller ' +
|
||||
'or more specific objects.'
|
||||
);
|
||||
},
|
||||
enumerable: true,
|
||||
configurable: false,
|
||||
});
|
||||
}
|
||||
Object.defineProperty(parentObject, key, {
|
||||
get: function () {
|
||||
// TODO: We should ideally throw here to indicate a difference.
|
||||
return (
|
||||
'This object has been omitted by React in the console log ' +
|
||||
'to avoid sending too much data from the server. Try logging smaller ' +
|
||||
'or more specific objects.'
|
||||
);
|
||||
},
|
||||
enumerable: true,
|
||||
configurable: false,
|
||||
});
|
||||
return null;
|
||||
}
|
||||
// Fallthrough
|
||||
@@ -3163,9 +3144,6 @@ function parseModel<T>(response: Response, json: UninitializedModel): T {
|
||||
function createFromJSONCallback(response: Response) {
|
||||
// $FlowFixMe[missing-this-annot]
|
||||
return function (key: string, value: JSONValue) {
|
||||
if (key === __PROTO__) {
|
||||
return undefined;
|
||||
}
|
||||
if (typeof value === 'string') {
|
||||
// We can't use .bind here because we need the "this" value.
|
||||
return parseModelString(response, this, key, value);
|
||||
|
||||
@@ -98,8 +98,6 @@ export type ReactServerValue =
|
||||
|
||||
type ReactServerObject = {+[key: string]: ReactServerValue};
|
||||
|
||||
const __PROTO__ = '__proto__';
|
||||
|
||||
function serializeByValueID(id: number): string {
|
||||
return '$' + id.toString(16);
|
||||
}
|
||||
@@ -109,7 +107,7 @@ function serializePromiseID(id: number): string {
|
||||
}
|
||||
|
||||
function serializeServerReferenceID(id: number): string {
|
||||
return '$h' + id.toString(16);
|
||||
return '$F' + id.toString(16);
|
||||
}
|
||||
|
||||
function serializeTemporaryReferenceMarker(): string {
|
||||
@@ -117,6 +115,7 @@ function serializeTemporaryReferenceMarker(): string {
|
||||
}
|
||||
|
||||
function serializeFormDataReference(id: number): string {
|
||||
// Why K? F is "Function". D is "Date". What else?
|
||||
return '$K' + id.toString(16);
|
||||
}
|
||||
|
||||
@@ -366,15 +365,6 @@ export function processReply(
|
||||
): ReactJSONValue {
|
||||
const parent = this;
|
||||
|
||||
if (__DEV__) {
|
||||
if (key === __PROTO__) {
|
||||
console.error(
|
||||
'Expected not to serialize an object with own property `__proto__`. When parsed this property will be omitted.%s',
|
||||
describeObjectForErrorMessage(parent, key),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure that `parent[key]` wasn't JSONified before `value` was passed to us
|
||||
if (__DEV__) {
|
||||
// $FlowFixMe[incompatible-use]
|
||||
@@ -487,22 +477,8 @@ export function processReply(
|
||||
}
|
||||
}
|
||||
|
||||
const existingReference = writtenObjects.get(value);
|
||||
|
||||
// $FlowFixMe[method-unbinding]
|
||||
if (typeof value.then === 'function') {
|
||||
if (existingReference !== undefined) {
|
||||
if (modelRoot === value) {
|
||||
// This is the ID we're currently emitting so we need to write it
|
||||
// once but if we discover it again, we refer to it by id.
|
||||
modelRoot = null;
|
||||
} else {
|
||||
// We've already emitted this as an outlined object, so we can
|
||||
// just refer to that by its existing ID.
|
||||
return existingReference;
|
||||
}
|
||||
}
|
||||
|
||||
// We assume that any object with a .then property is a "Thenable" type,
|
||||
// or a Promise type. Either of which can be represented by a Promise.
|
||||
if (formData === null) {
|
||||
@@ -511,19 +487,11 @@ export function processReply(
|
||||
}
|
||||
pendingParts++;
|
||||
const promiseId = nextPartId++;
|
||||
const promiseReference = serializePromiseID(promiseId);
|
||||
writtenObjects.set(value, promiseReference);
|
||||
const thenable: Thenable<any> = (value: any);
|
||||
thenable.then(
|
||||
partValue => {
|
||||
try {
|
||||
const previousReference = writtenObjects.get(partValue);
|
||||
let partJSON;
|
||||
if (previousReference !== undefined) {
|
||||
partJSON = JSON.stringify(previousReference);
|
||||
} else {
|
||||
partJSON = serializeModel(partValue, promiseId);
|
||||
}
|
||||
const partJSON = serializeModel(partValue, promiseId);
|
||||
// $FlowFixMe[incompatible-type] We know it's not null because we assigned it above.
|
||||
const data: FormData = formData;
|
||||
data.append(formFieldPrefix + promiseId, partJSON);
|
||||
@@ -539,9 +507,10 @@ export function processReply(
|
||||
// that throws on the server instead.
|
||||
reject,
|
||||
);
|
||||
return promiseReference;
|
||||
return serializePromiseID(promiseId);
|
||||
}
|
||||
|
||||
const existingReference = writtenObjects.get(value);
|
||||
if (existingReference !== undefined) {
|
||||
if (modelRoot === value) {
|
||||
// This is the ID we're currently emitting so we need to write it
|
||||
@@ -801,10 +770,6 @@ export function processReply(
|
||||
if (typeof value === 'function') {
|
||||
const metaData = knownServerReferences.get(value);
|
||||
if (metaData !== undefined) {
|
||||
const existingReference = writtenObjects.get(value);
|
||||
if (existingReference !== undefined) {
|
||||
return existingReference;
|
||||
}
|
||||
const metaDataJSON = JSON.stringify(metaData, resolveToJSON);
|
||||
if (formData === null) {
|
||||
// Upgrade to use FormData to allow us to stream this value.
|
||||
@@ -813,10 +778,7 @@ export function processReply(
|
||||
// The reference to this function came from the same client so we can pass it back.
|
||||
const refId = nextPartId++;
|
||||
formData.set(formFieldPrefix + refId, metaDataJSON);
|
||||
const serverReferenceId = serializeServerReferenceID(refId);
|
||||
// Store the server reference ID for deduplication.
|
||||
writtenObjects.set(value, serverReferenceId);
|
||||
return serverReferenceId;
|
||||
return serializeServerReferenceID(refId);
|
||||
}
|
||||
if (temporaryReferences !== undefined && key.indexOf(':') === -1) {
|
||||
// TODO: If the property name contains a colon, we don't dedupe. Escape instead.
|
||||
|
||||
@@ -214,7 +214,7 @@ const SuspenseException: mixed = new Error(
|
||||
'`try/catch` block. Capturing without rethrowing will lead to ' +
|
||||
'unexpected behavior.\n\n' +
|
||||
'To handle async errors, wrap your component in an error boundary, or ' +
|
||||
"call the promise's `.catch` method and pass the result to `use`",
|
||||
"call the promise's `.catch` method and pass the result to `use`.",
|
||||
);
|
||||
|
||||
function use<T>(usable: Usable<T>): T {
|
||||
@@ -560,7 +560,7 @@ function useId(): string {
|
||||
|
||||
// useMemoCache is an implementation detail of Forget's memoization
|
||||
// it should not be called directly in user-generated code
|
||||
function useMemoCache(size: number): Array<any> {
|
||||
function useMemoCache(size: number): Array<mixed> {
|
||||
const fiber = currentFiber;
|
||||
// Don't throw, in case this is called from getPrimitiveStackCache
|
||||
if (fiber == null) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "react-dom-bindings",
|
||||
"description": "React implementation details for react-dom.",
|
||||
"version": "19.0.5",
|
||||
"version": "19.0.0",
|
||||
"private": true,
|
||||
"main": "index.js",
|
||||
"repository": {
|
||||
@@ -18,6 +18,6 @@
|
||||
},
|
||||
"homepage": "https://react.dev/",
|
||||
"peerDependencies": {
|
||||
"react": "^19.0.5"
|
||||
"react": "^19.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user