Compare commits
50 Commits
pr35331
...
asserts-st
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d2b9b1fa18 | ||
|
|
41b3e9a670 | ||
|
|
195fd2286b | ||
|
|
d87298ae16 | ||
|
|
be3fb29904 | ||
|
|
23e5edd05c | ||
|
|
3926e2438f | ||
|
|
6baff7ac76 | ||
|
|
bef88f7c11 | ||
|
|
01c4d03d84 | ||
|
|
cbc4d40663 | ||
|
|
db71391c5c | ||
|
|
4cf906380d | ||
|
|
eac3c95537 | ||
|
|
35a81cecf7 | ||
|
|
4028aaa50c | ||
|
|
f0fbb0d199 | ||
|
|
bb8a76c6cc | ||
|
|
fae15df40e | ||
|
|
53daaf5aba | ||
|
|
4a3d993e52 | ||
|
|
3e1abcc8d7 | ||
|
|
c18662405c | ||
|
|
583e200332 | ||
|
|
8a83073753 | ||
|
|
5aec1b2a8d | ||
|
|
d6cae440e3 | ||
|
|
00908be9ff | ||
|
|
0e180141bf | ||
|
|
65eec428c4 | ||
|
|
454fc41fc7 | ||
|
|
f93b9fd44b | ||
|
|
b731fe28cc | ||
|
|
88ee1f5955 | ||
|
|
bcf97c7564 | ||
|
|
ba5b843692 | ||
|
|
b061b597f7 | ||
|
|
38a6f4e4a1 | ||
|
|
b85cf6af3d | ||
|
|
b45bb335db | ||
|
|
80cb7a9925 | ||
|
|
894bc73cb4 | ||
|
|
d3eb566291 | ||
|
|
37bcdcde04 | ||
|
|
5a970933c0 | ||
|
|
5d80124345 | ||
|
|
eade0d0fb7 | ||
|
|
d763f3131e | ||
|
|
734f1bf1ac | ||
|
|
61331f3c9e |
@@ -635,6 +635,7 @@ module.exports = {
|
||||
FocusOptions: 'readonly',
|
||||
OptionalEffectTiming: 'readonly',
|
||||
|
||||
__REACT_ROOT_PATH_TEST__: 'readonly',
|
||||
spyOnDev: 'readonly',
|
||||
spyOnDevAndProd: 'readonly',
|
||||
spyOnProd: 'readonly',
|
||||
|
||||
50
.github/workflows/runtime_build_and_test.yml
vendored
50
.github/workflows/runtime_build_and_test.yml
vendored
@@ -278,6 +278,7 @@ jobs:
|
||||
if: steps.node_modules.outputs.cache-hit != 'true'
|
||||
- run: yarn --cwd compiler install --frozen-lockfile
|
||||
if: steps.node_modules.outputs.cache-hit != 'true'
|
||||
- run: node --version
|
||||
- run: yarn test ${{ matrix.params }} --ci --shard=${{ matrix.shard }}
|
||||
|
||||
# Hardcoded to improve parallelism
|
||||
@@ -382,9 +383,6 @@ jobs:
|
||||
-r=experimental --env=development,
|
||||
-r=experimental --env=production,
|
||||
|
||||
# Dev Tools
|
||||
--project=devtools -r=experimental,
|
||||
|
||||
# TODO: Update test config to support www build tests
|
||||
# - "-r=www-classic --env=development --variant=false"
|
||||
# - "-r=www-classic --env=production --variant=false"
|
||||
@@ -448,8 +446,54 @@ jobs:
|
||||
merge-multiple: true
|
||||
- name: Display structure of build
|
||||
run: ls -R build
|
||||
- run: node --version
|
||||
- run: yarn test --build ${{ matrix.test_params }} --shard=${{ matrix.shard }} --ci
|
||||
|
||||
test_build_devtools:
|
||||
name: yarn test-build (devtools)
|
||||
needs: [build_and_lint, runtime_node_modules_cache]
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
shard:
|
||||
- 1/5
|
||||
- 2/5
|
||||
- 3/5
|
||||
- 4/5
|
||||
- 5/5
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.event.inputs.commit_sha != '' && github.event.inputs.commit_sha || github.event.pull_request.head.sha || github.sha }}
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: yarn
|
||||
cache-dependency-path: yarn.lock
|
||||
- name: Restore cached node_modules
|
||||
uses: actions/cache/restore@v4
|
||||
id: node_modules
|
||||
with:
|
||||
path: |
|
||||
**/node_modules
|
||||
key: runtime-node_modules-v7-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
# Don't use restore-keys here. Otherwise the cache grows indefinitely.
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn install --frozen-lockfile
|
||||
if: steps.node_modules.outputs.cache-hit != 'true'
|
||||
- name: Restore archived build
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
pattern: _build_*
|
||||
path: build
|
||||
merge-multiple: true
|
||||
- name: Display structure of build
|
||||
run: ls -R build
|
||||
- run: node --version
|
||||
- run: yarn test --build --project=devtools -r=experimental --shard=${{ matrix.shard }} --ci
|
||||
|
||||
process_artifacts_combined:
|
||||
name: Process artifacts combined
|
||||
needs: [build_and_lint, runtime_node_modules_cache]
|
||||
|
||||
@@ -35,13 +35,13 @@
|
||||
"lru-cache": "^11.2.2",
|
||||
"lz-string": "^1.5.0",
|
||||
"monaco-editor": "^0.52.0",
|
||||
"next": "15.5.7",
|
||||
"next": "15.5.9",
|
||||
"notistack": "^3.0.0-alpha.7",
|
||||
"prettier": "^3.3.3",
|
||||
"pretty-format": "^29.3.1",
|
||||
"re-resizable": "^6.9.16",
|
||||
"react": "19.2",
|
||||
"react-dom": "19.2"
|
||||
"react": "19.2.3",
|
||||
"react-dom": "19.2.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "18.11.9",
|
||||
|
||||
@@ -715,10 +715,10 @@
|
||||
dependencies:
|
||||
"@monaco-editor/loader" "^1.6.1"
|
||||
|
||||
"@next/env@15.5.7":
|
||||
version "15.5.7"
|
||||
resolved "https://registry.yarnpkg.com/@next/env/-/env-15.5.7.tgz#4168db34ae3bc9fd9ad3b951d327f4cfc38d4362"
|
||||
integrity sha512-4h6Y2NyEkIEN7Z8YxkA27pq6zTkS09bUSYC0xjd0NpwFxjnIKeZEeH591o5WECSmjpUhLn3H2QLJcDye3Uzcvg==
|
||||
"@next/env@15.5.9":
|
||||
version "15.5.9"
|
||||
resolved "https://registry.yarnpkg.com/@next/env/-/env-15.5.9.tgz#53c2c34dc17cd87b61f70c6cc211e303123b2ab8"
|
||||
integrity sha512-4GlTZ+EJM7WaW2HEZcyU317tIQDjkQIyENDLxYJfSWlfqguN+dHkZgyQTV/7ykvobU7yEH5gKvreNrH4B6QgIg==
|
||||
|
||||
"@next/eslint-plugin-next@15.5.2":
|
||||
version "15.5.2"
|
||||
@@ -3204,12 +3204,12 @@ natural-compare@^1.4.0:
|
||||
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
|
||||
integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==
|
||||
|
||||
next@15.5.7:
|
||||
version "15.5.7"
|
||||
resolved "https://registry.yarnpkg.com/next/-/next-15.5.7.tgz#4507700b2bbcaf2c9fb7a9ad25c0dac2ba4a9a75"
|
||||
integrity sha512-+t2/0jIJ48kUpGKkdlhgkv+zPTEOoXyr60qXe68eB/pl3CMJaLeIGjzp5D6Oqt25hCBiBTt8wEeeAzfJvUKnPQ==
|
||||
next@15.5.9:
|
||||
version "15.5.9"
|
||||
resolved "https://registry.yarnpkg.com/next/-/next-15.5.9.tgz#1b80d05865cc27e710fb4dcfc6fd9e726ed12ad4"
|
||||
integrity sha512-agNLK89seZEtC5zUHwtut0+tNrc0Xw4FT/Dg+B/VLEo9pAcS9rtTKpek3V6kVcVwsB2YlqMaHdfZL4eLEVYuCg==
|
||||
dependencies:
|
||||
"@next/env" "15.5.7"
|
||||
"@next/env" "15.5.9"
|
||||
"@swc/helpers" "0.5.15"
|
||||
caniuse-lite "^1.0.30001579"
|
||||
postcss "8.4.31"
|
||||
@@ -3582,10 +3582,10 @@ re-resizable@^6.9.16:
|
||||
resolved "https://registry.yarnpkg.com/re-resizable/-/re-resizable-6.10.0.tgz#d684a096ab438f1a93f59ad3a580a206b0ce31ee"
|
||||
integrity sha512-hysSK0xmA5nz24HBVztlk4yCqCLCvS32E6ZpWxVKop9x3tqCa4yAj1++facrmkOf62JsJHjmjABdKxXofYioCw==
|
||||
|
||||
react-dom@19.2:
|
||||
version "19.2.0"
|
||||
resolved "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz#00ed1e959c365e9a9d48f8918377465466ec3af8"
|
||||
integrity sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==
|
||||
react-dom@19.2.3:
|
||||
version "19.2.3"
|
||||
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-19.2.3.tgz#f0b61d7e5c4a86773889fcc1853af3ed5f215b17"
|
||||
integrity sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==
|
||||
dependencies:
|
||||
scheduler "^0.27.0"
|
||||
|
||||
@@ -3599,10 +3599,10 @@ react-is@^18.0.0:
|
||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e"
|
||||
integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==
|
||||
|
||||
react@19.2:
|
||||
version "19.2.0"
|
||||
resolved "https://registry.npmjs.org/react/-/react-19.2.0.tgz#d33dd1721698f4376ae57a54098cb47fc75d93a5"
|
||||
integrity sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==
|
||||
react@19.2.3:
|
||||
version "19.2.3"
|
||||
resolved "https://registry.yarnpkg.com/react/-/react-19.2.3.tgz#d83e5e8e7a258cf6b4fe28640515f99b87cd19b8"
|
||||
integrity sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==
|
||||
|
||||
read-cache@^1.0.0:
|
||||
version "1.0.0"
|
||||
|
||||
@@ -279,17 +279,20 @@ function runWithEnvironment(
|
||||
validateNoSetStateInRender(hir).unwrap();
|
||||
}
|
||||
|
||||
if (env.config.validateNoDerivedComputationsInEffects_exp) {
|
||||
if (
|
||||
env.config.validateNoDerivedComputationsInEffects_exp &&
|
||||
env.outputMode === 'lint'
|
||||
) {
|
||||
env.logErrors(validateNoDerivedComputationsInEffects_exp(hir));
|
||||
} else if (env.config.validateNoDerivedComputationsInEffects) {
|
||||
validateNoDerivedComputationsInEffects(hir);
|
||||
}
|
||||
|
||||
if (env.config.validateNoSetStateInEffects) {
|
||||
if (env.config.validateNoSetStateInEffects && env.outputMode === 'lint') {
|
||||
env.logErrors(validateNoSetStateInEffects(hir, env));
|
||||
}
|
||||
|
||||
if (env.config.validateNoJSXInTryStatements) {
|
||||
if (env.config.validateNoJSXInTryStatements && env.outputMode === 'lint') {
|
||||
env.logErrors(validateNoJSXInTryStatement(hir));
|
||||
}
|
||||
|
||||
@@ -320,7 +323,11 @@ function runWithEnvironment(
|
||||
value: hir,
|
||||
});
|
||||
|
||||
if (env.enableValidations && env.config.validateStaticComponents) {
|
||||
if (
|
||||
env.enableValidations &&
|
||||
env.config.validateStaticComponents &&
|
||||
env.outputMode === 'lint'
|
||||
) {
|
||||
env.logErrors(validateStaticComponents(hir));
|
||||
}
|
||||
|
||||
|
||||
@@ -4026,6 +4026,7 @@ function lowerAssignment(
|
||||
pattern: {
|
||||
kind: 'ArrayPattern',
|
||||
items,
|
||||
loc: lvalue.node.loc ?? GeneratedSource,
|
||||
},
|
||||
},
|
||||
value,
|
||||
@@ -4203,6 +4204,7 @@ function lowerAssignment(
|
||||
pattern: {
|
||||
kind: 'ObjectPattern',
|
||||
properties,
|
||||
loc: lvalue.node.loc ?? GeneratedSource,
|
||||
},
|
||||
},
|
||||
value,
|
||||
|
||||
@@ -225,8 +225,15 @@ export const EnvironmentConfigSchema = z.object({
|
||||
|
||||
/**
|
||||
* Validate that dependencies supplied to effect hooks are exhaustive.
|
||||
* Can be:
|
||||
* - 'off': No validation (default)
|
||||
* - 'all': Validate and report both missing and extra dependencies
|
||||
* - 'missing-only': Only report missing dependencies
|
||||
* - 'extra-only': Only report extra/unnecessary dependencies
|
||||
*/
|
||||
validateExhaustiveEffectDependencies: z.boolean().default(false),
|
||||
validateExhaustiveEffectDependencies: z
|
||||
.enum(['off', 'all', 'missing-only', 'extra-only'])
|
||||
.default('off'),
|
||||
|
||||
/**
|
||||
* When this is true, rather than pruning existing manual memoization but ensuring or validating
|
||||
|
||||
@@ -694,11 +694,13 @@ export type SpreadPattern = {
|
||||
export type ArrayPattern = {
|
||||
kind: 'ArrayPattern';
|
||||
items: Array<Place | SpreadPattern | Hole>;
|
||||
loc: SourceLocation;
|
||||
};
|
||||
|
||||
export type ObjectPattern = {
|
||||
kind: 'ObjectPattern';
|
||||
properties: Array<ObjectProperty | SpreadPattern>;
|
||||
loc: SourceLocation;
|
||||
};
|
||||
|
||||
export type ObjectPropertyKey =
|
||||
|
||||
@@ -515,6 +515,7 @@ function emitDestructureProps(
|
||||
pattern: {
|
||||
kind: 'ObjectPattern',
|
||||
properties,
|
||||
loc: GeneratedSource,
|
||||
},
|
||||
kind: InstructionKind.Let,
|
||||
},
|
||||
|
||||
@@ -702,7 +702,7 @@ function codegenReactiveScope(
|
||||
outputComments.push(name.name);
|
||||
if (!cx.hasDeclared(identifier)) {
|
||||
statements.push(
|
||||
t.variableDeclaration('let', [t.variableDeclarator(name)]),
|
||||
t.variableDeclaration('let', [createVariableDeclarator(name, null)]),
|
||||
);
|
||||
}
|
||||
cacheLoads.push({name, index, value: wrapCacheDep(cx, name)});
|
||||
@@ -1387,7 +1387,7 @@ function codegenInstructionNullable(
|
||||
suggestions: null,
|
||||
});
|
||||
return createVariableDeclaration(instr.loc, 'const', [
|
||||
t.variableDeclarator(codegenLValue(cx, lvalue), value),
|
||||
createVariableDeclarator(codegenLValue(cx, lvalue), value),
|
||||
]);
|
||||
}
|
||||
case InstructionKind.Function: {
|
||||
@@ -1451,7 +1451,7 @@ function codegenInstructionNullable(
|
||||
suggestions: null,
|
||||
});
|
||||
return createVariableDeclaration(instr.loc, 'let', [
|
||||
t.variableDeclarator(codegenLValue(cx, lvalue), value),
|
||||
createVariableDeclarator(codegenLValue(cx, lvalue), value),
|
||||
]);
|
||||
}
|
||||
case InstructionKind.Reassign: {
|
||||
@@ -1691,6 +1691,9 @@ function withLoc<T extends (...args: Array<any>) => t.Node>(
|
||||
};
|
||||
}
|
||||
|
||||
const createIdentifier = withLoc(t.identifier);
|
||||
const createArrayPattern = withLoc(t.arrayPattern);
|
||||
const createObjectPattern = withLoc(t.objectPattern);
|
||||
const createBinaryExpression = withLoc(t.binaryExpression);
|
||||
const createExpressionStatement = withLoc(t.expressionStatement);
|
||||
const _createLabelledStatement = withLoc(t.labeledStatement);
|
||||
@@ -1722,6 +1725,31 @@ const createTryStatement = withLoc(t.tryStatement);
|
||||
const createBreakStatement = withLoc(t.breakStatement);
|
||||
const createContinueStatement = withLoc(t.continueStatement);
|
||||
|
||||
function createVariableDeclarator(
|
||||
id: t.LVal,
|
||||
init?: t.Expression | null,
|
||||
): t.VariableDeclarator {
|
||||
const node = t.variableDeclarator(id, init);
|
||||
|
||||
/*
|
||||
* The variable declarator location is not preserved in HIR, however, we can use the
|
||||
* start location of the id and the end location of the init to recreate the
|
||||
* exact original variable declarator location.
|
||||
*
|
||||
* Or if init is null, we likely have a declaration without an initializer, so we can use the id.loc.end as the end location.
|
||||
*/
|
||||
if (id.loc && (init === null || init?.loc)) {
|
||||
node.loc = {
|
||||
start: id.loc.start,
|
||||
end: init?.loc?.end ?? id.loc.end,
|
||||
filename: id.loc.filename,
|
||||
identifierName: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
function createHookGuard(
|
||||
guard: ExternalFunction,
|
||||
context: ProgramContext,
|
||||
@@ -1829,7 +1857,7 @@ function codegenInstruction(
|
||||
);
|
||||
} else {
|
||||
return createVariableDeclaration(instr.loc, 'const', [
|
||||
t.variableDeclarator(
|
||||
createVariableDeclarator(
|
||||
convertIdentifier(instr.lvalue.identifier),
|
||||
expressionValue,
|
||||
),
|
||||
@@ -2756,7 +2784,7 @@ function codegenArrayPattern(
|
||||
): t.ArrayPattern {
|
||||
const hasHoles = !pattern.items.every(e => e.kind !== 'Hole');
|
||||
if (hasHoles) {
|
||||
const result = t.arrayPattern([]);
|
||||
const result = createArrayPattern(pattern.loc, []);
|
||||
/*
|
||||
* Older versions of babel have a validation bug fixed by
|
||||
* https://github.com/babel/babel/pull/10917
|
||||
@@ -2777,7 +2805,8 @@ function codegenArrayPattern(
|
||||
}
|
||||
return result;
|
||||
} else {
|
||||
return t.arrayPattern(
|
||||
return createArrayPattern(
|
||||
pattern.loc,
|
||||
pattern.items.map(item => {
|
||||
if (item.kind === 'Hole') {
|
||||
return null;
|
||||
@@ -2797,7 +2826,8 @@ function codegenLValue(
|
||||
return codegenArrayPattern(cx, pattern);
|
||||
}
|
||||
case 'ObjectPattern': {
|
||||
return t.objectPattern(
|
||||
return createObjectPattern(
|
||||
pattern.loc,
|
||||
pattern.properties.map(property => {
|
||||
if (property.kind === 'ObjectProperty') {
|
||||
const key = codegenObjectPropertyKey(cx, property.key);
|
||||
@@ -2916,7 +2946,7 @@ function convertIdentifier(identifier: Identifier): t.Identifier {
|
||||
suggestions: null,
|
||||
},
|
||||
);
|
||||
return t.identifier(identifier.name.value);
|
||||
return createIdentifier(identifier.loc, identifier.name.value);
|
||||
}
|
||||
|
||||
function compareScopeDependency(
|
||||
|
||||
@@ -141,6 +141,7 @@ export function validateExhaustiveDependencies(
|
||||
reactive,
|
||||
startMemo.depsLoc,
|
||||
ErrorCategory.MemoDependencies,
|
||||
'all',
|
||||
);
|
||||
if (diagnostic != null) {
|
||||
error.pushDiagnostic(diagnostic);
|
||||
@@ -159,7 +160,7 @@ export function validateExhaustiveDependencies(
|
||||
onStartMemoize,
|
||||
onFinishMemoize,
|
||||
onEffect: (inferred, manual, manualMemoLoc) => {
|
||||
if (env.config.validateExhaustiveEffectDependencies === false) {
|
||||
if (env.config.validateExhaustiveEffectDependencies === 'off') {
|
||||
return;
|
||||
}
|
||||
if (DEBUG) {
|
||||
@@ -195,12 +196,17 @@ export function validateExhaustiveDependencies(
|
||||
});
|
||||
}
|
||||
}
|
||||
const effectReportMode =
|
||||
typeof env.config.validateExhaustiveEffectDependencies === 'string'
|
||||
? env.config.validateExhaustiveEffectDependencies
|
||||
: 'all';
|
||||
const diagnostic = validateDependencies(
|
||||
Array.from(inferred),
|
||||
manualDeps,
|
||||
reactive,
|
||||
manualMemoLoc,
|
||||
ErrorCategory.EffectExhaustiveDependencies,
|
||||
effectReportMode,
|
||||
);
|
||||
if (diagnostic != null) {
|
||||
error.pushDiagnostic(diagnostic);
|
||||
@@ -220,6 +226,7 @@ function validateDependencies(
|
||||
category:
|
||||
| ErrorCategory.MemoDependencies
|
||||
| ErrorCategory.EffectExhaustiveDependencies,
|
||||
exhaustiveDepsReportMode: 'all' | 'missing-only' | 'extra-only',
|
||||
): CompilerDiagnostic | null {
|
||||
// Sort dependencies by name and path, with shorter/non-optional paths first
|
||||
inferred.sort((a, b) => {
|
||||
@@ -370,9 +377,20 @@ function validateDependencies(
|
||||
extra.push(dep);
|
||||
}
|
||||
|
||||
if (missing.length !== 0 || extra.length !== 0) {
|
||||
// Filter based on report mode
|
||||
const filteredMissing =
|
||||
exhaustiveDepsReportMode === 'extra-only' ? [] : missing;
|
||||
const filteredExtra =
|
||||
exhaustiveDepsReportMode === 'missing-only' ? [] : extra;
|
||||
|
||||
if (filteredMissing.length !== 0 || filteredExtra.length !== 0) {
|
||||
let suggestion: CompilerSuggestion | null = null;
|
||||
if (manualMemoLoc != null && typeof manualMemoLoc !== 'symbol') {
|
||||
if (
|
||||
manualMemoLoc != null &&
|
||||
typeof manualMemoLoc !== 'symbol' &&
|
||||
manualMemoLoc.start.index != null &&
|
||||
manualMemoLoc.end.index != null
|
||||
) {
|
||||
suggestion = {
|
||||
description: 'Update dependencies',
|
||||
range: [manualMemoLoc.start.index, manualMemoLoc.end.index],
|
||||
@@ -388,8 +406,13 @@ function validateDependencies(
|
||||
.join(', ')}]`,
|
||||
};
|
||||
}
|
||||
const diagnostic = createDiagnostic(category, missing, extra, suggestion);
|
||||
for (const dep of missing) {
|
||||
const diagnostic = createDiagnostic(
|
||||
category,
|
||||
filteredMissing,
|
||||
filteredExtra,
|
||||
suggestion,
|
||||
);
|
||||
for (const dep of filteredMissing) {
|
||||
let reactiveStableValueHint = '';
|
||||
if (isStableType(dep.identifier)) {
|
||||
reactiveStableValueHint =
|
||||
@@ -402,7 +425,7 @@ function validateDependencies(
|
||||
loc: dep.loc,
|
||||
});
|
||||
}
|
||||
for (const dep of extra) {
|
||||
for (const dep of filteredExtra) {
|
||||
if (dep.root.kind === 'Global') {
|
||||
diagnostic.withDetails({
|
||||
kind: 'error',
|
||||
|
||||
@@ -27,7 +27,11 @@ import {Result} from '../Utils/Result';
|
||||
|
||||
/**
|
||||
* Some common node types that are important for coverage tracking.
|
||||
* Based on istanbul-lib-instrument
|
||||
* Based on istanbul-lib-instrument + some other common nodes we expect to be present in the generated AST.
|
||||
*
|
||||
* Note: For VariableDeclaration, VariableDeclarator, and Identifier, we enforce stricter validation
|
||||
* that requires both the source location AND node type to match in the generated AST. This ensures
|
||||
* that variable declarations maintain their structural integrity through compilation.
|
||||
*/
|
||||
const IMPORTANT_INSTRUMENTED_TYPES = new Set([
|
||||
'ArrowFunctionExpression',
|
||||
@@ -54,6 +58,14 @@ const IMPORTANT_INSTRUMENTED_TYPES = new Set([
|
||||
'LabeledStatement',
|
||||
'ConditionalExpression',
|
||||
'LogicalExpression',
|
||||
|
||||
/**
|
||||
* Note: these aren't important for coverage tracking,
|
||||
* but we still want to track them to ensure we aren't regressing them when
|
||||
* we fix the source location tracking for other nodes.
|
||||
*/
|
||||
'VariableDeclaration',
|
||||
'Identifier',
|
||||
]);
|
||||
|
||||
/**
|
||||
@@ -114,10 +126,13 @@ export function validateSourceLocations(
|
||||
): Result<void, CompilerError> {
|
||||
const errors = new CompilerError();
|
||||
|
||||
// Step 1: Collect important locations from the original source
|
||||
/*
|
||||
* Step 1: Collect important locations from the original source
|
||||
* Note: Multiple node types can share the same location (e.g. VariableDeclarator and Identifier)
|
||||
*/
|
||||
const importantOriginalLocations = new Map<
|
||||
string,
|
||||
{loc: t.SourceLocation; nodeType: string}
|
||||
{loc: t.SourceLocation; nodeTypes: Set<string>}
|
||||
>();
|
||||
|
||||
func.traverse({
|
||||
@@ -137,20 +152,31 @@ export function validateSourceLocations(
|
||||
// Collect the location if it exists
|
||||
if (node.loc) {
|
||||
const key = locationKey(node.loc);
|
||||
importantOriginalLocations.set(key, {
|
||||
loc: node.loc,
|
||||
nodeType: node.type,
|
||||
});
|
||||
const existing = importantOriginalLocations.get(key);
|
||||
if (existing) {
|
||||
existing.nodeTypes.add(node.type);
|
||||
} else {
|
||||
importantOriginalLocations.set(key, {
|
||||
loc: node.loc,
|
||||
nodeTypes: new Set([node.type]),
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
// Step 2: Collect all locations from the generated AST
|
||||
const generatedLocations = new Set<string>();
|
||||
// Step 2: Collect all locations from the generated AST with their node types
|
||||
const generatedLocations = new Map<string, Set<string>>();
|
||||
|
||||
function collectGeneratedLocations(node: t.Node): void {
|
||||
if (node.loc) {
|
||||
generatedLocations.add(locationKey(node.loc));
|
||||
const key = locationKey(node.loc);
|
||||
const nodeTypes = generatedLocations.get(key);
|
||||
if (nodeTypes) {
|
||||
nodeTypes.add(node.type);
|
||||
} else {
|
||||
generatedLocations.set(key, new Set([node.type]));
|
||||
}
|
||||
}
|
||||
|
||||
// Use Babel's VISITOR_KEYS to traverse only actual node properties
|
||||
@@ -183,22 +209,86 @@ export function validateSourceLocations(
|
||||
collectGeneratedLocations(outlined.fn.body);
|
||||
}
|
||||
|
||||
// Step 3: Validate that all important locations are preserved
|
||||
for (const [key, {loc, nodeType}] of importantOriginalLocations) {
|
||||
if (!generatedLocations.has(key)) {
|
||||
errors.pushDiagnostic(
|
||||
CompilerDiagnostic.create({
|
||||
category: ErrorCategory.Todo,
|
||||
reason: 'Important source location missing in generated code',
|
||||
description:
|
||||
`Source location for ${nodeType} is missing in the generated output. This can cause coverage instrumentation ` +
|
||||
`to fail to track this code properly, resulting in inaccurate coverage reports.`,
|
||||
}).withDetails({
|
||||
kind: 'error',
|
||||
loc,
|
||||
message: null,
|
||||
}),
|
||||
);
|
||||
/*
|
||||
* Step 3: Validate that all important locations are preserved
|
||||
* For certain node types, also validate that the node type matches
|
||||
*/
|
||||
const strictNodeTypes = new Set([
|
||||
'VariableDeclaration',
|
||||
'VariableDeclarator',
|
||||
'Identifier',
|
||||
]);
|
||||
|
||||
const reportMissingLocation = (
|
||||
loc: t.SourceLocation,
|
||||
nodeType: string,
|
||||
): void => {
|
||||
errors.pushDiagnostic(
|
||||
CompilerDiagnostic.create({
|
||||
category: ErrorCategory.Todo,
|
||||
reason: 'Important source location missing in generated code',
|
||||
description:
|
||||
`Source location for ${nodeType} is missing in the generated output. This can cause coverage instrumentation ` +
|
||||
`to fail to track this code properly, resulting in inaccurate coverage reports.`,
|
||||
}).withDetails({
|
||||
kind: 'error',
|
||||
loc,
|
||||
message: null,
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
const reportWrongNodeType = (
|
||||
loc: t.SourceLocation,
|
||||
expectedType: string,
|
||||
actualTypes: Set<string>,
|
||||
): void => {
|
||||
errors.pushDiagnostic(
|
||||
CompilerDiagnostic.create({
|
||||
category: ErrorCategory.Todo,
|
||||
reason:
|
||||
'Important source location has wrong node type in generated code',
|
||||
description:
|
||||
`Source location for ${expectedType} exists in the generated output but with wrong node type(s): ${Array.from(actualTypes).join(', ')}. ` +
|
||||
`This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports.`,
|
||||
}).withDetails({
|
||||
kind: 'error',
|
||||
loc,
|
||||
message: null,
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
for (const [key, {loc, nodeTypes}] of importantOriginalLocations) {
|
||||
const generatedNodeTypes = generatedLocations.get(key);
|
||||
|
||||
if (!generatedNodeTypes) {
|
||||
// Location is completely missing
|
||||
reportMissingLocation(loc, Array.from(nodeTypes).join(', '));
|
||||
} else {
|
||||
// Location exists, check each node type
|
||||
for (const nodeType of nodeTypes) {
|
||||
if (
|
||||
strictNodeTypes.has(nodeType) &&
|
||||
!generatedNodeTypes.has(nodeType)
|
||||
) {
|
||||
/*
|
||||
* For strict node types, the specific node type must be present
|
||||
* Check if any generated node type is also an important original node type
|
||||
*/
|
||||
const hasValidNodeType = Array.from(generatedNodeTypes).some(
|
||||
genType => nodeTypes.has(genType),
|
||||
);
|
||||
|
||||
if (hasValidNodeType) {
|
||||
// At least one generated node type is valid (also in original), so this is just missing
|
||||
reportMissingLocation(loc, nodeType);
|
||||
} else {
|
||||
// None of the generated node types are in original - this is wrong node type
|
||||
reportWrongNodeType(loc, nodeType, generatedNodeTypes);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -35,10 +35,8 @@ function Component() {
|
||||
let t0;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
const a = makeObject_Primitives();
|
||||
|
||||
const x = [];
|
||||
x.push(a);
|
||||
|
||||
mutate(x);
|
||||
t0 = [x, a];
|
||||
$[0] = t0;
|
||||
|
||||
@@ -33,7 +33,6 @@ function Component() {
|
||||
if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
const x = [];
|
||||
x.push(a);
|
||||
|
||||
t1 = [x, a];
|
||||
$[1] = t1;
|
||||
} else {
|
||||
|
||||
@@ -85,14 +85,10 @@ function Component(t0) {
|
||||
let t1;
|
||||
if ($[0] !== prop) {
|
||||
const obj = shallowCopy(prop);
|
||||
|
||||
const aliasedObj = identity(obj);
|
||||
|
||||
const getId = () => obj.id;
|
||||
|
||||
mutate(aliasedObj);
|
||||
setPropertyByKey(aliasedObj, "id", prop.id + 1);
|
||||
|
||||
t1 = <Stringify getId={getId} shouldInvokeFns={true} />;
|
||||
$[0] = prop;
|
||||
$[1] = t1;
|
||||
|
||||
@@ -181,12 +181,9 @@ function Component(t0) {
|
||||
if ($[0] !== prop) {
|
||||
const obj = shallowCopy(prop);
|
||||
const aliasedObj = identity(obj);
|
||||
|
||||
const id = [obj.id];
|
||||
|
||||
mutate(aliasedObj);
|
||||
setPropertyByKey(aliasedObj, "id", prop.id + 1);
|
||||
|
||||
t1 = <Stringify id={id} />;
|
||||
$[0] = prop;
|
||||
$[1] = t1;
|
||||
|
||||
@@ -54,7 +54,6 @@ function Foo(t0) {
|
||||
let t1;
|
||||
if ($[0] !== cond1 || $[1] !== cond2) {
|
||||
const arr = makeArray({ a: 2 }, 2, []);
|
||||
|
||||
t1 = cond1 ? (
|
||||
<>
|
||||
<div>{identity("foo")}</div>
|
||||
|
||||
@@ -49,7 +49,6 @@ function Component() {
|
||||
ref.current = "";
|
||||
}
|
||||
};
|
||||
|
||||
t0 = () => {
|
||||
setRef();
|
||||
};
|
||||
|
||||
@@ -49,7 +49,6 @@ function Component() {
|
||||
ref.current.value = "";
|
||||
}
|
||||
};
|
||||
|
||||
t0 = () => {
|
||||
setRef();
|
||||
};
|
||||
|
||||
@@ -74,7 +74,6 @@ function Component() {
|
||||
console.log(ref.current.value);
|
||||
}
|
||||
};
|
||||
|
||||
t0 = (
|
||||
<>
|
||||
<input ref={ref} />
|
||||
|
||||
@@ -36,7 +36,6 @@ function useArrayOfRef() {
|
||||
const callback = (value) => {
|
||||
ref.current = value;
|
||||
};
|
||||
|
||||
t0 = [callback];
|
||||
$[0] = t0;
|
||||
} else {
|
||||
|
||||
@@ -35,7 +35,6 @@ function Component(props) {
|
||||
const arr = [...bar(props)];
|
||||
return arr.at(x);
|
||||
};
|
||||
|
||||
t1 = fn();
|
||||
$[2] = props;
|
||||
$[3] = x;
|
||||
|
||||
@@ -61,7 +61,6 @@ function useBar(t0) {
|
||||
if ($[0] !== arg) {
|
||||
const s = new Set([1, 5, 4]);
|
||||
const mutableIterator = s.values();
|
||||
|
||||
t1 = [arg, ...mutableIterator];
|
||||
$[0] = arg;
|
||||
$[1] = t1;
|
||||
|
||||
@@ -28,7 +28,6 @@ function Component(props) {
|
||||
const a = [];
|
||||
const b = {};
|
||||
foo(a, b);
|
||||
|
||||
foo(b);
|
||||
t0 = <div a={a} b={b} />;
|
||||
$[0] = t0;
|
||||
|
||||
@@ -45,7 +45,6 @@ function useKeyCommand() {
|
||||
const nextPosition = direction === "left" ? addOne(position) : position;
|
||||
currentPosition.current = nextPosition;
|
||||
};
|
||||
|
||||
const moveLeft = { handler: handleKey("left") };
|
||||
const moveRight = { handler: handleKey("right") };
|
||||
t0 = [moveLeft, moveRight];
|
||||
|
||||
@@ -45,7 +45,6 @@ function Component(t0) {
|
||||
z.a = 2;
|
||||
mutate(y.b);
|
||||
};
|
||||
|
||||
x();
|
||||
t1 = [y, z];
|
||||
$[0] = a;
|
||||
|
||||
@@ -29,7 +29,6 @@ function MyComponentName(props) {
|
||||
const x = {};
|
||||
foo(x, props.a);
|
||||
foo(x, props.b);
|
||||
|
||||
y = [];
|
||||
y.push(x);
|
||||
$[0] = props.a;
|
||||
|
||||
@@ -34,7 +34,6 @@ function useTest() {
|
||||
let t0;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
let w = {};
|
||||
|
||||
const t1 = (w = 42);
|
||||
const t2 = w;
|
||||
|
||||
|
||||
@@ -34,7 +34,6 @@ function useTest() {
|
||||
let t0;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
const w = {};
|
||||
|
||||
const t1 = (w.x = 42);
|
||||
const t2 = w.x;
|
||||
|
||||
|
||||
@@ -44,11 +44,9 @@ function ComponentA(props) {
|
||||
if (b) {
|
||||
a.push(props.p0);
|
||||
}
|
||||
|
||||
if (props.p1) {
|
||||
b.push(props.p2);
|
||||
}
|
||||
|
||||
t0 = <Foo a={a} b={b} />;
|
||||
$[0] = props.p0;
|
||||
$[1] = props.p1;
|
||||
@@ -69,11 +67,9 @@ function ComponentB(props) {
|
||||
if (mayMutate(b)) {
|
||||
a.push(props.p0);
|
||||
}
|
||||
|
||||
if (props.p1) {
|
||||
b.push(props.p2);
|
||||
}
|
||||
|
||||
t0 = <Foo a={a} b={b} />;
|
||||
$[0] = props.p0;
|
||||
$[1] = props.p1;
|
||||
|
||||
@@ -28,7 +28,6 @@ function Component(props) {
|
||||
const a = [];
|
||||
const b = {};
|
||||
new Foo(a, b);
|
||||
|
||||
new Foo(b);
|
||||
t0 = <div a={a} b={b} />;
|
||||
$[0] = t0;
|
||||
|
||||
@@ -34,7 +34,6 @@ function Component(props) {
|
||||
const callback = () => {
|
||||
console.log(x);
|
||||
};
|
||||
|
||||
x = {};
|
||||
t0 = <Stringify callback={callback} shouldInvokeFns={true} />;
|
||||
$[0] = t0;
|
||||
|
||||
@@ -75,7 +75,6 @@ function Component(props) {
|
||||
let t0;
|
||||
if ($[0] !== post) {
|
||||
const allUrls = [];
|
||||
|
||||
const { media: t1, comments: t2, urls: t3 } = post;
|
||||
const media = t1 === undefined ? null : t1;
|
||||
let t4;
|
||||
@@ -102,7 +101,6 @@ function Component(props) {
|
||||
if (!comments.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(comments.length);
|
||||
};
|
||||
$[6] = comments.length;
|
||||
@@ -111,7 +109,6 @@ function Component(props) {
|
||||
t6 = $[7];
|
||||
}
|
||||
const onClick = t6;
|
||||
|
||||
allUrls.push(...urls);
|
||||
t0 = <Stringify media={media} allUrls={allUrls} onClick={onClick} />;
|
||||
$[0] = post;
|
||||
|
||||
@@ -53,7 +53,6 @@ function Component(props) {
|
||||
let t0;
|
||||
if ($[0] !== post) {
|
||||
const allUrls = [];
|
||||
|
||||
const { media, comments, urls } = post;
|
||||
let t1;
|
||||
if ($[2] !== comments.length) {
|
||||
@@ -61,7 +60,6 @@ function Component(props) {
|
||||
if (!comments.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(comments.length);
|
||||
};
|
||||
$[2] = comments.length;
|
||||
@@ -70,7 +68,6 @@ function Component(props) {
|
||||
t1 = $[3];
|
||||
}
|
||||
const onClick = t1;
|
||||
|
||||
allUrls.push(...urls);
|
||||
t0 = <Media media={media} onClick={onClick} />;
|
||||
$[0] = post;
|
||||
|
||||
@@ -57,7 +57,6 @@ function Component(t0) {
|
||||
let y;
|
||||
if ($[0] !== a || $[1] !== b || $[2] !== c) {
|
||||
x = [];
|
||||
|
||||
if (a) {
|
||||
let t1;
|
||||
if ($[5] !== b) {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
|
||||
import {useEffect, useState} from 'react';
|
||||
|
||||
function Component({value, enabled}) {
|
||||
@@ -29,43 +29,21 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
function Component(t0) {
|
||||
const $ = _c(6);
|
||||
const { value, enabled } = t0;
|
||||
function Component({ value, enabled }) {
|
||||
const [localValue, setLocalValue] = useState("");
|
||||
let t1;
|
||||
let t2;
|
||||
if ($[0] !== enabled || $[1] !== value) {
|
||||
t1 = () => {
|
||||
if (enabled) {
|
||||
setLocalValue(value);
|
||||
} else {
|
||||
setLocalValue("disabled");
|
||||
}
|
||||
};
|
||||
|
||||
t2 = [value, enabled];
|
||||
$[0] = enabled;
|
||||
$[1] = value;
|
||||
$[2] = t1;
|
||||
$[3] = t2;
|
||||
} else {
|
||||
t1 = $[2];
|
||||
t2 = $[3];
|
||||
}
|
||||
useEffect(t1, t2);
|
||||
let t3;
|
||||
if ($[4] !== localValue) {
|
||||
t3 = <div>{localValue}</div>;
|
||||
$[4] = localValue;
|
||||
$[5] = t3;
|
||||
} else {
|
||||
t3 = $[5];
|
||||
}
|
||||
return t3;
|
||||
useEffect(() => {
|
||||
if (enabled) {
|
||||
setLocalValue(value);
|
||||
} else {
|
||||
setLocalValue("disabled");
|
||||
}
|
||||
}, [value, enabled]);
|
||||
|
||||
return <div>{localValue}</div>;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
@@ -78,8 +56,8 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
## Logs
|
||||
|
||||
```
|
||||
{"kind":"CompileError","detail":{"options":{"description":"Using an effect triggers an additional render which can hurt performance and user experience, potentially briefly showing stale values to the user\n\nThis setState call is setting a derived value that depends on the following reactive sources:\n\nProps: [value]\n\nData Flow Tree:\n└── value (Prop)\n\nSee: https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state","category":"EffectDerivationsOfState","reason":"You might not need an effect. Derive values in render, not effects.","details":[{"kind":"error","loc":{"start":{"line":9,"column":6,"index":244},"end":{"line":9,"column":19,"index":257},"filename":"derived-state-conditionally-in-effect.ts","identifierName":"setLocalValue"},"message":"This should be computed during render, not in an effect"}]}},"fnLoc":null}
|
||||
{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":107},"end":{"line":16,"column":1,"index":378},"filename":"derived-state-conditionally-in-effect.ts"},"fnName":"Component","memoSlots":6,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
|
||||
{"kind":"CompileError","detail":{"options":{"description":"Using an effect triggers an additional render which can hurt performance and user experience, potentially briefly showing stale values to the user\n\nThis setState call is setting a derived value that depends on the following reactive sources:\n\nProps: [value]\n\nData Flow Tree:\n└── value (Prop)\n\nSee: https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state","category":"EffectDerivationsOfState","reason":"You might not need an effect. Derive values in render, not effects.","details":[{"kind":"error","loc":{"start":{"line":9,"column":6,"index":263},"end":{"line":9,"column":19,"index":276},"filename":"derived-state-conditionally-in-effect.ts","identifierName":"setLocalValue"},"message":"This should be computed during render, not in an effect"}]}},"fnLoc":null}
|
||||
{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":126},"end":{"line":16,"column":1,"index":397},"filename":"derived-state-conditionally-in-effect.ts"},"fnName":"Component","memoSlots":6,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
|
||||
```
|
||||
|
||||
### Eval output
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
|
||||
import {useEffect, useState} from 'react';
|
||||
|
||||
function Component({value, enabled}) {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
|
||||
import {useEffect, useState} from 'react';
|
||||
|
||||
export default function Component({input = 'empty'}) {
|
||||
@@ -26,38 +26,18 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
export default function Component(t0) {
|
||||
const $ = _c(5);
|
||||
const { input: t1 } = t0;
|
||||
const input = t1 === undefined ? "empty" : t1;
|
||||
export default function Component({ input = "empty" }) {
|
||||
const [currInput, setCurrInput] = useState(input);
|
||||
let t2;
|
||||
let t3;
|
||||
if ($[0] !== input) {
|
||||
t2 = () => {
|
||||
setCurrInput(input + "local const");
|
||||
};
|
||||
t3 = [input, "local const"];
|
||||
$[0] = input;
|
||||
$[1] = t2;
|
||||
$[2] = t3;
|
||||
} else {
|
||||
t2 = $[1];
|
||||
t3 = $[2];
|
||||
}
|
||||
useEffect(t2, t3);
|
||||
let t4;
|
||||
if ($[3] !== currInput) {
|
||||
t4 = <div>{currInput}</div>;
|
||||
$[3] = currInput;
|
||||
$[4] = t4;
|
||||
} else {
|
||||
t4 = $[4];
|
||||
}
|
||||
return t4;
|
||||
const localConst = "local const";
|
||||
|
||||
useEffect(() => {
|
||||
setCurrInput(input + localConst);
|
||||
}, [input, localConst]);
|
||||
|
||||
return <div>{currInput}</div>;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
@@ -70,8 +50,8 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
## Logs
|
||||
|
||||
```
|
||||
{"kind":"CompileError","detail":{"options":{"description":"Using an effect triggers an additional render which can hurt performance and user experience, potentially briefly showing stale values to the user\n\nThis setState call is setting a derived value that depends on the following reactive sources:\n\nProps: [input]\n\nData Flow Tree:\n└── input (Prop)\n\nSee: https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state","category":"EffectDerivationsOfState","reason":"You might not need an effect. Derive values in render, not effects.","details":[{"kind":"error","loc":{"start":{"line":9,"column":4,"index":276},"end":{"line":9,"column":16,"index":288},"filename":"derived-state-from-default-props.ts","identifierName":"setCurrInput"},"message":"This should be computed during render, not in an effect"}]}},"fnLoc":null}
|
||||
{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":15,"index":122},"end":{"line":13,"column":1,"index":372},"filename":"derived-state-from-default-props.ts"},"fnName":"Component","memoSlots":5,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
|
||||
{"kind":"CompileError","detail":{"options":{"description":"Using an effect triggers an additional render which can hurt performance and user experience, potentially briefly showing stale values to the user\n\nThis setState call is setting a derived value that depends on the following reactive sources:\n\nProps: [input]\n\nData Flow Tree:\n└── input (Prop)\n\nSee: https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state","category":"EffectDerivationsOfState","reason":"You might not need an effect. Derive values in render, not effects.","details":[{"kind":"error","loc":{"start":{"line":9,"column":4,"index":295},"end":{"line":9,"column":16,"index":307},"filename":"derived-state-from-default-props.ts","identifierName":"setCurrInput"},"message":"This should be computed during render, not in an effect"}]}},"fnLoc":null}
|
||||
{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":15,"index":141},"end":{"line":13,"column":1,"index":391},"filename":"derived-state-from-default-props.ts"},"fnName":"Component","memoSlots":5,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
|
||||
```
|
||||
|
||||
### Eval output
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
|
||||
import {useEffect, useState} from 'react';
|
||||
|
||||
export default function Component({input = 'empty'}) {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
|
||||
|
||||
import {useEffect, useState} from 'react';
|
||||
|
||||
@@ -23,45 +23,20 @@ function Component({shouldChange}) {
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
function Component(t0) {
|
||||
const $ = _c(7);
|
||||
const { shouldChange } = t0;
|
||||
function Component({ shouldChange }) {
|
||||
const [count, setCount] = useState(0);
|
||||
let t1;
|
||||
if ($[0] !== count || $[1] !== shouldChange) {
|
||||
t1 = () => {
|
||||
if (shouldChange) {
|
||||
setCount(count + 1);
|
||||
}
|
||||
};
|
||||
$[0] = count;
|
||||
$[1] = shouldChange;
|
||||
$[2] = t1;
|
||||
} else {
|
||||
t1 = $[2];
|
||||
}
|
||||
let t2;
|
||||
if ($[3] !== count) {
|
||||
t2 = [count];
|
||||
$[3] = count;
|
||||
$[4] = t2;
|
||||
} else {
|
||||
t2 = $[4];
|
||||
}
|
||||
useEffect(t1, t2);
|
||||
let t3;
|
||||
if ($[5] !== count) {
|
||||
t3 = <div>{count}</div>;
|
||||
$[5] = count;
|
||||
$[6] = t3;
|
||||
} else {
|
||||
t3 = $[6];
|
||||
}
|
||||
return t3;
|
||||
|
||||
useEffect(() => {
|
||||
if (shouldChange) {
|
||||
setCount(count + 1);
|
||||
}
|
||||
}, [count]);
|
||||
|
||||
return <div>{count}</div>;
|
||||
}
|
||||
|
||||
```
|
||||
@@ -69,8 +44,8 @@ function Component(t0) {
|
||||
## Logs
|
||||
|
||||
```
|
||||
{"kind":"CompileError","detail":{"options":{"description":"Using an effect triggers an additional render which can hurt performance and user experience, potentially briefly showing stale values to the user\n\nThis setState call is setting a derived value that depends on the following reactive sources:\n\nState: [count]\n\nData Flow Tree:\n└── count (State)\n\nSee: https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state","category":"EffectDerivationsOfState","reason":"You might not need an effect. Derive values in render, not effects.","details":[{"kind":"error","loc":{"start":{"line":10,"column":6,"index":237},"end":{"line":10,"column":14,"index":245},"filename":"derived-state-from-local-state-in-effect.ts","identifierName":"setCount"},"message":"This should be computed during render, not in an effect"}]}},"fnLoc":null}
|
||||
{"kind":"CompileSuccess","fnLoc":{"start":{"line":5,"column":0,"index":108},"end":{"line":15,"column":1,"index":310},"filename":"derived-state-from-local-state-in-effect.ts"},"fnName":"Component","memoSlots":7,"memoBlocks":3,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
|
||||
{"kind":"CompileError","detail":{"options":{"description":"Using an effect triggers an additional render which can hurt performance and user experience, potentially briefly showing stale values to the user\n\nThis setState call is setting a derived value that depends on the following reactive sources:\n\nState: [count]\n\nData Flow Tree:\n└── count (State)\n\nSee: https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state","category":"EffectDerivationsOfState","reason":"You might not need an effect. Derive values in render, not effects.","details":[{"kind":"error","loc":{"start":{"line":10,"column":6,"index":256},"end":{"line":10,"column":14,"index":264},"filename":"derived-state-from-local-state-in-effect.ts","identifierName":"setCount"},"message":"This should be computed during render, not in an effect"}]}},"fnLoc":null}
|
||||
{"kind":"CompileSuccess","fnLoc":{"start":{"line":5,"column":0,"index":127},"end":{"line":15,"column":1,"index":329},"filename":"derived-state-from-local-state-in-effect.ts"},"fnName":"Component","memoSlots":7,"memoBlocks":3,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
|
||||
```
|
||||
|
||||
### Eval output
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
|
||||
|
||||
import {useEffect, useState} from 'react';
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
|
||||
import {useEffect, useState} from 'react';
|
||||
|
||||
function Component({firstName}) {
|
||||
@@ -33,68 +33,25 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
function Component(t0) {
|
||||
const $ = _c(12);
|
||||
const { firstName } = t0;
|
||||
function Component({ firstName }) {
|
||||
const [lastName, setLastName] = useState("Doe");
|
||||
const [fullName, setFullName] = useState("John");
|
||||
let t1;
|
||||
let t2;
|
||||
if ($[0] !== firstName || $[1] !== lastName) {
|
||||
t1 = () => {
|
||||
setFullName(firstName + " " + "D." + " " + lastName);
|
||||
};
|
||||
t2 = [firstName, "D.", lastName];
|
||||
$[0] = firstName;
|
||||
$[1] = lastName;
|
||||
$[2] = t1;
|
||||
$[3] = t2;
|
||||
} else {
|
||||
t1 = $[2];
|
||||
t2 = $[3];
|
||||
}
|
||||
useEffect(t1, t2);
|
||||
let t3;
|
||||
if ($[4] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t3 = (e) => setLastName(e.target.value);
|
||||
$[4] = t3;
|
||||
} else {
|
||||
t3 = $[4];
|
||||
}
|
||||
let t4;
|
||||
if ($[5] !== lastName) {
|
||||
t4 = <input value={lastName} onChange={t3} />;
|
||||
$[5] = lastName;
|
||||
$[6] = t4;
|
||||
} else {
|
||||
t4 = $[6];
|
||||
}
|
||||
let t5;
|
||||
if ($[7] !== fullName) {
|
||||
t5 = <div>{fullName}</div>;
|
||||
$[7] = fullName;
|
||||
$[8] = t5;
|
||||
} else {
|
||||
t5 = $[8];
|
||||
}
|
||||
let t6;
|
||||
if ($[9] !== t4 || $[10] !== t5) {
|
||||
t6 = (
|
||||
<div>
|
||||
{t4}
|
||||
{t5}
|
||||
</div>
|
||||
);
|
||||
$[9] = t4;
|
||||
$[10] = t5;
|
||||
$[11] = t6;
|
||||
} else {
|
||||
t6 = $[11];
|
||||
}
|
||||
return t6;
|
||||
|
||||
const middleName = "D.";
|
||||
|
||||
useEffect(() => {
|
||||
setFullName(firstName + " " + middleName + " " + lastName);
|
||||
}, [firstName, middleName, lastName]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<input value={lastName} onChange={(e) => setLastName(e.target.value)} />
|
||||
<div>{fullName}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
@@ -107,8 +64,8 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
## Logs
|
||||
|
||||
```
|
||||
{"kind":"CompileError","detail":{"options":{"description":"Using an effect triggers an additional render which can hurt performance and user experience, potentially briefly showing stale values to the user\n\nThis setState call is setting a derived value that depends on the following reactive sources:\n\nProps: [firstName]\nState: [lastName]\n\nData Flow Tree:\n├── firstName (Prop)\n└── lastName (State)\n\nSee: https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state","category":"EffectDerivationsOfState","reason":"You might not need an effect. Derive values in render, not effects.","details":[{"kind":"error","loc":{"start":{"line":11,"column":4,"index":297},"end":{"line":11,"column":15,"index":308},"filename":"derived-state-from-prop-local-state-and-component-scope.ts","identifierName":"setFullName"},"message":"This should be computed during render, not in an effect"}]}},"fnLoc":null}
|
||||
{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":107},"end":{"line":20,"column":1,"index":542},"filename":"derived-state-from-prop-local-state-and-component-scope.ts"},"fnName":"Component","memoSlots":12,"memoBlocks":5,"memoValues":6,"prunedMemoBlocks":0,"prunedMemoValues":0}
|
||||
{"kind":"CompileError","detail":{"options":{"description":"Using an effect triggers an additional render which can hurt performance and user experience, potentially briefly showing stale values to the user\n\nThis setState call is setting a derived value that depends on the following reactive sources:\n\nProps: [firstName]\nState: [lastName]\n\nData Flow Tree:\n├── firstName (Prop)\n└── lastName (State)\n\nSee: https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state","category":"EffectDerivationsOfState","reason":"You might not need an effect. Derive values in render, not effects.","details":[{"kind":"error","loc":{"start":{"line":11,"column":4,"index":316},"end":{"line":11,"column":15,"index":327},"filename":"derived-state-from-prop-local-state-and-component-scope.ts","identifierName":"setFullName"},"message":"This should be computed during render, not in an effect"}]}},"fnLoc":null}
|
||||
{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":126},"end":{"line":20,"column":1,"index":561},"filename":"derived-state-from-prop-local-state-and-component-scope.ts"},"fnName":"Component","memoSlots":12,"memoBlocks":5,"memoValues":6,"prunedMemoBlocks":0,"prunedMemoValues":0}
|
||||
```
|
||||
|
||||
### Eval output
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
|
||||
import {useEffect, useState} from 'react';
|
||||
|
||||
function Component({firstName}) {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
|
||||
import {useEffect, useState} from 'react';
|
||||
|
||||
function Component({initialName}) {
|
||||
@@ -29,48 +29,21 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
function Component(t0) {
|
||||
const $ = _c(6);
|
||||
const { initialName } = t0;
|
||||
function Component({ initialName }) {
|
||||
const [name, setName] = useState("");
|
||||
let t1;
|
||||
let t2;
|
||||
if ($[0] !== initialName) {
|
||||
t1 = () => {
|
||||
setName(initialName);
|
||||
};
|
||||
t2 = [initialName];
|
||||
$[0] = initialName;
|
||||
$[1] = t1;
|
||||
$[2] = t2;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
t2 = $[2];
|
||||
}
|
||||
useEffect(t1, t2);
|
||||
let t3;
|
||||
if ($[3] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t3 = (e) => setName(e.target.value);
|
||||
$[3] = t3;
|
||||
} else {
|
||||
t3 = $[3];
|
||||
}
|
||||
let t4;
|
||||
if ($[4] !== name) {
|
||||
t4 = (
|
||||
<div>
|
||||
<input value={name} onChange={t3} />
|
||||
</div>
|
||||
);
|
||||
$[4] = name;
|
||||
$[5] = t4;
|
||||
} else {
|
||||
t4 = $[5];
|
||||
}
|
||||
return t4;
|
||||
|
||||
useEffect(() => {
|
||||
setName(initialName);
|
||||
}, [initialName]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<input value={name} onChange={(e) => setName(e.target.value)} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
@@ -83,7 +56,7 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
## Logs
|
||||
|
||||
```
|
||||
{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":107},"end":{"line":16,"column":1,"index":359},"filename":"derived-state-from-prop-setter-call-outside-effect-no-error.ts"},"fnName":"Component","memoSlots":6,"memoBlocks":3,"memoValues":4,"prunedMemoBlocks":0,"prunedMemoValues":0}
|
||||
{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":126},"end":{"line":16,"column":1,"index":378},"filename":"derived-state-from-prop-setter-call-outside-effect-no-error.ts"},"fnName":"Component","memoSlots":6,"memoBlocks":3,"memoValues":4,"prunedMemoBlocks":0,"prunedMemoValues":0}
|
||||
```
|
||||
|
||||
### Eval output
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
|
||||
import {useEffect, useState} from 'react';
|
||||
|
||||
function Component({initialName}) {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @validateNoDerivedComputationsInEffects_exp
|
||||
// @validateNoDerivedComputationsInEffects_exp @outputMode:"lint"
|
||||
|
||||
function Component({value}) {
|
||||
const [checked, setChecked] = useState('');
|
||||
@@ -19,36 +19,16 @@ function Component({value}) {
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp
|
||||
// @validateNoDerivedComputationsInEffects_exp @outputMode:"lint"
|
||||
|
||||
function Component(t0) {
|
||||
const $ = _c(5);
|
||||
const { value } = t0;
|
||||
function Component({ value }) {
|
||||
const [checked, setChecked] = useState("");
|
||||
let t1;
|
||||
let t2;
|
||||
if ($[0] !== value) {
|
||||
t1 = () => {
|
||||
setChecked(value === "" ? [] : value.split(","));
|
||||
};
|
||||
t2 = [value];
|
||||
$[0] = value;
|
||||
$[1] = t1;
|
||||
$[2] = t2;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
t2 = $[2];
|
||||
}
|
||||
useEffect(t1, t2);
|
||||
let t3;
|
||||
if ($[3] !== checked) {
|
||||
t3 = <div>{checked}</div>;
|
||||
$[3] = checked;
|
||||
$[4] = t3;
|
||||
} else {
|
||||
t3 = $[4];
|
||||
}
|
||||
return t3;
|
||||
|
||||
useEffect(() => {
|
||||
setChecked(value === "" ? [] : value.split(","));
|
||||
}, [value]);
|
||||
|
||||
return <div>{checked}</div>;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @validateNoDerivedComputationsInEffects_exp
|
||||
// @validateNoDerivedComputationsInEffects_exp @outputMode:"lint"
|
||||
|
||||
function Component({value}) {
|
||||
const [checked, setChecked] = useState('');
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
|
||||
import {useEffect, useState} from 'react';
|
||||
|
||||
function MockComponent({onSet}) {
|
||||
@@ -28,50 +28,20 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
function MockComponent(t0) {
|
||||
const $ = _c(2);
|
||||
const { onSet } = t0;
|
||||
let t1;
|
||||
if ($[0] !== onSet) {
|
||||
t1 = <div onClick={() => onSet("clicked")}>Mock Component</div>;
|
||||
$[0] = onSet;
|
||||
$[1] = t1;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
}
|
||||
return t1;
|
||||
function MockComponent({ onSet }) {
|
||||
return <div onClick={() => onSet("clicked")}>Mock Component</div>;
|
||||
}
|
||||
|
||||
function Component(t0) {
|
||||
const $ = _c(4);
|
||||
const { propValue } = t0;
|
||||
const [, setValue] = useState(null);
|
||||
let t1;
|
||||
let t2;
|
||||
if ($[0] !== propValue) {
|
||||
t1 = () => {
|
||||
setValue(propValue);
|
||||
};
|
||||
t2 = [propValue];
|
||||
$[0] = propValue;
|
||||
$[1] = t1;
|
||||
$[2] = t2;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
t2 = $[2];
|
||||
}
|
||||
useEffect(t1, t2);
|
||||
let t3;
|
||||
if ($[3] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t3 = <MockComponent onSet={setValue} />;
|
||||
$[3] = t3;
|
||||
} else {
|
||||
t3 = $[3];
|
||||
}
|
||||
return t3;
|
||||
function Component({ propValue }) {
|
||||
const [value, setValue] = useState(null);
|
||||
useEffect(() => {
|
||||
setValue(propValue);
|
||||
}, [propValue]);
|
||||
|
||||
return <MockComponent onSet={setValue} />;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
@@ -84,8 +54,8 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
## Logs
|
||||
|
||||
```
|
||||
{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":107},"end":{"line":6,"column":1,"index":211},"filename":"derived-state-from-prop-setter-used-outside-effect-no-error.ts"},"fnName":"MockComponent","memoSlots":2,"memoBlocks":1,"memoValues":1,"prunedMemoBlocks":0,"prunedMemoValues":0}
|
||||
{"kind":"CompileSuccess","fnLoc":{"start":{"line":8,"column":0,"index":213},"end":{"line":15,"column":1,"index":402},"filename":"derived-state-from-prop-setter-used-outside-effect-no-error.ts"},"fnName":"Component","memoSlots":4,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
|
||||
{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":126},"end":{"line":6,"column":1,"index":230},"filename":"derived-state-from-prop-setter-used-outside-effect-no-error.ts"},"fnName":"MockComponent","memoSlots":2,"memoBlocks":1,"memoValues":1,"prunedMemoBlocks":0,"prunedMemoValues":0}
|
||||
{"kind":"CompileSuccess","fnLoc":{"start":{"line":8,"column":0,"index":232},"end":{"line":15,"column":1,"index":421},"filename":"derived-state-from-prop-setter-used-outside-effect-no-error.ts"},"fnName":"Component","memoSlots":4,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
|
||||
```
|
||||
|
||||
### Eval output
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
|
||||
import {useEffect, useState} from 'react';
|
||||
|
||||
function MockComponent({onSet}) {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
|
||||
import {useEffect, useState} from 'react';
|
||||
|
||||
function Component({value}) {
|
||||
@@ -26,38 +26,18 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
function Component(t0) {
|
||||
const $ = _c(5);
|
||||
const { value } = t0;
|
||||
function Component({ value }) {
|
||||
const [localValue, setLocalValue] = useState("");
|
||||
let t1;
|
||||
let t2;
|
||||
if ($[0] !== value) {
|
||||
t1 = () => {
|
||||
setLocalValue(value);
|
||||
document.title = `Value: ${value}`;
|
||||
};
|
||||
t2 = [value];
|
||||
$[0] = value;
|
||||
$[1] = t1;
|
||||
$[2] = t2;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
t2 = $[2];
|
||||
}
|
||||
useEffect(t1, t2);
|
||||
let t3;
|
||||
if ($[3] !== localValue) {
|
||||
t3 = <div>{localValue}</div>;
|
||||
$[3] = localValue;
|
||||
$[4] = t3;
|
||||
} else {
|
||||
t3 = $[4];
|
||||
}
|
||||
return t3;
|
||||
|
||||
useEffect(() => {
|
||||
setLocalValue(value);
|
||||
document.title = `Value: ${value}`;
|
||||
}, [value]);
|
||||
|
||||
return <div>{localValue}</div>;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
@@ -70,8 +50,8 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
## Logs
|
||||
|
||||
```
|
||||
{"kind":"CompileError","detail":{"options":{"description":"Using an effect triggers an additional render which can hurt performance and user experience, potentially briefly showing stale values to the user\n\nThis setState call is setting a derived value that depends on the following reactive sources:\n\nProps: [value]\n\nData Flow Tree:\n└── value (Prop)\n\nSee: https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state","category":"EffectDerivationsOfState","reason":"You might not need an effect. Derive values in render, not effects.","details":[{"kind":"error","loc":{"start":{"line":8,"column":4,"index":214},"end":{"line":8,"column":17,"index":227},"filename":"derived-state-from-prop-with-side-effect.ts","identifierName":"setLocalValue"},"message":"This should be computed during render, not in an effect"}]}},"fnLoc":null}
|
||||
{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":107},"end":{"line":13,"column":1,"index":327},"filename":"derived-state-from-prop-with-side-effect.ts"},"fnName":"Component","memoSlots":5,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
|
||||
{"kind":"CompileError","detail":{"options":{"description":"Using an effect triggers an additional render which can hurt performance and user experience, potentially briefly showing stale values to the user\n\nThis setState call is setting a derived value that depends on the following reactive sources:\n\nProps: [value]\n\nData Flow Tree:\n└── value (Prop)\n\nSee: https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state","category":"EffectDerivationsOfState","reason":"You might not need an effect. Derive values in render, not effects.","details":[{"kind":"error","loc":{"start":{"line":8,"column":4,"index":233},"end":{"line":8,"column":17,"index":246},"filename":"derived-state-from-prop-with-side-effect.ts","identifierName":"setLocalValue"},"message":"This should be computed during render, not in an effect"}]}},"fnLoc":null}
|
||||
{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":126},"end":{"line":13,"column":1,"index":346},"filename":"derived-state-from-prop-with-side-effect.ts"},"fnName":"Component","memoSlots":5,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
|
||||
```
|
||||
|
||||
### Eval output
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
|
||||
import {useEffect, useState} from 'react';
|
||||
|
||||
function Component({value}) {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
|
||||
import {useEffect, useState, useRef} from 'react';
|
||||
|
||||
export default function Component({test}) {
|
||||
@@ -27,39 +27,19 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
|
||||
import { useEffect, useState, useRef } from "react";
|
||||
|
||||
export default function Component(t0) {
|
||||
const $ = _c(5);
|
||||
const { test } = t0;
|
||||
export default function Component({ test }) {
|
||||
const [local, setLocal] = useState("");
|
||||
|
||||
const myRef = useRef(null);
|
||||
let t1;
|
||||
let t2;
|
||||
if ($[0] !== test) {
|
||||
t1 = () => {
|
||||
setLocal(myRef.current + test);
|
||||
};
|
||||
t2 = [test];
|
||||
$[0] = test;
|
||||
$[1] = t1;
|
||||
$[2] = t2;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
t2 = $[2];
|
||||
}
|
||||
useEffect(t1, t2);
|
||||
let t3;
|
||||
if ($[3] !== local) {
|
||||
t3 = <>{local}</>;
|
||||
$[3] = local;
|
||||
$[4] = t3;
|
||||
} else {
|
||||
t3 = $[4];
|
||||
}
|
||||
return t3;
|
||||
|
||||
useEffect(() => {
|
||||
setLocal(myRef.current + test);
|
||||
}, [test]);
|
||||
|
||||
return <>{local}</>;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
@@ -72,7 +52,7 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
## Logs
|
||||
|
||||
```
|
||||
{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":15,"index":130},"end":{"line":14,"column":1,"index":328},"filename":"derived-state-from-ref-and-state-no-error.ts"},"fnName":"Component","memoSlots":5,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
|
||||
{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":15,"index":149},"end":{"line":14,"column":1,"index":347},"filename":"derived-state-from-ref-and-state-no-error.ts"},"fnName":"Component","memoSlots":5,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
|
||||
```
|
||||
|
||||
### Eval output
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
|
||||
import {useEffect, useState, useRef} from 'react';
|
||||
|
||||
export default function Component({test}) {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
|
||||
import {useEffect, useState} from 'react';
|
||||
|
||||
function Component({propValue}) {
|
||||
@@ -30,48 +30,22 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
function Component(t0) {
|
||||
const $ = _c(6);
|
||||
const { propValue } = t0;
|
||||
function Component({ propValue }) {
|
||||
const [value, setValue] = useState(null);
|
||||
let t1;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t1 = function localFunction() {
|
||||
console.log("local function");
|
||||
};
|
||||
$[0] = t1;
|
||||
} else {
|
||||
t1 = $[0];
|
||||
|
||||
function localFunction() {
|
||||
console.log("local function");
|
||||
}
|
||||
const localFunction = t1;
|
||||
let t2;
|
||||
let t3;
|
||||
if ($[1] !== propValue) {
|
||||
t2 = () => {
|
||||
setValue(propValue);
|
||||
localFunction();
|
||||
};
|
||||
t3 = [propValue];
|
||||
$[1] = propValue;
|
||||
$[2] = t2;
|
||||
$[3] = t3;
|
||||
} else {
|
||||
t2 = $[2];
|
||||
t3 = $[3];
|
||||
}
|
||||
useEffect(t2, t3);
|
||||
let t4;
|
||||
if ($[4] !== value) {
|
||||
t4 = <div>{value}</div>;
|
||||
$[4] = value;
|
||||
$[5] = t4;
|
||||
} else {
|
||||
t4 = $[5];
|
||||
}
|
||||
return t4;
|
||||
|
||||
useEffect(() => {
|
||||
setValue(propValue);
|
||||
localFunction();
|
||||
}, [propValue]);
|
||||
|
||||
return <div>{value}</div>;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
@@ -84,8 +58,8 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
## Logs
|
||||
|
||||
```
|
||||
{"kind":"CompileError","detail":{"options":{"description":"Using an effect triggers an additional render which can hurt performance and user experience, potentially briefly showing stale values to the user\n\nThis setState call is setting a derived value that depends on the following reactive sources:\n\nProps: [propValue]\n\nData Flow Tree:\n└── propValue (Prop)\n\nSee: https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state","category":"EffectDerivationsOfState","reason":"You might not need an effect. Derive values in render, not effects.","details":[{"kind":"error","loc":{"start":{"line":12,"column":4,"index":279},"end":{"line":12,"column":12,"index":287},"filename":"effect-contains-local-function-call.ts","identifierName":"setValue"},"message":"This should be computed during render, not in an effect"}]}},"fnLoc":null}
|
||||
{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":107},"end":{"line":17,"column":1,"index":371},"filename":"effect-contains-local-function-call.ts"},"fnName":"Component","memoSlots":6,"memoBlocks":3,"memoValues":4,"prunedMemoBlocks":0,"prunedMemoValues":0}
|
||||
{"kind":"CompileError","detail":{"options":{"description":"Using an effect triggers an additional render which can hurt performance and user experience, potentially briefly showing stale values to the user\n\nThis setState call is setting a derived value that depends on the following reactive sources:\n\nProps: [propValue]\n\nData Flow Tree:\n└── propValue (Prop)\n\nSee: https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state","category":"EffectDerivationsOfState","reason":"You might not need an effect. Derive values in render, not effects.","details":[{"kind":"error","loc":{"start":{"line":12,"column":4,"index":298},"end":{"line":12,"column":12,"index":306},"filename":"effect-contains-local-function-call.ts","identifierName":"setValue"},"message":"This should be computed during render, not in an effect"}]}},"fnLoc":null}
|
||||
{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":126},"end":{"line":17,"column":1,"index":390},"filename":"effect-contains-local-function-call.ts"},"fnName":"Component","memoSlots":6,"memoBlocks":3,"memoValues":4,"prunedMemoBlocks":0,"prunedMemoValues":0}
|
||||
```
|
||||
|
||||
### Eval output
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
|
||||
import {useEffect, useState} from 'react';
|
||||
|
||||
function Component({propValue}) {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
|
||||
import {useEffect, useState} from 'react';
|
||||
|
||||
function Component({propValue, onChange}) {
|
||||
@@ -25,43 +25,17 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
function Component(t0) {
|
||||
const $ = _c(7);
|
||||
const { propValue, onChange } = t0;
|
||||
function Component({ propValue, onChange }) {
|
||||
const [value, setValue] = useState(null);
|
||||
let t1;
|
||||
if ($[0] !== onChange || $[1] !== propValue) {
|
||||
t1 = () => {
|
||||
setValue(propValue);
|
||||
onChange();
|
||||
};
|
||||
$[0] = onChange;
|
||||
$[1] = propValue;
|
||||
$[2] = t1;
|
||||
} else {
|
||||
t1 = $[2];
|
||||
}
|
||||
let t2;
|
||||
if ($[3] !== propValue) {
|
||||
t2 = [propValue];
|
||||
$[3] = propValue;
|
||||
$[4] = t2;
|
||||
} else {
|
||||
t2 = $[4];
|
||||
}
|
||||
useEffect(t1, t2);
|
||||
let t3;
|
||||
if ($[5] !== value) {
|
||||
t3 = <div>{value}</div>;
|
||||
$[5] = value;
|
||||
$[6] = t3;
|
||||
} else {
|
||||
t3 = $[6];
|
||||
}
|
||||
return t3;
|
||||
useEffect(() => {
|
||||
setValue(propValue);
|
||||
onChange();
|
||||
}, [propValue]);
|
||||
|
||||
return <div>{value}</div>;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
@@ -74,8 +48,8 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
## Logs
|
||||
|
||||
```
|
||||
{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":107},"end":{"line":12,"column":1,"index":306},"filename":"effect-contains-prop-function-call-no-error.ts"},"fnName":"Component","memoSlots":7,"memoBlocks":3,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
|
||||
{"kind":"CompileSuccess","fnLoc":{"start":{"line":16,"column":41,"index":402},"end":{"line":16,"column":49,"index":410},"filename":"effect-contains-prop-function-call-no-error.ts"},"fnName":null,"memoSlots":0,"memoBlocks":0,"memoValues":0,"prunedMemoBlocks":0,"prunedMemoValues":0}
|
||||
{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":126},"end":{"line":12,"column":1,"index":325},"filename":"effect-contains-prop-function-call-no-error.ts"},"fnName":"Component","memoSlots":7,"memoBlocks":3,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
|
||||
{"kind":"CompileSuccess","fnLoc":{"start":{"line":16,"column":41,"index":421},"end":{"line":16,"column":49,"index":429},"filename":"effect-contains-prop-function-call-no-error.ts"},"fnName":null,"memoSlots":0,"memoBlocks":0,"memoValues":0,"prunedMemoBlocks":0,"prunedMemoValues":0}
|
||||
```
|
||||
|
||||
### Eval output
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
|
||||
import {useEffect, useState} from 'react';
|
||||
|
||||
function Component({propValue, onChange}) {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
|
||||
|
||||
function Component({prop}) {
|
||||
const [s, setS] = useState(0);
|
||||
@@ -18,36 +18,15 @@ function Component({prop}) {
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
|
||||
|
||||
function Component(t0) {
|
||||
const $ = _c(5);
|
||||
const { prop } = t0;
|
||||
const [, setS] = useState(0);
|
||||
let t1;
|
||||
let t2;
|
||||
if ($[0] !== prop) {
|
||||
t1 = () => {
|
||||
setS(prop);
|
||||
};
|
||||
t2 = [prop, setS];
|
||||
$[0] = prop;
|
||||
$[1] = t1;
|
||||
$[2] = t2;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
t2 = $[2];
|
||||
}
|
||||
useEffect(t1, t2);
|
||||
let t3;
|
||||
if ($[3] !== prop) {
|
||||
t3 = <div>{prop}</div>;
|
||||
$[3] = prop;
|
||||
$[4] = t3;
|
||||
} else {
|
||||
t3 = $[4];
|
||||
}
|
||||
return t3;
|
||||
function Component({ prop }) {
|
||||
const [s, setS] = useState(0);
|
||||
useEffect(() => {
|
||||
setS(prop);
|
||||
}, [prop, setS]);
|
||||
|
||||
return <div>{prop}</div>;
|
||||
}
|
||||
|
||||
```
|
||||
@@ -55,8 +34,8 @@ function Component(t0) {
|
||||
## Logs
|
||||
|
||||
```
|
||||
{"kind":"CompileError","detail":{"options":{"description":"Using an effect triggers an additional render which can hurt performance and user experience, potentially briefly showing stale values to the user\n\nThis setState call is setting a derived value that depends on the following reactive sources:\n\nProps: [prop]\n\nData Flow Tree:\n└── prop (Prop)\n\nSee: https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state","category":"EffectDerivationsOfState","reason":"You might not need an effect. Derive values in render, not effects.","details":[{"kind":"error","loc":{"start":{"line":6,"column":4,"index":150},"end":{"line":6,"column":8,"index":154},"filename":"effect-used-in-dep-array-still-errors.ts","identifierName":"setS"},"message":"This should be computed during render, not in an effect"}]}},"fnLoc":null}
|
||||
{"kind":"CompileSuccess","fnLoc":{"start":{"line":3,"column":0,"index":64},"end":{"line":10,"column":1,"index":212},"filename":"effect-used-in-dep-array-still-errors.ts"},"fnName":"Component","memoSlots":5,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
|
||||
{"kind":"CompileError","detail":{"options":{"description":"Using an effect triggers an additional render which can hurt performance and user experience, potentially briefly showing stale values to the user\n\nThis setState call is setting a derived value that depends on the following reactive sources:\n\nProps: [prop]\n\nData Flow Tree:\n└── prop (Prop)\n\nSee: https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state","category":"EffectDerivationsOfState","reason":"You might not need an effect. Derive values in render, not effects.","details":[{"kind":"error","loc":{"start":{"line":6,"column":4,"index":169},"end":{"line":6,"column":8,"index":173},"filename":"effect-used-in-dep-array-still-errors.ts","identifierName":"setS"},"message":"This should be computed during render, not in an effect"}]}},"fnLoc":null}
|
||||
{"kind":"CompileSuccess","fnLoc":{"start":{"line":3,"column":0,"index":83},"end":{"line":10,"column":1,"index":231},"filename":"effect-used-in-dep-array-still-errors.ts"},"fnName":"Component","memoSlots":5,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
|
||||
```
|
||||
|
||||
### Eval output
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
|
||||
|
||||
function Component({prop}) {
|
||||
const [s, setS] = useState(0);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
|
||||
|
||||
import {useEffect, useState} from 'react';
|
||||
|
||||
@@ -29,39 +29,26 @@ function Component(file: File) {
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
function Component(file) {
|
||||
const $ = _c(5);
|
||||
function Component(file: File) {
|
||||
const [imageUrl, setImageUrl] = useState(null);
|
||||
let t0;
|
||||
let t1;
|
||||
if ($[0] !== file) {
|
||||
t0 = () => {
|
||||
const imageUrlPrepared = URL.createObjectURL(file);
|
||||
setImageUrl(imageUrlPrepared);
|
||||
return () => URL.revokeObjectURL(imageUrlPrepared);
|
||||
};
|
||||
t1 = [file];
|
||||
$[0] = file;
|
||||
$[1] = t0;
|
||||
$[2] = t1;
|
||||
} else {
|
||||
t0 = $[1];
|
||||
t1 = $[2];
|
||||
}
|
||||
useEffect(t0, t1);
|
||||
let t2;
|
||||
if ($[3] !== imageUrl) {
|
||||
t2 = <Image src={imageUrl} xstyle={styles.imageSizeLimits} />;
|
||||
$[3] = imageUrl;
|
||||
$[4] = t2;
|
||||
} else {
|
||||
t2 = $[4];
|
||||
}
|
||||
return t2;
|
||||
|
||||
/*
|
||||
* Cleaning up the variable or a source of the variable used to setState
|
||||
* inside the effect communicates that we always need to clean up something
|
||||
* which is a valid use case for useEffect. In which case we want to
|
||||
* avoid an throwing
|
||||
*/
|
||||
useEffect(() => {
|
||||
const imageUrlPrepared = URL.createObjectURL(file);
|
||||
setImageUrl(imageUrlPrepared);
|
||||
return () => URL.revokeObjectURL(imageUrlPrepared);
|
||||
}, [file]);
|
||||
|
||||
return <Image src={imageUrl} xstyle={styles.imageSizeLimits} />;
|
||||
}
|
||||
|
||||
```
|
||||
@@ -69,7 +56,7 @@ function Component(file) {
|
||||
## Logs
|
||||
|
||||
```
|
||||
{"kind":"CompileSuccess","fnLoc":{"start":{"line":5,"column":0,"index":108},"end":{"line":21,"column":1,"index":700},"filename":"effect-with-cleanup-function-depending-on-derived-computation-value.ts"},"fnName":"Component","memoSlots":5,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
|
||||
{"kind":"CompileSuccess","fnLoc":{"start":{"line":5,"column":0,"index":127},"end":{"line":21,"column":1,"index":719},"filename":"effect-with-cleanup-function-depending-on-derived-computation-value.ts"},"fnName":"Component","memoSlots":5,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
|
||||
```
|
||||
|
||||
### Eval output
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
|
||||
|
||||
import {useEffect, useState} from 'react';
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
|
||||
import {useEffect, useState} from 'react';
|
||||
|
||||
function Component({propValue}) {
|
||||
@@ -25,38 +25,17 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
function Component(t0) {
|
||||
const $ = _c(5);
|
||||
const { propValue } = t0;
|
||||
function Component({ propValue }) {
|
||||
const [value, setValue] = useState(null);
|
||||
let t1;
|
||||
let t2;
|
||||
if ($[0] !== propValue) {
|
||||
t1 = () => {
|
||||
setValue(propValue);
|
||||
globalCall();
|
||||
};
|
||||
t2 = [propValue];
|
||||
$[0] = propValue;
|
||||
$[1] = t1;
|
||||
$[2] = t2;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
t2 = $[2];
|
||||
}
|
||||
useEffect(t1, t2);
|
||||
let t3;
|
||||
if ($[3] !== value) {
|
||||
t3 = <div>{value}</div>;
|
||||
$[3] = value;
|
||||
$[4] = t3;
|
||||
} else {
|
||||
t3 = $[4];
|
||||
}
|
||||
return t3;
|
||||
useEffect(() => {
|
||||
setValue(propValue);
|
||||
globalCall();
|
||||
}, [propValue]);
|
||||
|
||||
return <div>{value}</div>;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
@@ -69,7 +48,7 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
## Logs
|
||||
|
||||
```
|
||||
{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":107},"end":{"line":12,"column":1,"index":298},"filename":"effect-with-global-function-call-no-error.ts"},"fnName":"Component","memoSlots":5,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
|
||||
{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":126},"end":{"line":12,"column":1,"index":317},"filename":"effect-with-global-function-call-no-error.ts"},"fnName":"Component","memoSlots":5,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
|
||||
```
|
||||
|
||||
### Eval output
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
|
||||
import {useEffect, useState} from 'react';
|
||||
|
||||
function Component({propValue}) {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @validateNoDerivedComputationsInEffects_exp @enableTreatSetIdentifiersAsStateSetters @loggerTestOnly
|
||||
// @validateNoDerivedComputationsInEffects_exp @enableTreatSetIdentifiersAsStateSetters @loggerTestOnly @outputMode:"lint"
|
||||
|
||||
function Component({setParentState, prop}) {
|
||||
useEffect(() => {
|
||||
@@ -17,40 +17,14 @@ function Component({setParentState, prop}) {
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @enableTreatSetIdentifiersAsStateSetters @loggerTestOnly
|
||||
// @validateNoDerivedComputationsInEffects_exp @enableTreatSetIdentifiersAsStateSetters @loggerTestOnly @outputMode:"lint"
|
||||
|
||||
function Component(t0) {
|
||||
const $ = _c(7);
|
||||
const { setParentState, prop } = t0;
|
||||
let t1;
|
||||
if ($[0] !== prop || $[1] !== setParentState) {
|
||||
t1 = () => {
|
||||
setParentState(prop);
|
||||
};
|
||||
$[0] = prop;
|
||||
$[1] = setParentState;
|
||||
$[2] = t1;
|
||||
} else {
|
||||
t1 = $[2];
|
||||
}
|
||||
let t2;
|
||||
if ($[3] !== prop) {
|
||||
t2 = [prop];
|
||||
$[3] = prop;
|
||||
$[4] = t2;
|
||||
} else {
|
||||
t2 = $[4];
|
||||
}
|
||||
useEffect(t1, t2);
|
||||
let t3;
|
||||
if ($[5] !== prop) {
|
||||
t3 = <div>{prop}</div>;
|
||||
$[5] = prop;
|
||||
$[6] = t3;
|
||||
} else {
|
||||
t3 = $[6];
|
||||
}
|
||||
return t3;
|
||||
function Component({ setParentState, prop }) {
|
||||
useEffect(() => {
|
||||
setParentState(prop);
|
||||
}, [prop]);
|
||||
|
||||
return <div>{prop}</div>;
|
||||
}
|
||||
|
||||
```
|
||||
@@ -58,7 +32,7 @@ function Component(t0) {
|
||||
## Logs
|
||||
|
||||
```
|
||||
{"kind":"CompileSuccess","fnLoc":{"start":{"line":3,"column":0,"index":105},"end":{"line":9,"column":1,"index":240},"filename":"from-props-setstate-in-effect-no-error.ts"},"fnName":"Component","memoSlots":7,"memoBlocks":3,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
|
||||
{"kind":"CompileSuccess","fnLoc":{"start":{"line":3,"column":0,"index":124},"end":{"line":9,"column":1,"index":259},"filename":"from-props-setstate-in-effect-no-error.ts"},"fnName":"Component","memoSlots":7,"memoBlocks":3,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
|
||||
```
|
||||
|
||||
### Eval output
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @validateNoDerivedComputationsInEffects_exp @enableTreatSetIdentifiersAsStateSetters @loggerTestOnly
|
||||
// @validateNoDerivedComputationsInEffects_exp @enableTreatSetIdentifiersAsStateSetters @loggerTestOnly @outputMode:"lint"
|
||||
|
||||
function Component({setParentState, prop}) {
|
||||
useEffect(() => {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
|
||||
|
||||
function Component() {
|
||||
const [foo, setFoo] = useState({});
|
||||
@@ -40,66 +40,37 @@ function Component() {
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
|
||||
|
||||
function Component() {
|
||||
const $ = _c(9);
|
||||
let t0;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t0 = {};
|
||||
$[0] = t0;
|
||||
} else {
|
||||
t0 = $[0];
|
||||
}
|
||||
const [foo, setFoo] = useState(t0);
|
||||
let t1;
|
||||
if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t1 = new Set();
|
||||
$[1] = t1;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
}
|
||||
const [bar] = useState(t1);
|
||||
let t2;
|
||||
let t3;
|
||||
if ($[2] !== bar || $[3] !== foo) {
|
||||
t2 = () => {
|
||||
let isChanged = false;
|
||||
const [foo, setFoo] = useState({});
|
||||
const [bar, setBar] = useState(new Set());
|
||||
|
||||
const newData = foo.map((val) => {
|
||||
bar.someMethod(val);
|
||||
isChanged = true;
|
||||
});
|
||||
/*
|
||||
* isChanged is considered context of the effect's function expression,
|
||||
* if we don't bail out of effect mutation derivation tracking, isChanged
|
||||
* will inherit the sources of the effect's function expression.
|
||||
*
|
||||
* This is innacurate and with the multiple passes ends up causing an infinite loop.
|
||||
*/
|
||||
useEffect(() => {
|
||||
let isChanged = false;
|
||||
|
||||
if (isChanged) {
|
||||
setFoo(newData);
|
||||
}
|
||||
};
|
||||
const newData = foo.map((val) => {
|
||||
bar.someMethod(val);
|
||||
isChanged = true;
|
||||
});
|
||||
|
||||
t3 = [foo, bar];
|
||||
$[2] = bar;
|
||||
$[3] = foo;
|
||||
$[4] = t2;
|
||||
$[5] = t3;
|
||||
} else {
|
||||
t2 = $[4];
|
||||
t3 = $[5];
|
||||
}
|
||||
useEffect(t2, t3);
|
||||
let t4;
|
||||
if ($[6] !== bar || $[7] !== foo) {
|
||||
t4 = (
|
||||
<div>
|
||||
{foo}, {bar}
|
||||
</div>
|
||||
);
|
||||
$[6] = bar;
|
||||
$[7] = foo;
|
||||
$[8] = t4;
|
||||
} else {
|
||||
t4 = $[8];
|
||||
}
|
||||
return t4;
|
||||
if (isChanged) {
|
||||
setFoo(newData);
|
||||
}
|
||||
}, [foo, bar]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
{foo}, {bar}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
```
|
||||
@@ -107,8 +78,8 @@ function Component() {
|
||||
## Logs
|
||||
|
||||
```
|
||||
{"kind":"CompileError","detail":{"options":{"description":"Using an effect triggers an additional render which can hurt performance and user experience, potentially briefly showing stale values to the user\n\nThis setState call is setting a derived value that depends on the following reactive sources:\n\nState: [foo, bar]\n\nData Flow Tree:\n└── newData\n ├── foo (State)\n └── bar (State)\n\nSee: https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state","category":"EffectDerivationsOfState","reason":"You might not need an effect. Derive values in render, not effects.","details":[{"kind":"error","loc":{"start":{"line":23,"column":6,"index":663},"end":{"line":23,"column":12,"index":669},"filename":"function-expression-mutation-edge-case.ts","identifierName":"setFoo"},"message":"This should be computed during render, not in an effect"}]}},"fnLoc":null}
|
||||
{"kind":"CompileSuccess","fnLoc":{"start":{"line":3,"column":0,"index":64},"end":{"line":32,"column":1,"index":762},"filename":"function-expression-mutation-edge-case.ts"},"fnName":"Component","memoSlots":9,"memoBlocks":4,"memoValues":5,"prunedMemoBlocks":0,"prunedMemoValues":0}
|
||||
{"kind":"CompileError","detail":{"options":{"description":"Using an effect triggers an additional render which can hurt performance and user experience, potentially briefly showing stale values to the user\n\nThis setState call is setting a derived value that depends on the following reactive sources:\n\nState: [foo, bar]\n\nData Flow Tree:\n└── newData\n ├── foo (State)\n └── bar (State)\n\nSee: https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state","category":"EffectDerivationsOfState","reason":"You might not need an effect. Derive values in render, not effects.","details":[{"kind":"error","loc":{"start":{"line":23,"column":6,"index":682},"end":{"line":23,"column":12,"index":688},"filename":"function-expression-mutation-edge-case.ts","identifierName":"setFoo"},"message":"This should be computed during render, not in an effect"}]}},"fnLoc":null}
|
||||
{"kind":"CompileSuccess","fnLoc":{"start":{"line":3,"column":0,"index":83},"end":{"line":32,"column":1,"index":781},"filename":"function-expression-mutation-edge-case.ts"},"fnName":"Component","memoSlots":9,"memoBlocks":4,"memoValues":5,"prunedMemoBlocks":0,"prunedMemoValues":0}
|
||||
```
|
||||
|
||||
### Eval output
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
|
||||
|
||||
function Component() {
|
||||
const [foo, setFoo] = useState({});
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
|
||||
import {useEffect, useState} from 'react';
|
||||
|
||||
function Component() {
|
||||
@@ -28,38 +28,20 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
function Component() {
|
||||
const $ = _c(5);
|
||||
const [firstName] = useState("Taylor");
|
||||
const [firstName, setFirstName] = useState("Taylor");
|
||||
const lastName = "Swift";
|
||||
|
||||
// 🔴 Avoid: redundant state and unnecessary Effect
|
||||
const [fullName, setFullName] = useState("");
|
||||
let t0;
|
||||
let t1;
|
||||
if ($[0] !== firstName) {
|
||||
t0 = () => {
|
||||
setFullName(firstName + " " + "Swift");
|
||||
};
|
||||
t1 = [firstName, "Swift"];
|
||||
$[0] = firstName;
|
||||
$[1] = t0;
|
||||
$[2] = t1;
|
||||
} else {
|
||||
t0 = $[1];
|
||||
t1 = $[2];
|
||||
}
|
||||
useEffect(t0, t1);
|
||||
let t2;
|
||||
if ($[3] !== fullName) {
|
||||
t2 = <div>{fullName}</div>;
|
||||
$[3] = fullName;
|
||||
$[4] = t2;
|
||||
} else {
|
||||
t2 = $[4];
|
||||
}
|
||||
return t2;
|
||||
useEffect(() => {
|
||||
setFullName(firstName + " " + lastName);
|
||||
}, [firstName, lastName]);
|
||||
|
||||
return <div>{fullName}</div>;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
@@ -72,8 +54,8 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
## Logs
|
||||
|
||||
```
|
||||
{"kind":"CompileError","detail":{"options":{"description":"Using an effect triggers an additional render which can hurt performance and user experience, potentially briefly showing stale values to the user\n\nThis setState call is setting a derived value that depends on the following reactive sources:\n\nState: [firstName]\n\nData Flow Tree:\n└── firstName (State)\n\nSee: https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state","category":"EffectDerivationsOfState","reason":"You might not need an effect. Derive values in render, not effects.","details":[{"kind":"error","loc":{"start":{"line":11,"column":4,"index":341},"end":{"line":11,"column":15,"index":352},"filename":"invalid-derived-computation-in-effect.ts","identifierName":"setFullName"},"message":"This should be computed during render, not in an effect"}]}},"fnLoc":null}
|
||||
{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":107},"end":{"line":15,"column":1,"index":445},"filename":"invalid-derived-computation-in-effect.ts"},"fnName":"Component","memoSlots":5,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
|
||||
{"kind":"CompileError","detail":{"options":{"description":"Using an effect triggers an additional render which can hurt performance and user experience, potentially briefly showing stale values to the user\n\nThis setState call is setting a derived value that depends on the following reactive sources:\n\nState: [firstName]\n\nData Flow Tree:\n└── firstName (State)\n\nSee: https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state","category":"EffectDerivationsOfState","reason":"You might not need an effect. Derive values in render, not effects.","details":[{"kind":"error","loc":{"start":{"line":11,"column":4,"index":360},"end":{"line":11,"column":15,"index":371},"filename":"invalid-derived-computation-in-effect.ts","identifierName":"setFullName"},"message":"This should be computed during render, not in an effect"}]}},"fnLoc":null}
|
||||
{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":126},"end":{"line":15,"column":1,"index":464},"filename":"invalid-derived-computation-in-effect.ts"},"fnName":"Component","memoSlots":5,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
|
||||
```
|
||||
|
||||
### Eval output
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
|
||||
import {useEffect, useState} from 'react';
|
||||
|
||||
function Component() {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
|
||||
import {useEffect, useState} from 'react';
|
||||
|
||||
export default function Component(props) {
|
||||
@@ -26,39 +26,18 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
export default function Component(props) {
|
||||
const $ = _c(7);
|
||||
const [displayValue, setDisplayValue] = useState("");
|
||||
let t0;
|
||||
let t1;
|
||||
if ($[0] !== props.prefix || $[1] !== props.suffix || $[2] !== props.value) {
|
||||
t0 = () => {
|
||||
const computed = props.prefix + props.value + props.suffix;
|
||||
setDisplayValue(computed);
|
||||
};
|
||||
t1 = [props.prefix, props.value, props.suffix];
|
||||
$[0] = props.prefix;
|
||||
$[1] = props.suffix;
|
||||
$[2] = props.value;
|
||||
$[3] = t0;
|
||||
$[4] = t1;
|
||||
} else {
|
||||
t0 = $[3];
|
||||
t1 = $[4];
|
||||
}
|
||||
useEffect(t0, t1);
|
||||
let t2;
|
||||
if ($[5] !== displayValue) {
|
||||
t2 = <div>{displayValue}</div>;
|
||||
$[5] = displayValue;
|
||||
$[6] = t2;
|
||||
} else {
|
||||
t2 = $[6];
|
||||
}
|
||||
return t2;
|
||||
|
||||
useEffect(() => {
|
||||
const computed = props.prefix + props.value + props.suffix;
|
||||
setDisplayValue(computed);
|
||||
}, [props.prefix, props.value, props.suffix]);
|
||||
|
||||
return <div>{displayValue}</div>;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
@@ -71,8 +50,8 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
## Logs
|
||||
|
||||
```
|
||||
{"kind":"CompileError","detail":{"options":{"description":"Using an effect triggers an additional render which can hurt performance and user experience, potentially briefly showing stale values to the user\n\nThis setState call is setting a derived value that depends on the following reactive sources:\n\nProps: [props]\n\nData Flow Tree:\n└── computed\n └── props (Prop)\n\nSee: https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state","category":"EffectDerivationsOfState","reason":"You might not need an effect. Derive values in render, not effects.","details":[{"kind":"error","loc":{"start":{"line":9,"column":4,"index":295},"end":{"line":9,"column":19,"index":310},"filename":"invalid-derived-state-from-computed-props.ts","identifierName":"setDisplayValue"},"message":"This should be computed during render, not in an effect"}]}},"fnLoc":null}
|
||||
{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":15,"index":122},"end":{"line":13,"column":1,"index":409},"filename":"invalid-derived-state-from-computed-props.ts"},"fnName":"Component","memoSlots":7,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
|
||||
{"kind":"CompileError","detail":{"options":{"description":"Using an effect triggers an additional render which can hurt performance and user experience, potentially briefly showing stale values to the user\n\nThis setState call is setting a derived value that depends on the following reactive sources:\n\nProps: [props]\n\nData Flow Tree:\n└── computed\n └── props (Prop)\n\nSee: https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state","category":"EffectDerivationsOfState","reason":"You might not need an effect. Derive values in render, not effects.","details":[{"kind":"error","loc":{"start":{"line":9,"column":4,"index":314},"end":{"line":9,"column":19,"index":329},"filename":"invalid-derived-state-from-computed-props.ts","identifierName":"setDisplayValue"},"message":"This should be computed during render, not in an effect"}]}},"fnLoc":null}
|
||||
{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":15,"index":141},"end":{"line":13,"column":1,"index":428},"filename":"invalid-derived-state-from-computed-props.ts"},"fnName":"Component","memoSlots":7,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
|
||||
```
|
||||
|
||||
### Eval output
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
|
||||
import {useEffect, useState} from 'react';
|
||||
|
||||
export default function Component(props) {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
|
||||
import {useEffect, useState} from 'react';
|
||||
|
||||
export default function Component({props}) {
|
||||
@@ -27,40 +27,19 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
export default function Component(t0) {
|
||||
const $ = _c(6);
|
||||
const { props } = t0;
|
||||
export default function Component({ props }) {
|
||||
const [fullName, setFullName] = useState(
|
||||
props.firstName + " " + props.lastName,
|
||||
);
|
||||
let t1;
|
||||
let t2;
|
||||
if ($[0] !== props.firstName || $[1] !== props.lastName) {
|
||||
t1 = () => {
|
||||
setFullName(props.firstName + " " + props.lastName);
|
||||
};
|
||||
t2 = [props.firstName, props.lastName];
|
||||
$[0] = props.firstName;
|
||||
$[1] = props.lastName;
|
||||
$[2] = t1;
|
||||
$[3] = t2;
|
||||
} else {
|
||||
t1 = $[2];
|
||||
t2 = $[3];
|
||||
}
|
||||
useEffect(t1, t2);
|
||||
let t3;
|
||||
if ($[4] !== fullName) {
|
||||
t3 = <div>{fullName}</div>;
|
||||
$[4] = fullName;
|
||||
$[5] = t3;
|
||||
} else {
|
||||
t3 = $[5];
|
||||
}
|
||||
return t3;
|
||||
|
||||
useEffect(() => {
|
||||
setFullName(props.firstName + " " + props.lastName);
|
||||
}, [props.firstName, props.lastName]);
|
||||
|
||||
return <div>{fullName}</div>;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
@@ -73,8 +52,8 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
## Logs
|
||||
|
||||
```
|
||||
{"kind":"CompileError","detail":{"options":{"description":"Using an effect triggers an additional render which can hurt performance and user experience, potentially briefly showing stale values to the user\n\nThis setState call is setting a derived value that depends on the following reactive sources:\n\nProps: [props]\n\nData Flow Tree:\n└── props (Prop)\n\nSee: https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state","category":"EffectDerivationsOfState","reason":"You might not need an effect. Derive values in render, not effects.","details":[{"kind":"error","loc":{"start":{"line":10,"column":4,"index":269},"end":{"line":10,"column":15,"index":280},"filename":"invalid-derived-state-from-destructured-props.ts","identifierName":"setFullName"},"message":"This should be computed during render, not in an effect"}]}},"fnLoc":null}
|
||||
{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":15,"index":122},"end":{"line":14,"column":1,"index":397},"filename":"invalid-derived-state-from-destructured-props.ts"},"fnName":"Component","memoSlots":6,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
|
||||
{"kind":"CompileError","detail":{"options":{"description":"Using an effect triggers an additional render which can hurt performance and user experience, potentially briefly showing stale values to the user\n\nThis setState call is setting a derived value that depends on the following reactive sources:\n\nProps: [props]\n\nData Flow Tree:\n└── props (Prop)\n\nSee: https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state","category":"EffectDerivationsOfState","reason":"You might not need an effect. Derive values in render, not effects.","details":[{"kind":"error","loc":{"start":{"line":10,"column":4,"index":288},"end":{"line":10,"column":15,"index":299},"filename":"invalid-derived-state-from-destructured-props.ts","identifierName":"setFullName"},"message":"This should be computed during render, not in an effect"}]}},"fnLoc":null}
|
||||
{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":15,"index":141},"end":{"line":14,"column":1,"index":416},"filename":"invalid-derived-state-from-destructured-props.ts"},"fnName":"Component","memoSlots":6,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
|
||||
```
|
||||
|
||||
### Eval output
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
|
||||
import {useEffect, useState} from 'react';
|
||||
|
||||
export default function Component({props}) {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
|
||||
import {useEffect, useState, useRef} from 'react';
|
||||
|
||||
export default function Component({test}) {
|
||||
@@ -31,44 +31,23 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
|
||||
import { useEffect, useState, useRef } from "react";
|
||||
|
||||
export default function Component(t0) {
|
||||
const $ = _c(5);
|
||||
const { test } = t0;
|
||||
export default function Component({ test }) {
|
||||
const [local, setLocal] = useState(0);
|
||||
|
||||
const myRef = useRef(null);
|
||||
let t1;
|
||||
let t2;
|
||||
if ($[0] !== test) {
|
||||
t1 = () => {
|
||||
if (myRef.current) {
|
||||
setLocal(test);
|
||||
} else {
|
||||
setLocal(test + test);
|
||||
}
|
||||
};
|
||||
|
||||
t2 = [test];
|
||||
$[0] = test;
|
||||
$[1] = t1;
|
||||
$[2] = t2;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
t2 = $[2];
|
||||
}
|
||||
useEffect(t1, t2);
|
||||
let t3;
|
||||
if ($[3] !== local) {
|
||||
t3 = <>{local}</>;
|
||||
$[3] = local;
|
||||
$[4] = t3;
|
||||
} else {
|
||||
t3 = $[4];
|
||||
}
|
||||
return t3;
|
||||
useEffect(() => {
|
||||
if (myRef.current) {
|
||||
setLocal(test);
|
||||
} else {
|
||||
setLocal(test + test);
|
||||
}
|
||||
}, [test]);
|
||||
|
||||
return <>{local}</>;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
@@ -81,7 +60,7 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
## Logs
|
||||
|
||||
```
|
||||
{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":15,"index":130},"end":{"line":18,"column":1,"index":386},"filename":"ref-conditional-in-effect-no-error.ts"},"fnName":"Component","memoSlots":5,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
|
||||
{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":15,"index":149},"end":{"line":18,"column":1,"index":405},"filename":"ref-conditional-in-effect-no-error.ts"},"fnName":"Component","memoSlots":5,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
|
||||
```
|
||||
|
||||
### Eval output
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
|
||||
import {useEffect, useState, useRef} from 'react';
|
||||
|
||||
export default function Component({test}) {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
|
||||
|
||||
function Component({prop}) {
|
||||
const [s, setS] = useState();
|
||||
@@ -26,37 +26,23 @@ function Component({prop}) {
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
|
||||
|
||||
function Component(t0) {
|
||||
const $ = _c(5);
|
||||
const { prop } = t0;
|
||||
function Component({ prop }) {
|
||||
const [s, setS] = useState();
|
||||
const [second] = useState(prop);
|
||||
let t1;
|
||||
let t2;
|
||||
if ($[0] !== second) {
|
||||
t1 = () => {
|
||||
setS(second);
|
||||
};
|
||||
t2 = [second];
|
||||
$[0] = second;
|
||||
$[1] = t1;
|
||||
$[2] = t2;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
t2 = $[2];
|
||||
}
|
||||
useEffect(t1, t2);
|
||||
let t3;
|
||||
if ($[3] !== s) {
|
||||
t3 = <div>{s}</div>;
|
||||
$[3] = s;
|
||||
$[4] = t3;
|
||||
} else {
|
||||
t3 = $[4];
|
||||
}
|
||||
return t3;
|
||||
const [second, setSecond] = useState(prop);
|
||||
|
||||
/*
|
||||
* `second` is a source of state. It will inherit the value of `prop` in
|
||||
* the first render, but after that it will no longer be updated when
|
||||
* `prop` changes. So we shouldn't consider `second` as being derived from
|
||||
* `prop`
|
||||
*/
|
||||
useEffect(() => {
|
||||
setS(second);
|
||||
}, [second]);
|
||||
|
||||
return <div>{s}</div>;
|
||||
}
|
||||
|
||||
```
|
||||
@@ -64,8 +50,8 @@ function Component(t0) {
|
||||
## Logs
|
||||
|
||||
```
|
||||
{"kind":"CompileError","detail":{"options":{"description":"Using an effect triggers an additional render which can hurt performance and user experience, potentially briefly showing stale values to the user\n\nThis setState call is setting a derived value that depends on the following reactive sources:\n\nState: [second]\n\nData Flow Tree:\n└── second (State)\n\nSee: https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state","category":"EffectDerivationsOfState","reason":"You might not need an effect. Derive values in render, not effects.","details":[{"kind":"error","loc":{"start":{"line":14,"column":4,"index":443},"end":{"line":14,"column":8,"index":447},"filename":"usestate-derived-from-prop-no-show-in-data-flow-tree.ts","identifierName":"setS"},"message":"This should be computed during render, not in an effect"}]}},"fnLoc":null}
|
||||
{"kind":"CompileSuccess","fnLoc":{"start":{"line":3,"column":0,"index":64},"end":{"line":18,"column":1,"index":500},"filename":"usestate-derived-from-prop-no-show-in-data-flow-tree.ts"},"fnName":"Component","memoSlots":5,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
|
||||
{"kind":"CompileError","detail":{"options":{"description":"Using an effect triggers an additional render which can hurt performance and user experience, potentially briefly showing stale values to the user\n\nThis setState call is setting a derived value that depends on the following reactive sources:\n\nState: [second]\n\nData Flow Tree:\n└── second (State)\n\nSee: https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state","category":"EffectDerivationsOfState","reason":"You might not need an effect. Derive values in render, not effects.","details":[{"kind":"error","loc":{"start":{"line":14,"column":4,"index":462},"end":{"line":14,"column":8,"index":466},"filename":"usestate-derived-from-prop-no-show-in-data-flow-tree.ts","identifierName":"setS"},"message":"This should be computed during render, not in an effect"}]}},"fnLoc":null}
|
||||
{"kind":"CompileSuccess","fnLoc":{"start":{"line":3,"column":0,"index":83},"end":{"line":18,"column":1,"index":519},"filename":"usestate-derived-from-prop-no-show-in-data-flow-tree.ts"},"fnName":"Component","memoSlots":5,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
|
||||
```
|
||||
|
||||
### Eval output
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
|
||||
// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
|
||||
|
||||
function Component({prop}) {
|
||||
const [s, setS] = useState();
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @validateNoJSXInTryStatements
|
||||
// @validateNoJSXInTryStatements @outputMode:"lint"
|
||||
import {identity} from 'shared-runtime';
|
||||
|
||||
function Component(props) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @validateNoJSXInTryStatements
|
||||
// @validateNoJSXInTryStatements @outputMode:"lint"
|
||||
import {identity} from 'shared-runtime';
|
||||
|
||||
function Component(props) {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @validateNoJSXInTryStatements
|
||||
// @validateNoJSXInTryStatements @outputMode:"lint"
|
||||
function Component(props) {
|
||||
let el;
|
||||
try {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @validateNoJSXInTryStatements
|
||||
// @validateNoJSXInTryStatements @outputMode:"lint"
|
||||
function Component(props) {
|
||||
let el;
|
||||
try {
|
||||
|
||||
@@ -10,14 +10,28 @@ function Component({prop1, prop2}) {
|
||||
const y = x * 2;
|
||||
const arr = [x, y];
|
||||
const obj = {x, y};
|
||||
let destA, destB;
|
||||
if (y > 5) {
|
||||
[destA, destB] = arr;
|
||||
}
|
||||
|
||||
const [a, b] = arr;
|
||||
const {x: c, y: d} = obj;
|
||||
let sound;
|
||||
|
||||
if (y > 10) {
|
||||
sound = 'woof';
|
||||
} else {
|
||||
sound = 'meow';
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (a > 10) {
|
||||
console.log(a);
|
||||
console.log(sound);
|
||||
console.log(destA, destB);
|
||||
}
|
||||
}, [a]);
|
||||
}, [a, sound, destA, destB]);
|
||||
|
||||
const foo = useCallback(() => {
|
||||
return a + b;
|
||||
@@ -38,187 +52,343 @@ function Component({prop1, prop2}) {
|
||||
## Error
|
||||
|
||||
```
|
||||
Found 13 errors:
|
||||
Found 25 errors:
|
||||
|
||||
Todo: Important source location missing in generated code
|
||||
|
||||
Source location for VariableDeclarator is missing in the generated output. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
|
||||
Source location for Identifier is missing in the generated output. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
|
||||
|
||||
error.todo-missing-source-locations.ts:5:8
|
||||
error.todo-missing-source-locations.ts:4:9
|
||||
2 | import {useEffect, useCallback} from 'react';
|
||||
3 |
|
||||
4 | function Component({prop1, prop2}) {
|
||||
> 5 | const x = prop1 + prop2;
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
> 4 | function Component({prop1, prop2}) {
|
||||
| ^^^^^^^^^
|
||||
5 | const x = prop1 + prop2;
|
||||
6 | const y = x * 2;
|
||||
7 | const arr = [x, y];
|
||||
8 | const obj = {x, y};
|
||||
|
||||
Todo: Important source location missing in generated code
|
||||
|
||||
Source location for VariableDeclarator is missing in the generated output. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
|
||||
Source location for VariableDeclaration is missing in the generated output. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
|
||||
|
||||
error.todo-missing-source-locations.ts:6:8
|
||||
4 | function Component({prop1, prop2}) {
|
||||
5 | const x = prop1 + prop2;
|
||||
> 6 | const y = x * 2;
|
||||
| ^^^^^^^^^
|
||||
7 | const arr = [x, y];
|
||||
8 | const obj = {x, y};
|
||||
9 | const [a, b] = arr;
|
||||
|
||||
Todo: Important source location missing in generated code
|
||||
|
||||
Source location for VariableDeclarator is missing in the generated output. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
|
||||
|
||||
error.todo-missing-source-locations.ts:7:8
|
||||
5 | const x = prop1 + prop2;
|
||||
6 | const y = x * 2;
|
||||
> 7 | const arr = [x, y];
|
||||
| ^^^^^^^^^^^^
|
||||
8 | const obj = {x, y};
|
||||
9 | const [a, b] = arr;
|
||||
10 | const {x: c, y: d} = obj;
|
||||
|
||||
Todo: Important source location missing in generated code
|
||||
|
||||
Source location for VariableDeclarator is missing in the generated output. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
|
||||
|
||||
error.todo-missing-source-locations.ts:8:8
|
||||
6 | const y = x * 2;
|
||||
7 | const arr = [x, y];
|
||||
> 8 | const obj = {x, y};
|
||||
| ^^^^^^^^^^^^
|
||||
9 | const [a, b] = arr;
|
||||
10 | const {x: c, y: d} = obj;
|
||||
11 |
|
||||
|
||||
Todo: Important source location missing in generated code
|
||||
|
||||
Source location for VariableDeclarator is missing in the generated output. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
|
||||
|
||||
error.todo-missing-source-locations.ts:9:8
|
||||
error.todo-missing-source-locations.ts:9:2
|
||||
7 | const arr = [x, y];
|
||||
8 | const obj = {x, y};
|
||||
> 9 | const [a, b] = arr;
|
||||
| ^^^^^^^^^^^^
|
||||
10 | const {x: c, y: d} = obj;
|
||||
11 |
|
||||
12 | useEffect(() => {
|
||||
|
||||
Todo: Important source location missing in generated code
|
||||
|
||||
Source location for VariableDeclarator is missing in the generated output. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
|
||||
|
||||
error.todo-missing-source-locations.ts:10:8
|
||||
8 | const obj = {x, y};
|
||||
9 | const [a, b] = arr;
|
||||
> 10 | const {x: c, y: d} = obj;
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
11 |
|
||||
12 | useEffect(() => {
|
||||
13 | if (a > 10) {
|
||||
|
||||
Todo: Important source location missing in generated code
|
||||
|
||||
Source location for ExpressionStatement is missing in the generated output. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
|
||||
|
||||
error.todo-missing-source-locations.ts:12:2
|
||||
10 | const {x: c, y: d} = obj;
|
||||
11 |
|
||||
> 12 | useEffect(() => {
|
||||
> 9 | let destA, destB;
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
> 13 | if (a > 10) {
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
> 14 | console.log(a);
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
> 15 | }
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
> 16 | }, [a]);
|
||||
| ^^^^^^^^^^^
|
||||
17 |
|
||||
18 | const foo = useCallback(() => {
|
||||
19 | return a + b;
|
||||
10 | if (y > 5) {
|
||||
11 | [destA, destB] = arr;
|
||||
12 | }
|
||||
|
||||
Todo: Important source location missing in generated code
|
||||
|
||||
Source location for ExpressionStatement is missing in the generated output. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
|
||||
|
||||
error.todo-missing-source-locations.ts:14:6
|
||||
12 | useEffect(() => {
|
||||
13 | if (a > 10) {
|
||||
> 14 | console.log(a);
|
||||
| ^^^^^^^^^^^^^^^
|
||||
15 | }
|
||||
16 | }, [a]);
|
||||
17 |
|
||||
error.todo-missing-source-locations.ts:11:4
|
||||
9 | let destA, destB;
|
||||
10 | if (y > 5) {
|
||||
> 11 | [destA, destB] = arr;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
12 | }
|
||||
13 |
|
||||
14 | const [a, b] = arr;
|
||||
|
||||
Todo: Important source location missing in generated code
|
||||
|
||||
Source location for VariableDeclarator is missing in the generated output. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
|
||||
Source location for Identifier is missing in the generated output. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
|
||||
|
||||
error.todo-missing-source-locations.ts:18:8
|
||||
16 | }, [a]);
|
||||
error.todo-missing-source-locations.ts:15:9
|
||||
13 |
|
||||
14 | const [a, b] = arr;
|
||||
> 15 | const {x: c, y: d} = obj;
|
||||
| ^
|
||||
16 | let sound;
|
||||
17 |
|
||||
> 18 | const foo = useCallback(() => {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
> 19 | return a + b;
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
> 20 | }, [a, b]);
|
||||
| ^^^^^^^^^^^^^
|
||||
21 |
|
||||
22 | function bar() {
|
||||
23 | return (c + d) * 2;
|
||||
18 | if (y > 10) {
|
||||
|
||||
Todo: Important source location missing in generated code
|
||||
|
||||
Source location for ReturnStatement is missing in the generated output. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
|
||||
Source location for Identifier is missing in the generated output. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
|
||||
|
||||
error.todo-missing-source-locations.ts:15:15
|
||||
13 |
|
||||
14 | const [a, b] = arr;
|
||||
> 15 | const {x: c, y: d} = obj;
|
||||
| ^
|
||||
16 | let sound;
|
||||
17 |
|
||||
18 | if (y > 10) {
|
||||
|
||||
Todo: Important source location missing in generated code
|
||||
|
||||
Source location for VariableDeclaration is missing in the generated output. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
|
||||
|
||||
error.todo-missing-source-locations.ts:16:2
|
||||
14 | const [a, b] = arr;
|
||||
15 | const {x: c, y: d} = obj;
|
||||
> 16 | let sound;
|
||||
| ^^^^^^^^^^
|
||||
17 |
|
||||
18 | if (y > 10) {
|
||||
19 | sound = 'woof';
|
||||
|
||||
Todo: Important source location missing in generated code
|
||||
|
||||
Source location for ExpressionStatement is missing in the generated output. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
|
||||
|
||||
error.todo-missing-source-locations.ts:19:4
|
||||
17 |
|
||||
18 | const foo = useCallback(() => {
|
||||
> 19 | return a + b;
|
||||
| ^^^^^^^^^^^^^
|
||||
20 | }, [a, b]);
|
||||
21 |
|
||||
22 | function bar() {
|
||||
18 | if (y > 10) {
|
||||
> 19 | sound = 'woof';
|
||||
| ^^^^^^^^^^^^^^^
|
||||
20 | } else {
|
||||
21 | sound = 'meow';
|
||||
22 | }
|
||||
|
||||
Todo: Important source location missing in generated code
|
||||
Todo: Important source location has wrong node type in generated code
|
||||
|
||||
Source location for ReturnStatement is missing in the generated output. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
|
||||
Source location for Identifier exists in the generated output but with wrong node type(s): ExpressionStatement. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
|
||||
|
||||
error.todo-missing-source-locations.ts:23:4
|
||||
21 |
|
||||
22 | function bar() {
|
||||
> 23 | return (c + d) * 2;
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
24 | }
|
||||
25 |
|
||||
26 | console.log('Hello, world!');
|
||||
error.todo-missing-source-locations.ts:19:4
|
||||
17 |
|
||||
18 | if (y > 10) {
|
||||
> 19 | sound = 'woof';
|
||||
| ^^^^^
|
||||
20 | } else {
|
||||
21 | sound = 'meow';
|
||||
22 | }
|
||||
|
||||
Todo: Important source location missing in generated code
|
||||
|
||||
Source location for ExpressionStatement is missing in the generated output. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
|
||||
|
||||
error.todo-missing-source-locations.ts:26:2
|
||||
24 | }
|
||||
25 |
|
||||
> 26 | console.log('Hello, world!');
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
27 |
|
||||
28 | return [y, foo, bar];
|
||||
29 | }
|
||||
error.todo-missing-source-locations.ts:21:4
|
||||
19 | sound = 'woof';
|
||||
20 | } else {
|
||||
> 21 | sound = 'meow';
|
||||
| ^^^^^^^^^^^^^^^
|
||||
22 | }
|
||||
23 |
|
||||
24 | useEffect(() => {
|
||||
|
||||
Todo: Important source location has wrong node type in generated code
|
||||
|
||||
Source location for Identifier exists in the generated output but with wrong node type(s): ExpressionStatement. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
|
||||
|
||||
error.todo-missing-source-locations.ts:21:4
|
||||
19 | sound = 'woof';
|
||||
20 | } else {
|
||||
> 21 | sound = 'meow';
|
||||
| ^^^^^
|
||||
22 | }
|
||||
23 |
|
||||
24 | useEffect(() => {
|
||||
|
||||
Todo: Important source location missing in generated code
|
||||
|
||||
Source location for ExpressionStatement is missing in the generated output. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
|
||||
|
||||
error.todo-missing-source-locations.ts:24:2
|
||||
22 | }
|
||||
23 |
|
||||
> 24 | useEffect(() => {
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
> 25 | if (a > 10) {
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
> 26 | console.log(a);
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
> 27 | console.log(sound);
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
> 28 | console.log(destA, destB);
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
> 29 | }
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
> 30 | }, [a, sound, destA, destB]);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
31 |
|
||||
32 | const foo = useCallback(() => {
|
||||
33 | return a + b;
|
||||
|
||||
Todo: Important source location missing in generated code
|
||||
|
||||
Source location for ExpressionStatement is missing in the generated output. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
|
||||
|
||||
error.todo-missing-source-locations.ts:26:6
|
||||
24 | useEffect(() => {
|
||||
25 | if (a > 10) {
|
||||
> 26 | console.log(a);
|
||||
| ^^^^^^^^^^^^^^^
|
||||
27 | console.log(sound);
|
||||
28 | console.log(destA, destB);
|
||||
29 | }
|
||||
|
||||
Todo: Important source location missing in generated code
|
||||
|
||||
Source location for Identifier is missing in the generated output. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
|
||||
|
||||
error.todo-missing-source-locations.ts:26:14
|
||||
24 | useEffect(() => {
|
||||
25 | if (a > 10) {
|
||||
> 26 | console.log(a);
|
||||
| ^^^
|
||||
27 | console.log(sound);
|
||||
28 | console.log(destA, destB);
|
||||
29 | }
|
||||
|
||||
Todo: Important source location missing in generated code
|
||||
|
||||
Source location for ExpressionStatement is missing in the generated output. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
|
||||
|
||||
error.todo-missing-source-locations.ts:27:6
|
||||
25 | if (a > 10) {
|
||||
26 | console.log(a);
|
||||
> 27 | console.log(sound);
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
28 | console.log(destA, destB);
|
||||
29 | }
|
||||
30 | }, [a, sound, destA, destB]);
|
||||
|
||||
Todo: Important source location missing in generated code
|
||||
|
||||
Source location for Identifier is missing in the generated output. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
|
||||
|
||||
error.todo-missing-source-locations.ts:27:14
|
||||
25 | if (a > 10) {
|
||||
26 | console.log(a);
|
||||
> 27 | console.log(sound);
|
||||
| ^^^
|
||||
28 | console.log(destA, destB);
|
||||
29 | }
|
||||
30 | }, [a, sound, destA, destB]);
|
||||
|
||||
Todo: Important source location missing in generated code
|
||||
|
||||
Source location for ExpressionStatement is missing in the generated output. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
|
||||
|
||||
error.todo-missing-source-locations.ts:28:6
|
||||
26 | console.log(a);
|
||||
27 | console.log(sound);
|
||||
> 28 | console.log(destA, destB);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
29 | }
|
||||
30 | }, [a, sound, destA, destB]);
|
||||
31 |
|
||||
|
||||
Todo: Important source location missing in generated code
|
||||
|
||||
Source location for Identifier is missing in the generated output. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
|
||||
|
||||
error.todo-missing-source-locations.ts:28:14
|
||||
26 | console.log(a);
|
||||
27 | console.log(sound);
|
||||
> 28 | console.log(destA, destB);
|
||||
| ^^^
|
||||
29 | }
|
||||
30 | }, [a, sound, destA, destB]);
|
||||
31 |
|
||||
|
||||
Todo: Important source location missing in generated code
|
||||
|
||||
Source location for Identifier is missing in the generated output. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
|
||||
|
||||
error.todo-missing-source-locations.ts:32:14
|
||||
30 | }, [a, sound, destA, destB]);
|
||||
31 |
|
||||
> 32 | const foo = useCallback(() => {
|
||||
| ^^^^^^^^^^^
|
||||
33 | return a + b;
|
||||
34 | }, [a, b]);
|
||||
35 |
|
||||
|
||||
Todo: Important source location missing in generated code
|
||||
|
||||
Source location for ReturnStatement is missing in the generated output. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
|
||||
|
||||
error.todo-missing-source-locations.ts:28:2
|
||||
26 | console.log('Hello, world!');
|
||||
27 |
|
||||
> 28 | return [y, foo, bar];
|
||||
error.todo-missing-source-locations.ts:33:4
|
||||
31 |
|
||||
32 | const foo = useCallback(() => {
|
||||
> 33 | return a + b;
|
||||
| ^^^^^^^^^^^^^
|
||||
34 | }, [a, b]);
|
||||
35 |
|
||||
36 | function bar() {
|
||||
|
||||
Todo: Important source location missing in generated code
|
||||
|
||||
Source location for Identifier is missing in the generated output. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
|
||||
|
||||
error.todo-missing-source-locations.ts:34:6
|
||||
32 | const foo = useCallback(() => {
|
||||
33 | return a + b;
|
||||
> 34 | }, [a, b]);
|
||||
| ^
|
||||
35 |
|
||||
36 | function bar() {
|
||||
37 | return (c + d) * 2;
|
||||
|
||||
Todo: Important source location missing in generated code
|
||||
|
||||
Source location for Identifier is missing in the generated output. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
|
||||
|
||||
error.todo-missing-source-locations.ts:34:9
|
||||
32 | const foo = useCallback(() => {
|
||||
33 | return a + b;
|
||||
> 34 | }, [a, b]);
|
||||
| ^
|
||||
35 |
|
||||
36 | function bar() {
|
||||
37 | return (c + d) * 2;
|
||||
|
||||
Todo: Important source location missing in generated code
|
||||
|
||||
Source location for ReturnStatement is missing in the generated output. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
|
||||
|
||||
error.todo-missing-source-locations.ts:37:4
|
||||
35 |
|
||||
36 | function bar() {
|
||||
> 37 | return (c + d) * 2;
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
38 | }
|
||||
39 |
|
||||
40 | console.log('Hello, world!');
|
||||
|
||||
Todo: Important source location missing in generated code
|
||||
|
||||
Source location for ExpressionStatement is missing in the generated output. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
|
||||
|
||||
error.todo-missing-source-locations.ts:40:2
|
||||
38 | }
|
||||
39 |
|
||||
> 40 | console.log('Hello, world!');
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
41 |
|
||||
42 | return [y, foo, bar];
|
||||
43 | }
|
||||
|
||||
Todo: Important source location missing in generated code
|
||||
|
||||
Source location for Identifier is missing in the generated output. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
|
||||
|
||||
error.todo-missing-source-locations.ts:40:10
|
||||
38 | }
|
||||
39 |
|
||||
> 40 | console.log('Hello, world!');
|
||||
| ^^^
|
||||
41 |
|
||||
42 | return [y, foo, bar];
|
||||
43 | }
|
||||
|
||||
Todo: Important source location missing in generated code
|
||||
|
||||
Source location for ReturnStatement is missing in the generated output. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
|
||||
|
||||
error.todo-missing-source-locations.ts:42:2
|
||||
40 | console.log('Hello, world!');
|
||||
41 |
|
||||
> 42 | return [y, foo, bar];
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
29 | }
|
||||
30 |
|
||||
43 | }
|
||||
44 |
|
||||
```
|
||||
|
||||
|
||||
@@ -6,14 +6,28 @@ function Component({prop1, prop2}) {
|
||||
const y = x * 2;
|
||||
const arr = [x, y];
|
||||
const obj = {x, y};
|
||||
let destA, destB;
|
||||
if (y > 5) {
|
||||
[destA, destB] = arr;
|
||||
}
|
||||
|
||||
const [a, b] = arr;
|
||||
const {x: c, y: d} = obj;
|
||||
let sound;
|
||||
|
||||
if (y > 10) {
|
||||
sound = 'woof';
|
||||
} else {
|
||||
sound = 'meow';
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (a > 10) {
|
||||
console.log(a);
|
||||
console.log(sound);
|
||||
console.log(destA, destB);
|
||||
}
|
||||
}, [a]);
|
||||
}, [a, sound, destA, destB]);
|
||||
|
||||
const foo = useCallback(() => {
|
||||
return a + b;
|
||||
|
||||
@@ -44,7 +44,6 @@ function Component(props) {
|
||||
let t0;
|
||||
if ($[0] !== props.a) {
|
||||
const a = [props.a];
|
||||
|
||||
t0 = [a];
|
||||
$[0] = props.a;
|
||||
$[1] = t0;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @validateExhaustiveEffectDependencies
|
||||
// @validateExhaustiveEffectDependencies:"all"
|
||||
import {useEffect, useEffectEvent} from 'react';
|
||||
|
||||
function Component({x, y, z}) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @validateExhaustiveEffectDependencies
|
||||
// @validateExhaustiveEffectDependencies:"all"
|
||||
import {useEffect, useEffectEvent} from 'react';
|
||||
|
||||
function Component({x, y, z}) {
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @validateExhaustiveEffectDependencies:"extra-only"
|
||||
import {useEffect} from 'react';
|
||||
|
||||
function Component({x, y, z}) {
|
||||
// no error: missing dep not reported in extra-only mode
|
||||
useEffect(() => {
|
||||
log(x);
|
||||
}, []);
|
||||
|
||||
// error: extra dep - y
|
||||
useEffect(() => {
|
||||
log(x);
|
||||
}, [x, y]);
|
||||
|
||||
// error: extra dep - y (missing dep - z not reported)
|
||||
useEffect(() => {
|
||||
log(x, z);
|
||||
}, [x, y]);
|
||||
|
||||
// error: extra dep - x.y
|
||||
useEffect(() => {
|
||||
log(x);
|
||||
}, [x.y]);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
## Error
|
||||
|
||||
```
|
||||
Found 3 errors:
|
||||
|
||||
Error: Found extra effect dependencies
|
||||
|
||||
Extra dependencies can cause an effect to fire more often than it should, resulting in performance problems such as excessive renders and side effects.
|
||||
|
||||
error.invalid-exhaustive-effect-deps-extra-only.ts:13:9
|
||||
11 | useEffect(() => {
|
||||
12 | log(x);
|
||||
> 13 | }, [x, y]);
|
||||
| ^ Unnecessary dependency `y`
|
||||
14 |
|
||||
15 | // error: extra dep - y (missing dep - z not reported)
|
||||
16 | useEffect(() => {
|
||||
|
||||
Inferred dependencies: `[x]`
|
||||
|
||||
Error: Found extra effect dependencies
|
||||
|
||||
Extra dependencies can cause an effect to fire more often than it should, resulting in performance problems such as excessive renders and side effects.
|
||||
|
||||
error.invalid-exhaustive-effect-deps-extra-only.ts:18:9
|
||||
16 | useEffect(() => {
|
||||
17 | log(x, z);
|
||||
> 18 | }, [x, y]);
|
||||
| ^ Unnecessary dependency `y`
|
||||
19 |
|
||||
20 | // error: extra dep - x.y
|
||||
21 | useEffect(() => {
|
||||
|
||||
Inferred dependencies: `[x, z]`
|
||||
|
||||
Error: Found extra effect dependencies
|
||||
|
||||
Extra dependencies can cause an effect to fire more often than it should, resulting in performance problems such as excessive renders and side effects.
|
||||
|
||||
error.invalid-exhaustive-effect-deps-extra-only.ts:23:6
|
||||
21 | useEffect(() => {
|
||||
22 | log(x);
|
||||
> 23 | }, [x.y]);
|
||||
| ^^^ Overly precise dependency `x.y`, use `x` instead
|
||||
24 | }
|
||||
25 |
|
||||
|
||||
Inferred dependencies: `[x]`
|
||||
```
|
||||
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
// @validateExhaustiveEffectDependencies:"extra-only"
|
||||
import {useEffect} from 'react';
|
||||
|
||||
function Component({x, y, z}) {
|
||||
// no error: missing dep not reported in extra-only mode
|
||||
useEffect(() => {
|
||||
log(x);
|
||||
}, []);
|
||||
|
||||
// error: extra dep - y
|
||||
useEffect(() => {
|
||||
log(x);
|
||||
}, [x, y]);
|
||||
|
||||
// error: extra dep - y (missing dep - z not reported)
|
||||
useEffect(() => {
|
||||
log(x, z);
|
||||
}, [x, y]);
|
||||
|
||||
// error: extra dep - x.y
|
||||
useEffect(() => {
|
||||
log(x);
|
||||
}, [x.y]);
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @validateExhaustiveEffectDependencies:"missing-only"
|
||||
import {useEffect} from 'react';
|
||||
|
||||
function Component({x, y, z}) {
|
||||
// error: missing dep - x
|
||||
useEffect(() => {
|
||||
log(x);
|
||||
}, []);
|
||||
|
||||
// no error: extra dep not reported in missing-only mode
|
||||
useEffect(() => {
|
||||
log(x);
|
||||
}, [x, y]);
|
||||
|
||||
// error: missing dep - z (extra dep - y not reported)
|
||||
useEffect(() => {
|
||||
log(x, z);
|
||||
}, [x, y]);
|
||||
|
||||
// error: missing dep x
|
||||
useEffect(() => {
|
||||
log(x);
|
||||
}, [x.y]);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
## Error
|
||||
|
||||
```
|
||||
Found 3 errors:
|
||||
|
||||
Error: Found missing effect dependencies
|
||||
|
||||
Missing dependencies can cause an effect to fire less often than it should.
|
||||
|
||||
error.invalid-exhaustive-effect-deps-missing-only.ts:7:8
|
||||
5 | // error: missing dep - x
|
||||
6 | useEffect(() => {
|
||||
> 7 | log(x);
|
||||
| ^ Missing dependency `x`
|
||||
8 | }, []);
|
||||
9 |
|
||||
10 | // no error: extra dep not reported in missing-only mode
|
||||
|
||||
Inferred dependencies: `[x]`
|
||||
|
||||
Error: Found missing effect dependencies
|
||||
|
||||
Missing dependencies can cause an effect to fire less often than it should.
|
||||
|
||||
error.invalid-exhaustive-effect-deps-missing-only.ts:17:11
|
||||
15 | // error: missing dep - z (extra dep - y not reported)
|
||||
16 | useEffect(() => {
|
||||
> 17 | log(x, z);
|
||||
| ^ Missing dependency `z`
|
||||
18 | }, [x, y]);
|
||||
19 |
|
||||
20 | // error: missing dep x
|
||||
|
||||
Inferred dependencies: `[x, z]`
|
||||
|
||||
Error: Found missing effect dependencies
|
||||
|
||||
Missing dependencies can cause an effect to fire less often than it should.
|
||||
|
||||
error.invalid-exhaustive-effect-deps-missing-only.ts:22:8
|
||||
20 | // error: missing dep x
|
||||
21 | useEffect(() => {
|
||||
> 22 | log(x);
|
||||
| ^ Missing dependency `x`
|
||||
23 | }, [x.y]);
|
||||
24 | }
|
||||
25 |
|
||||
|
||||
Inferred dependencies: `[x]`
|
||||
```
|
||||
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
// @validateExhaustiveEffectDependencies:"missing-only"
|
||||
import {useEffect} from 'react';
|
||||
|
||||
function Component({x, y, z}) {
|
||||
// error: missing dep - x
|
||||
useEffect(() => {
|
||||
log(x);
|
||||
}, []);
|
||||
|
||||
// no error: extra dep not reported in missing-only mode
|
||||
useEffect(() => {
|
||||
log(x);
|
||||
}, [x, y]);
|
||||
|
||||
// error: missing dep - z (extra dep - y not reported)
|
||||
useEffect(() => {
|
||||
log(x, z);
|
||||
}, [x, y]);
|
||||
|
||||
// error: missing dep x
|
||||
useEffect(() => {
|
||||
log(x);
|
||||
}, [x.y]);
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @validateExhaustiveEffectDependencies
|
||||
// @validateExhaustiveEffectDependencies:"all"
|
||||
import {useEffect} from 'react';
|
||||
|
||||
function Component({x, y, z}) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @validateExhaustiveEffectDependencies
|
||||
// @validateExhaustiveEffectDependencies:"all"
|
||||
import {useEffect} from 'react';
|
||||
|
||||
function Component({x, y, z}) {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @validateExhaustiveMemoizationDependencies @validateExhaustiveEffectDependencies
|
||||
// @validateExhaustiveMemoizationDependencies @validateExhaustiveEffectDependencies:"all"
|
||||
import {
|
||||
useCallback,
|
||||
useTransition,
|
||||
@@ -69,7 +69,7 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime"; // @validateExhaustiveMemoizationDependencies @validateExhaustiveEffectDependencies
|
||||
import { c as _c } from "react/compiler-runtime"; // @validateExhaustiveMemoizationDependencies @validateExhaustiveEffectDependencies:"all"
|
||||
import {
|
||||
useCallback,
|
||||
useTransition,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @validateExhaustiveMemoizationDependencies @validateExhaustiveEffectDependencies
|
||||
// @validateExhaustiveMemoizationDependencies @validateExhaustiveEffectDependencies:"all"
|
||||
import {
|
||||
useCallback,
|
||||
useTransition,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @validateExhaustiveEffectDependencies
|
||||
// @validateExhaustiveEffectDependencies:"all"
|
||||
import {useEffect, useEffectEvent} from 'react';
|
||||
|
||||
function Component({x, y, z}) {
|
||||
@@ -30,7 +30,7 @@ function Component({x, y, z}) {
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime"; // @validateExhaustiveEffectDependencies
|
||||
import { c as _c } from "react/compiler-runtime"; // @validateExhaustiveEffectDependencies:"all"
|
||||
import { useEffect, useEffectEvent } from "react";
|
||||
|
||||
function Component(t0) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @validateExhaustiveEffectDependencies
|
||||
// @validateExhaustiveEffectDependencies:"all"
|
||||
import {useEffect, useEffectEvent} from 'react';
|
||||
|
||||
function Component({x, y, z}) {
|
||||
|
||||
@@ -40,13 +40,11 @@ function Component(props) {
|
||||
[
|
||||
fbt._param(
|
||||
"a really long description that got split into multiple lines",
|
||||
|
||||
props.name,
|
||||
),
|
||||
],
|
||||
{ hk: "1euPUp" },
|
||||
);
|
||||
|
||||
t0 = element.toString();
|
||||
$[0] = props.name;
|
||||
$[1] = t0;
|
||||
|
||||
@@ -32,16 +32,9 @@ function Component(props) {
|
||||
if ($[0] !== props.name) {
|
||||
const element = fbt._(
|
||||
'Hello {"user" name}',
|
||||
[
|
||||
fbt._param(
|
||||
'"user" name',
|
||||
|
||||
props.name,
|
||||
),
|
||||
],
|
||||
[fbt._param('"user" name', props.name)],
|
||||
{ hk: "S0vMe" },
|
||||
);
|
||||
|
||||
t0 = element.toString();
|
||||
$[0] = props.name;
|
||||
$[1] = t0;
|
||||
|
||||
@@ -32,16 +32,9 @@ function Component(props) {
|
||||
if ($[0] !== props.name) {
|
||||
const element = fbt._(
|
||||
"Hello {user name ☺}",
|
||||
[
|
||||
fbt._param(
|
||||
"user name \u263A",
|
||||
|
||||
props.name,
|
||||
),
|
||||
],
|
||||
[fbt._param("user name \u263A", props.name)],
|
||||
{ hk: "1En1lp" },
|
||||
);
|
||||
|
||||
t0 = element.toString();
|
||||
$[0] = props.name;
|
||||
$[1] = t0;
|
||||
|
||||
@@ -32,16 +32,9 @@ function Component(props) {
|
||||
if ($[0] !== props.name) {
|
||||
const element = fbt._(
|
||||
"Hello {user name}",
|
||||
[
|
||||
fbt._param(
|
||||
"user name",
|
||||
|
||||
props.name,
|
||||
),
|
||||
],
|
||||
[fbt._param("user name", props.name)],
|
||||
{ hk: "2zEDKF" },
|
||||
);
|
||||
|
||||
t0 = element.toString();
|
||||
$[0] = props.name;
|
||||
$[1] = t0;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user