Compare commits

..

1 Commits

Author SHA1 Message Date
Mofei Zhang
bc33b6218f [compiler] Aggregate error reporting, separate eslint rules
NOTE: this is a merged version of @mofeiZ's original PR along with my edits per offline discussion. The description is updated to reflect the latest approach.

The key problem we're trying to solve with this PR is to allow developers more control over the compiler's various validations. The idea is to have a number of rules targeting a specific category of issues, such as enforcing immutability of props/state/etc or disallowing access to refs during render. We don't want to have to run the compiler again for every single rule, though, so @mofeiZ added an LRU cache that caches the full compilation output of N most recent files. The first rule to run on a given file will cause it to get cached, and then subsequent rules can pull from the cache, with each rule filtering down to its specific category of errors.

For the categories, I went through and assigned a category roughly 1:1 to existing validations, and then used my judgement on some places that felt distinct enough to warrant a separate error. Every error in the compiler now has to supply both a severity (for legacy reasons) and a category (for ESLint). Each category corresponds 1:1 to a ESLint rule definition, so that the set of rules is automatically populated based on the defined categories.

Categories include a flag for whether they should be in the recommended set or not.

Note that as with the original version of this PR, only eslint-plugin-react-compiler is changed. We still have to update the main lint rule.
2025-08-21 14:37:36 -07:00
294 changed files with 1604 additions and 20239 deletions

View File

@@ -1,7 +1,7 @@
{
"packages": ["packages/react", "packages/react-dom", "packages/react-server-dom-webpack", "packages/scheduler"],
"buildCommand": "download-build-in-codesandbox-ci",
"node": "20",
"node": "18",
"publishDirectory": {
"react": "build/oss-experimental/react",
"react-dom": "build/oss-experimental/react-dom",

View File

@@ -28,6 +28,3 @@ packages/react-devtools-shared/src/hooks/__tests__/__source__/__untransformed__/
packages/react-devtools-shell/dist
packages/react-devtools-timeline/dist
packages/react-devtools-timeline/static
# Imported third-party Flow types
flow-typed/

View File

@@ -547,10 +547,13 @@ module.exports = {
},
globals: {
$Call: 'readonly',
$ElementType: 'readonly',
$Flow$ModuleRef: 'readonly',
$FlowFixMe: 'readonly',
$Keys: 'readonly',
$NonMaybeType: 'readonly',
$PropertyType: 'readonly',
$ReadOnly: 'readonly',
$ReadOnlyArray: 'readonly',
$ArrayBufferView: 'readonly',
@@ -565,7 +568,6 @@ module.exports = {
BigInt: 'readonly',
BigInt64Array: 'readonly',
BigUint64Array: 'readonly',
CacheType: 'readonly',
Class: 'readonly',
ClientRect: 'readonly',
CopyInspectedElementPath: 'readonly',
@@ -580,15 +582,13 @@ module.exports = {
IteratorResult: 'readonly',
JSONValue: 'readonly',
JSResourceReference: 'readonly',
mixin$Animatable: 'readonly',
MouseEventHandler: 'readonly',
NavigateEvent: 'readonly',
PerformanceMeasureOptions: 'readonly',
PropagationPhases: 'readonly',
PropertyDescriptor: 'readonly',
PropertyDescriptorMap: 'readonly',
Proxy$traps: 'readonly',
React$AbstractComponent: 'readonly',
React$Component: 'readonly',
React$ComponentType: 'readonly',
React$Config: 'readonly',
React$Context: 'readonly',
React$Element: 'readonly',
@@ -620,6 +620,7 @@ module.exports = {
PropertyIndexedKeyframes: 'readonly',
KeyframeAnimationOptions: 'readonly',
GetAnimationsOptions: 'readonly',
Animatable: 'readonly',
ScrollTimeline: 'readonly',
EventListenerOptionsOrUseCapture: 'readonly',
FocusOptions: 'readonly',

View File

@@ -57,6 +57,8 @@ jobs:
key: playwright-browsers-v6-${{ runner.arch }}-${{ runner.os }}-${{ steps.playwright_version.outputs.playwright_version }}
- run: npx playwright install --with-deps chromium
if: steps.cache_playwright_browsers.outputs.cache-hit != 'true'
- run: npx playwright install-deps
if: steps.cache_playwright_browsers.outputs.cache-hit == 'true'
- run: CI=true yarn test
- run: ls -R test-results
if: '!cancelled()'

View File

@@ -316,7 +316,7 @@ jobs:
if: steps.node_modules.outputs.cache-hit != 'true'
- run: ./scripts/react-compiler/build-compiler.sh && ./scripts/react-compiler/link-compiler.sh
- run: yarn workspace eslint-plugin-react-hooks test
# ----- BUILD -----
build_and_lint:
name: yarn build and lint
@@ -811,18 +811,9 @@ jobs:
pattern: _build_*
path: build
merge-multiple: true
- name: Check Playwright version
id: playwright_version
run: echo "playwright_version=$(npm ls @playwright/test | grep @playwright | sed 's/.*@//' | head -1)" >> "$GITHUB_OUTPUT"
- name: Cache Playwright Browsers for version ${{ steps.playwright_version.outputs.playwright_version }}
id: cache_playwright_browsers
uses: actions/cache@v4
with:
path: ~/.cache/ms-playwright
key: playwright-browsers-v6-${{ runner.arch }}-${{ runner.os }}-${{ steps.playwright_version.outputs.playwright_version }}
- name: Playwright install deps
if: steps.cache_playwright_browsers.outputs.cache-hit != 'true'
run: npx playwright install --with-deps chromium
- run: |
npx playwright install
sudo npx playwright install-deps
- run: ./scripts/ci/run_devtools_e2e_tests.js
env:
RELEASE_CHANNEL: experimental

View File

@@ -18,7 +18,6 @@ jobs:
permissions:
# Used to create a review and close PRs
pull-requests: write
contents: write
steps:
- name: Close PR
uses: actions/github-script@v7

View File

@@ -1,103 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import MonacoEditor, {loader, type Monaco} from '@monaco-editor/react';
import {parseConfigPragmaAsString} from 'babel-plugin-react-compiler';
import type {editor} from 'monaco-editor';
import * as monaco from 'monaco-editor';
import parserBabel from 'prettier/plugins/babel';
import * as prettierPluginEstree from 'prettier/plugins/estree';
import * as prettier from 'prettier/standalone';
import {useState, useEffect} from 'react';
import {Resizable} from 're-resizable';
import {useStore} from '../StoreContext';
import {monacoOptions} from './monacoOptions';
loader.config({monaco});
export default function ConfigEditor(): JSX.Element {
const [, setMonaco] = useState<Monaco | null>(null);
const store = useStore();
// Parse string-based override config from pragma comment and format it
const [configJavaScript, setConfigJavaScript] = useState('');
useEffect(() => {
const pragma = store.source.substring(0, store.source.indexOf('\n'));
const configString = `(${parseConfigPragmaAsString(pragma)})`;
prettier
.format(configString, {
semi: true,
parser: 'babel-ts',
plugins: [parserBabel, prettierPluginEstree],
})
.then(formatted => {
setConfigJavaScript(formatted);
})
.catch(error => {
console.error('Error formatting config:', error);
setConfigJavaScript('({})'); // Return empty object if not valid for now
//TODO: Add validation and error handling for config
});
console.log('Config:', configString);
}, [store.source]);
const handleChange: (value: string | undefined) => void = value => {
if (!value) return;
// TODO: Implement sync logic to update pragma comments in the source
console.log('Config changed:', value);
};
const handleMount: (
_: editor.IStandaloneCodeEditor,
monaco: Monaco,
) => void = (_, monaco) => {
setMonaco(monaco);
const uri = monaco.Uri.parse(`file:///config.js`);
const model = monaco.editor.getModel(uri);
if (model) {
model.updateOptions({tabSize: 2});
}
};
return (
<div className="relative flex flex-col flex-none border-r border-gray-200">
<h2 className="p-4 duration-150 ease-in border-b cursor-default border-grey-200 font-light text-secondary">
Config Overrides
</h2>
<Resizable
minWidth={300}
maxWidth={600}
defaultSize={{width: 350, height: 'auto'}}
enable={{right: true}}
className="!h-[calc(100vh_-_3.5rem_-_4rem)]">
<MonacoEditor
path={'config.js'}
language={'javascript'}
value={configJavaScript}
onMount={handleMount}
onChange={handleChange}
options={{
...monacoOptions,
readOnly: true,
lineNumbers: 'off',
folding: false,
renderLineHighlight: 'none',
scrollBeyondLastLine: false,
hideCursorInOverviewRuler: true,
overviewRulerBorder: false,
overviewRulerLanes: 0,
fontSize: 12,
}}
/>
</Resizable>
</div>
);
}

View File

@@ -37,7 +37,6 @@ import {
type Store,
} from '../../lib/stores';
import {useStore, useStoreDispatch} from '../StoreContext';
import ConfigEditor from './ConfigEditor';
import Input from './Input';
import {
CompilerOutput,
@@ -47,7 +46,6 @@ import {
} from './Output';
import {transformFromAstSync} from '@babel/core';
import {LoggerEvent} from 'babel-plugin-react-compiler/dist/Entrypoint';
import {useSearchParams} from 'next/navigation';
function parseInput(
input: string,
@@ -293,13 +291,7 @@ export default function Editor(): JSX.Element {
[deferredStore.source],
);
// TODO: Remove this once the config editor is more stable
const searchParams = useSearchParams();
const search = searchParams.get('showConfig');
const shouldShowConfig = search === 'true';
useMountEffect(() => {
// Initialize store
let mountStore: Store;
try {
mountStore = initStoreFromUrlOrLocalStorage();
@@ -336,7 +328,6 @@ export default function Editor(): JSX.Element {
return (
<>
<div className="relative flex basis top-14">
{shouldShowConfig && <ConfigEditor />}
<div className={clsx('relative sm:basis-1/4')}>
<Input language={language} errors={errors} />
</div>

View File

@@ -19,8 +19,7 @@
"test": "yarn workspaces run test",
"snap": "yarn workspace babel-plugin-react-compiler run snap",
"snap:build": "yarn workspace snap run build",
"npm:publish": "node scripts/release/publish",
"eslint-docs": "yarn workspace babel-plugin-react-compiler build && node scripts/build-eslint-docs.js"
"npm:publish": "node scripts/release/publish"
},
"dependencies": {
"fs-extra": "^4.0.2",

View File

@@ -7,10 +7,9 @@
import * as t from '@babel/types';
import {codeFrameColumns} from '@babel/code-frame';
import {type SourceLocation} from './HIR';
import type {SourceLocation} from './HIR';
import {Err, Ok, Result} from './Utils/Result';
import {assertExhaustive} from './Utils/utils';
import invariant from 'invariant';
export enum ErrorSeverity {
/**
@@ -36,14 +35,6 @@ export enum ErrorSeverity {
* memoization.
*/
CannotPreserveMemoization = 'CannotPreserveMemoization',
/**
* An API that is known to be incompatible with the compiler. Generally as a result of
* the library using "interior mutability", ie having a value whose referential identity
* stays the same but which provides access to values that can change. For example a
* function that doesn't change but returns different results, or an object that doesn't
* change identity but whose properties change.
*/
IncompatibleLibrary = 'IncompatibleLibrary',
/**
* Unhandled syntax that we don't support yet.
*/
@@ -466,8 +457,7 @@ export class CompilerError extends Error {
case ErrorSeverity.InvalidJS:
case ErrorSeverity.InvalidReact:
case ErrorSeverity.InvalidConfig:
case ErrorSeverity.UnsupportedJS:
case ErrorSeverity.IncompatibleLibrary: {
case ErrorSeverity.UnsupportedJS: {
return true;
}
case ErrorSeverity.CannotPreserveMemoization:
@@ -515,9 +505,8 @@ function printErrorSummary(severity: ErrorSeverity, message: string): string {
severityCategory = 'Error';
break;
}
case ErrorSeverity.IncompatibleLibrary:
case ErrorSeverity.CannotPreserveMemoization: {
severityCategory = 'Compilation Skipped';
severityCategory = 'Memoization';
break;
}
case ErrorSeverity.Invariant: {
@@ -551,15 +540,9 @@ export enum ErrorCategory {
// Checking for valid usage of manual memoization
UseMemo = 'UseMemo',
// Checking for higher order functions acting as factories for components/hooks
Factories = 'Factories',
// Checks that manual memoization is preserved
PreserveManualMemo = 'PreserveManualMemo',
// Checks for known incompatible libraries
IncompatibleLibrary = 'IncompatibleLibrary',
// Checking for no mutations of props, hook arguments, hook return values
Immutability = 'Immutability',
@@ -645,18 +628,7 @@ export type LintRule = {
recommended: boolean;
};
const RULE_NAME_PATTERN = /^[a-z]+(-[a-z]+)*$/;
export function getRuleForCategory(category: ErrorCategory): LintRule {
const rule = getRuleForCategoryImpl(category);
invariant(
RULE_NAME_PATTERN.test(rule.name),
`Invalid rule name, got '${rule.name}' but rules must match ${RULE_NAME_PATTERN.toString()}`,
);
return rule;
}
function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
switch (category) {
case ErrorCategory.AutomaticEffectDependencies: {
return {
@@ -664,7 +636,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
name: 'automatic-effect-dependencies',
description:
'Verifies that automatic effect dependencies are compiled if opted-in',
recommended: false,
recommended: true,
};
}
case ErrorCategory.CapitalizedCalls: {
@@ -680,7 +652,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
return {
category,
name: 'config',
description: 'Validates the compiler configuration options',
description: 'Validates the configuration',
recommended: true,
};
}
@@ -706,7 +678,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
category,
name: 'set-state-in-effect',
description:
'Validates against calling setState synchronously in an effect, which can lead to re-renders that degrade performance',
'Validates against calling setState synchronously in an effect',
recommended: true,
};
}
@@ -715,17 +687,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
category,
name: 'error-boundaries',
description:
'Validates usage of error boundaries instead of try/catch for errors in child components',
recommended: true,
};
}
case ErrorCategory.Factories: {
return {
category,
name: 'component-hook-factories',
description:
'Validates against higher order functions defining nested components or hooks. ' +
'Components and hooks should be defined at the module level',
'Validates usage of error boundaries instead of try/catch for errors in JSX',
recommended: true,
};
}
@@ -749,8 +711,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
return {
category,
name: 'gating',
description:
'Validates configuration of [gating mode](https://react.dev/reference/react-compiler/gating)',
description: 'Validates configuration of gating mode',
recommended: true,
};
}
@@ -759,8 +720,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
category,
name: 'globals',
description:
'Validates against assignment/mutation of globals during render, part of ensuring that ' +
'[side effects must render outside of render](https://react.dev/reference/rules/components-and-hooks-must-be-pure#side-effects-must-run-outside-of-render)',
'Validates against assignment/mutation of globals during render',
recommended: true,
};
}
@@ -782,7 +742,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
category,
name: 'immutability',
description:
'Validates against mutating props, state, and other values that [are immutable](https://react.dev/reference/rules/components-and-hooks-must-be-pure#props-and-state-are-immutable)',
'Validates that immutable values (props, state, etc) are not mutated',
recommended: true,
};
}
@@ -799,9 +759,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
category,
name: 'preserve-manual-memoization',
description:
'Validates that existing manual memoized is preserved by the compiler. ' +
'React Compiler will only compile components and hooks if its inference ' +
'[matches or exceeds the existing manual memoization](https://react.dev/learn/react-compiler/introduction#what-should-i-do-about-usememo-usecallback-and-reactmemo)',
'Validates that existing manual memoized is preserved by the compiler',
recommended: true,
};
}
@@ -810,7 +768,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
category,
name: 'purity',
description:
'Validates that [components/hooks are pure](https://react.dev/reference/rules/components-and-hooks-must-be-pure) by checking that they do not call known-impure functions',
'Validates that the component/hook is pure, and does not call known-impure functions',
recommended: true,
};
}
@@ -819,7 +777,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
category,
name: 'refs',
description:
'Validates correct usage of refs, not reading/writing during render. See the "pitfalls" section in [`useRef()` usage](https://react.dev/reference/react/useRef#usage)',
'Validates correct usage of refs, not reading/writing during render',
recommended: true,
};
}
@@ -827,8 +785,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
return {
category,
name: 'set-state-in-render',
description:
'Validates against setting state during render, which can trigger additional renders and potential infinite render loops',
description: 'Validates against setting state during render',
recommended: true,
};
}
@@ -837,7 +794,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
category,
name: 'static-components',
description:
'Validates that components are static, not recreated every render. Components that are recreated dynamically can reset state and trigger excessive re-rendering',
'Validates that components are static, not recreated every render',
recommended: true,
};
}
@@ -869,8 +826,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
return {
category,
name: 'unsupported-syntax',
description:
'Validates against syntax that we do not plan to support in React Compiler',
description: 'Validates against syntax that we do not plan to support',
recommended: true,
};
}
@@ -878,17 +834,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
return {
category,
name: 'use-memo',
description:
'Validates usage of the useMemo() hook against common mistakes. See [`useMemo()` docs](https://react.dev/reference/react/useMemo) for more information.',
recommended: true,
};
}
case ErrorCategory.IncompatibleLibrary: {
return {
category,
name: 'incompatible-library',
description:
'Validates against usage of libraries which are incompatible with memoization (manual or automatic)',
description: 'Validates usage of the useMemo() hook',
recommended: true,
};
}

View File

@@ -494,20 +494,7 @@ function findFunctionsToCompile(
): Array<CompileSource> {
const queue: Array<CompileSource> = [];
const traverseFunction = (fn: BabelFn, pass: CompilerPass): void => {
// In 'all' mode, compile only top level functions
if (
pass.opts.compilationMode === 'all' &&
fn.scope.getProgramParent() !== fn.scope.parent
) {
return;
}
const fnType = getReactFunctionType(fn, pass);
if (pass.opts.environment.validateNoDynamicallyCreatedComponentsOrHooks) {
validateNoDynamicallyCreatedComponentsOrHooks(fn, pass, programContext);
}
if (fnType === null || programContext.alreadyCompiled.has(fn.node)) {
return;
}
@@ -852,73 +839,6 @@ function shouldSkipCompilation(
return false;
}
/**
* Validates that Components/Hooks are always defined at module level. This prevents scope reference
* errors that occur when the compiler attempts to optimize the nested component/hook while its
* parent function remains uncompiled.
*/
function validateNoDynamicallyCreatedComponentsOrHooks(
fn: BabelFn,
pass: CompilerPass,
programContext: ProgramContext,
): void {
const parentNameExpr = getFunctionName(fn);
const parentName =
parentNameExpr !== null && parentNameExpr.isIdentifier()
? parentNameExpr.node.name
: '<anonymous>';
const validateNestedFunction = (
nestedFn: NodePath<
t.FunctionDeclaration | t.FunctionExpression | t.ArrowFunctionExpression
>,
): void => {
if (
nestedFn.node === fn.node ||
programContext.alreadyCompiled.has(nestedFn.node)
) {
return;
}
if (nestedFn.scope.getProgramParent() !== nestedFn.scope.parent) {
const nestedFnType = getReactFunctionType(nestedFn as BabelFn, pass);
const nestedFnNameExpr = getFunctionName(nestedFn as BabelFn);
const nestedName =
nestedFnNameExpr !== null && nestedFnNameExpr.isIdentifier()
? nestedFnNameExpr.node.name
: '<anonymous>';
if (nestedFnType === 'Component' || nestedFnType === 'Hook') {
CompilerError.throwDiagnostic({
category: ErrorCategory.Factories,
severity: ErrorSeverity.InvalidReact,
reason: `Components and hooks cannot be created dynamically`,
description: `The function \`${nestedName}\` appears to be a React ${nestedFnType.toLowerCase()}, but it's defined inside \`${parentName}\`. Components and Hooks should always be declared at module scope`,
details: [
{
kind: 'error',
message: 'this function dynamically created a component/hook',
loc: parentNameExpr?.node.loc ?? fn.node.loc ?? null,
},
{
kind: 'error',
message: 'the component is created here',
loc: nestedFnNameExpr?.node.loc ?? nestedFn.node.loc ?? null,
},
],
});
}
}
nestedFn.skip();
};
fn.traverse({
FunctionDeclaration: validateNestedFunction,
FunctionExpression: validateNestedFunction,
ArrowFunctionExpression: validateNestedFunction,
});
}
function getReactFunctionType(
fn: BabelFn,
pass: CompilerPass,
@@ -957,6 +877,11 @@ function getReactFunctionType(
return componentSyntaxType;
}
case 'all': {
// Compile only top level functions
if (fn.scope.getProgramParent() !== fn.scope.parent) {
return null;
}
return getComponentOrHookLike(fn, hookPattern) ?? 'Other';
}
default: {

View File

@@ -1,91 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import {Effect, ValueKind} from '..';
import {TypeConfig} from './TypeSchema';
/**
* Libraries developed before we officially documented the [Rules of React](https://react.dev/reference/rules)
* implement APIs which cannot be memoized safely, either via manual or automatic memoization.
*
* Any non-hook API that is designed to be called during render (not events/effects) should be safe to memoize:
*
* ```js
* function Component() {
* const {someFunction} = useLibrary();
* // it should always be safe to memoize functions like this
* const result = useMemo(() => someFunction(), [someFunction]);
* }
* ```
*
* However, some APIs implement "interior mutability" — mutating values rather than copying into a new value
* and setting state with the new value. Such functions (`someFunction()` in the example) could return different
* values even though the function itself is the same object. This breaks memoization, since React relies on
* the outer object (or function) changing if part of its value has changed.
*
* Given that we didn't have the Rules of React precisely documented prior to the introduction of React compiler,
* it's understandable that some libraries accidentally shipped APIs that break this rule. However, developers
* can easily run into pitfalls with these APIs. They may manually memoize them, which can break their app. Or
* they may try using React Compiler, and think that the compiler has broken their code.
*
* To help ensure that developers can successfully use the compiler with existing code, this file teaches the
* compiler about specific APIs that are known to be incompatible with memoization. We've tried to be as precise
* as possible.
*
* The React team is open to collaborating with library authors to help develop compatible versions of these APIs,
* and we have already reached out to the teams who own any API listed here to ensure they are aware of the issue.
*/
export function defaultModuleTypeProvider(
moduleName: string,
): TypeConfig | null {
switch (moduleName) {
case 'react-hook-form': {
return {
kind: 'object',
properties: {
useForm: {
kind: 'hook',
returnType: {
kind: 'object',
properties: {
// Only the `watch()` function returned by react-hook-form's `useForm()` API is incompatible
watch: {
kind: 'function',
positionalParams: [],
restParam: Effect.Read,
calleeEffect: Effect.Read,
returnType: {kind: 'type', name: 'Any'},
returnValueKind: ValueKind.Mutable,
knownIncompatible: `React Hook Form's \`useForm()\` API returns a \`watch()\` function which cannot be memoized safely.`,
},
},
},
},
},
};
}
case '@tanstack/react-table': {
return {
kind: 'object',
properties: {
/*
* Many of the properties of `useReactTable()`'s return value are incompatible, so we mark the entire hook
* as incompatible
*/
useReactTable: {
kind: 'hook',
positionalParams: [],
restParam: Effect.Read,
returnType: {kind: 'type', name: 'Any'},
knownIncompatible: `TanStack Table's \`useReactTable()\` API returns functions that cannot be memoized safely`,
},
},
};
}
}
return null;
}

View File

@@ -50,7 +50,6 @@ import {
import {Scope as BabelScope, NodePath} from '@babel/traverse';
import {TypeSchema} from './TypeSchema';
import {FlowTypeEnv} from '../Flood/Types';
import {defaultModuleTypeProvider} from './DefaultModuleTypeProvider';
export const ReactElementSymbolSchema = z.object({
elementSymbol: z.union([
@@ -651,13 +650,6 @@ export const EnvironmentConfigSchema = z.object({
* useMemo(() => { ... }, [...]);
*/
validateNoVoidUseMemo: z.boolean().default(false),
/**
* Validates that Components/Hooks are always defined at module level. This prevents scope
* reference errors that occur when the compiler attempts to optimize the nested component/hook
* while its parent function remains uncompiled.
*/
validateNoDynamicallyCreatedComponentsOrHooks: z.boolean().default(false),
});
export type EnvironmentConfig = z.infer<typeof EnvironmentConfigSchema>;
@@ -861,16 +853,10 @@ export class Environment {
#resolveModuleType(moduleName: string, loc: SourceLocation): Global | null {
let moduleType = this.#moduleTypes.get(moduleName);
if (moduleType === undefined) {
/*
* NOTE: Zod doesn't work when specifying a function as a default, so we have to
* fallback to the default value here
*/
const moduleTypeProvider =
this.config.moduleTypeProvider ?? defaultModuleTypeProvider;
if (moduleTypeProvider == null) {
if (this.config.moduleTypeProvider == null) {
return null;
}
const unparsedModuleConfig = moduleTypeProvider(moduleName);
const unparsedModuleConfig = this.config.moduleTypeProvider(moduleName);
if (unparsedModuleConfig != null) {
const parsedModuleConfig = TypeSchema.safeParse(unparsedModuleConfig);
if (!parsedModuleConfig.success) {

View File

@@ -1001,7 +1001,6 @@ export function installTypeConfig(
mutableOnlyIfOperandsAreMutable:
typeConfig.mutableOnlyIfOperandsAreMutable === true,
aliasing: typeConfig.aliasing,
knownIncompatible: typeConfig.knownIncompatible ?? null,
});
}
case 'hook': {
@@ -1020,7 +1019,6 @@ export function installTypeConfig(
returnValueKind: typeConfig.returnValueKind ?? ValueKind.Frozen,
noAlias: typeConfig.noAlias === true,
aliasing: typeConfig.aliasing,
knownIncompatible: typeConfig.knownIncompatible ?? null,
});
}
case 'object': {

View File

@@ -323,22 +323,6 @@ export default class HIRBuilder {
],
});
}
if (node.name === 'this') {
CompilerError.throwDiagnostic({
severity: ErrorSeverity.UnsupportedJS,
category: ErrorCategory.UnsupportedSyntax,
reason: '`this` is not supported syntax',
description:
'React Compiler does not support compiling functions that use `this`',
details: [
{
kind: 'error',
message: '`this` was used here',
loc: node.loc ?? GeneratedSource,
},
],
});
}
const originalName = node.name;
let name = originalName;
let index = 0;

View File

@@ -332,7 +332,6 @@ export type FunctionSignature = {
mutableOnlyIfOperandsAreMutable?: boolean;
impure?: boolean;
knownIncompatible?: string | null | undefined;
canonicalName?: string;

View File

@@ -880,8 +880,7 @@ export function printType(type: Type): string {
if (type.kind === 'Object' && type.shapeId != null) {
return `:T${type.kind}<${type.shapeId}>`;
} else if (type.kind === 'Function' && type.shapeId != null) {
const returnType = printType(type.return);
return `:T${type.kind}<${type.shapeId}>()${returnType !== '' ? `: ${returnType}` : ''}`;
return `:T${type.kind}<${type.shapeId}>`;
} else {
return `:T${type.kind}`;
}
@@ -984,7 +983,7 @@ export function printAliasingEffect(effect: AliasingEffect): string {
case 'MutateConditionally':
case 'MutateTransitive':
case 'MutateTransitiveConditionally': {
return `${effect.kind} ${printPlaceForAliasEffect(effect.value)}${effect.kind === 'Mutate' && effect.reason?.kind === 'AssignCurrentProperty' ? ' (assign `.current`)' : ''}`;
return `${effect.kind} ${printPlaceForAliasEffect(effect.value)}`;
}
case 'MutateFrozen': {
return `MutateFrozen ${printPlaceForAliasEffect(effect.place)} reason=${JSON.stringify(effect.error.reason)}`;

View File

@@ -251,7 +251,6 @@ export type FunctionTypeConfig = {
impure?: boolean | null | undefined;
canonicalName?: string | null | undefined;
aliasing?: AliasingSignatureConfig | null | undefined;
knownIncompatible?: string | null | undefined;
};
export const FunctionTypeSchema: z.ZodType<FunctionTypeConfig> = z.object({
kind: z.literal('function'),
@@ -265,7 +264,6 @@ export const FunctionTypeSchema: z.ZodType<FunctionTypeConfig> = z.object({
impure: z.boolean().nullable().optional(),
canonicalName: z.string().nullable().optional(),
aliasing: AliasingSignatureSchema.nullable().optional(),
knownIncompatible: z.string().nullable().optional(),
});
export type HookTypeConfig = {
@@ -276,7 +274,6 @@ export type HookTypeConfig = {
returnValueKind?: ValueKind | null | undefined;
noAlias?: boolean | null | undefined;
aliasing?: AliasingSignatureConfig | null | undefined;
knownIncompatible?: string | null | undefined;
};
export const HookTypeSchema: z.ZodType<HookTypeConfig> = z.object({
kind: z.literal('hook'),
@@ -286,7 +283,6 @@ export const HookTypeSchema: z.ZodType<HookTypeConfig> = z.object({
returnValueKind: ValueKindSchema.nullable().optional(),
noAlias: z.boolean().nullable().optional(),
aliasing: AliasingSignatureSchema.nullable().optional(),
knownIncompatible: z.string().nullable().optional(),
});
export type BuiltInTypeConfig =

View File

@@ -27,7 +27,6 @@ import {
InstructionKind,
InstructionValue,
isArrayType,
isJsxType,
isMapType,
isPrimitiveType,
isRefOrRefValue,
@@ -1872,23 +1871,6 @@ function computeSignatureForInstruction(
});
}
}
for (const prop of value.props) {
if (
prop.kind === 'JsxAttribute' &&
prop.place.identifier.type.kind === 'Function' &&
(isJsxType(prop.place.identifier.type.return) ||
(prop.place.identifier.type.return.kind === 'Phi' &&
prop.place.identifier.type.return.operands.some(operand =>
isJsxType(operand),
)))
) {
// Any props which return jsx are assumed to be called during render
effects.push({
kind: 'Render',
place: prop.place,
});
}
}
}
break;
}
@@ -2170,27 +2152,6 @@ function computeEffectsForLegacySignature(
}),
});
}
if (signature.knownIncompatible != null && state.env.isInferredMemoEnabled) {
const errors = new CompilerError();
errors.pushDiagnostic(
CompilerDiagnostic.create({
category: ErrorCategory.IncompatibleLibrary,
severity: ErrorSeverity.IncompatibleLibrary,
reason: 'Use of incompatible library',
description: [
'This API returns functions which cannot be memoized without leading to stale UI. ' +
'To prevent this, by default React Compiler will skip memoizing this component/hook. ' +
'However, you may see issues if values from this API are passed to other components/hooks that are ' +
'memoized.',
].join(''),
}).withDetail({
kind: 'error',
loc: receiver.loc,
message: signature.knownIncompatible,
}),
);
throw errors;
}
const stores: Array<Place> = [];
const captures: Array<Place> = [];
function visit(place: Place, effect: Effect): void {

View File

@@ -27,7 +27,7 @@ import {
} from '../HIR/visitors';
import {assertExhaustive, getOrInsertWith} from '../Utils/utils';
import {Err, Ok, Result} from '../Utils/Result';
import {AliasingEffect, MutationReason} from './AliasingEffects';
import {AliasingEffect} from './AliasingEffects';
/**
* This pass builds an abstract model of the heap and interprets the effects of the
@@ -101,7 +101,6 @@ export function inferMutationAliasingRanges(
transitive: boolean;
kind: MutationKind;
place: Place;
reason: MutationReason | null;
}> = [];
const renders: Array<{index: number; place: Place}> = [];
@@ -177,7 +176,6 @@ export function inferMutationAliasingRanges(
effect.kind === 'MutateTransitive'
? MutationKind.Definite
: MutationKind.Conditional,
reason: null,
place: effect.value,
});
} else if (
@@ -192,7 +190,6 @@ export function inferMutationAliasingRanges(
effect.kind === 'Mutate'
? MutationKind.Definite
: MutationKind.Conditional,
reason: effect.kind === 'Mutate' ? (effect.reason ?? null) : null,
place: effect.value,
});
} else if (
@@ -244,7 +241,6 @@ export function inferMutationAliasingRanges(
mutation.transitive,
mutation.kind,
mutation.place.loc,
mutation.reason,
errors,
);
}
@@ -271,7 +267,6 @@ export function inferMutationAliasingRanges(
functionEffects.push({
kind: 'Mutate',
value: {...place, loc: node.local.loc},
reason: node.mutationReason,
});
}
}
@@ -512,7 +507,6 @@ export function inferMutationAliasingRanges(
true,
MutationKind.Conditional,
into.loc,
null,
ignoredErrors,
);
for (const from of tracked) {
@@ -586,7 +580,6 @@ type Node = {
transitive: {kind: MutationKind; loc: SourceLocation} | null;
local: {kind: MutationKind; loc: SourceLocation} | null;
lastMutated: number;
mutationReason: MutationReason | null;
value:
| {kind: 'Object'}
| {kind: 'Phi'}
@@ -606,7 +599,6 @@ class AliasingState {
transitive: null,
local: null,
lastMutated: 0,
mutationReason: null,
value,
});
}
@@ -705,7 +697,6 @@ class AliasingState {
transitive: boolean,
startKind: MutationKind,
loc: SourceLocation,
reason: MutationReason | null,
errors: CompilerError,
): void {
const seen = new Map<Identifier, MutationKind>();
@@ -726,7 +717,6 @@ class AliasingState {
if (node == null) {
continue;
}
node.mutationReason ??= reason;
node.lastMutated = Math.max(node.lastMutated, index);
if (end != null) {
node.id.mutableRange.end = makeInstructionId(

View File

@@ -777,15 +777,6 @@ class Unifier {
return {kind: 'Phi', operands: type.operands.map(o => this.get(o))};
}
if (type.kind === 'Function') {
return {
kind: 'Function',
isConstructor: type.isConstructor,
shapeId: type.shapeId,
return: this.get(type.return),
};
}
return type;
}
}

View File

@@ -182,11 +182,6 @@ export function parseConfigPragmaForTests(
environment?: PartialEnvironmentConfig;
},
): PluginOptions {
const overridePragma = parseConfigPragmaAsString(pragma);
if (overridePragma !== '') {
return parseConfigStringAsJS(overridePragma, defaults);
}
const environment = parseConfigPragmaEnvironmentForTest(
pragma,
defaults.environment ?? {},
@@ -222,104 +217,3 @@ export function parseConfigPragmaForTests(
}
return parsePluginOptions(options);
}
export function parseConfigPragmaAsString(pragma: string): string {
// Check if it's in JS override format
for (const {key, value: val} of splitPragma(pragma)) {
if (key === 'OVERRIDE' && val != null) {
return val;
}
}
return '';
}
function parseConfigStringAsJS(
configString: string,
defaults: {
compilationMode: CompilationMode;
environment?: PartialEnvironmentConfig;
},
): PluginOptions {
let parsedConfig: any;
try {
// Parse the JavaScript object literal
parsedConfig = new Function(`return ${configString}`)();
} catch (error) {
CompilerError.invariant(false, {
reason: 'Failed to parse config pragma as JavaScript object',
description: `Could not parse: ${configString}. Error: ${error}`,
loc: null,
suggestions: null,
});
}
console.log('OVERRIDE:', parsedConfig);
const options: Record<keyof PluginOptions, unknown> = {
...defaultOptions,
panicThreshold: 'all_errors',
compilationMode: defaults.compilationMode,
environment: defaults.environment ?? defaultOptions.environment,
};
// Apply parsed config, merging environment if it exists
if (parsedConfig.environment) {
const mergedEnvironment = {
...(options.environment as Record<string, unknown>),
...parsedConfig.environment,
};
// Apply complex defaults for environment flags that are set to true
const environmentConfig: Partial<Record<keyof EnvironmentConfig, unknown>> =
{};
for (const [key, value] of Object.entries(mergedEnvironment)) {
if (hasOwnProperty(EnvironmentConfigSchema.shape, key)) {
if (value === true && key in testComplexConfigDefaults) {
environmentConfig[key] = testComplexConfigDefaults[key];
} else {
environmentConfig[key] = value;
}
}
}
// Validate environment config
const validatedEnvironment =
EnvironmentConfigSchema.safeParse(environmentConfig);
if (!validatedEnvironment.success) {
CompilerError.invariant(false, {
reason: 'Invalid environment configuration in config pragma',
description: `${fromZodError(validatedEnvironment.error)}`,
loc: null,
suggestions: null,
});
}
if (validatedEnvironment.data.enableResetCacheOnSourceFileChanges == null) {
validatedEnvironment.data.enableResetCacheOnSourceFileChanges = false;
}
options.environment = validatedEnvironment.data;
}
// Apply other config options
for (const [key, value] of Object.entries(parsedConfig)) {
if (key === 'environment') {
continue;
}
if (hasOwnProperty(defaultOptions, key)) {
if (value === true && key in testComplexPluginOptionDefaults) {
options[key] = testComplexPluginOptionDefaults[key];
} else if (key === 'target' && value === 'donotuse_meta_internal') {
options[key] = {
kind: value,
runtimeModule: 'react',
};
} else {
options[key] = value;
}
}
}
return parsePluginOptions(options);
}

View File

@@ -284,7 +284,8 @@ function validateInferredDep(
CompilerDiagnostic.create({
category: ErrorCategory.PreserveManualMemo,
severity: ErrorSeverity.CannotPreserveMemoization,
reason: 'Existing memoization could not be preserved',
reason:
'Compilation skipped because existing memoization could not be preserved',
description: [
'React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. ',
'The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected. ',
@@ -538,7 +539,8 @@ class Visitor extends ReactiveFunctionVisitor<VisitorState> {
CompilerDiagnostic.create({
category: ErrorCategory.PreserveManualMemo,
severity: ErrorSeverity.CannotPreserveMemoization,
reason: 'Existing memoization could not be preserved',
reason:
'Compilation skipped because existing memoization could not be preserved',
description: [
'React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. ',
'This dependency may be mutated later, which could cause the value to change unexpectedly.',
@@ -586,7 +588,8 @@ class Visitor extends ReactiveFunctionVisitor<VisitorState> {
CompilerDiagnostic.create({
category: ErrorCategory.PreserveManualMemo,
severity: ErrorSeverity.CannotPreserveMemoization,
reason: 'Existing memoization could not be preserved',
reason:
'Compilation skipped because existing memoization could not be preserved',
description: [
'React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. This value was memoized in source but not in compilation output. ',
DEBUG

View File

@@ -24,18 +24,9 @@ function useThing(fn) {
```
Found 1 error:
Error: `this` is not supported syntax
Error: Expected a non-reserved identifier name
React Compiler does not support compiling functions that use `this`
error.reserved-words.ts:8:28
6 |
7 | if (ref.current === null) {
> 8 | ref.current = function (this: unknown, ...args) {
| ^^^^^^^^^^^^^ `this` was used here
9 | return fnRef.current.call(this, ...args);
10 | };
11 | }
`this` is a reserved word in JavaScript and cannot be used as an identifier name.
```

View File

@@ -1,37 +0,0 @@
## Input
```javascript
// Fixture to test that we show a hint to name as `ref` or `-Ref` when attempting
// to assign .current inside an effect
function Component({foo}) {
useEffect(() => {
foo.current = true;
}, [foo]);
}
```
## Error
```
Found 1 error:
Error: This value cannot be modified
Modifying component props or hook arguments is not allowed. Consider using a local variable instead.
error.assign-ref-in-effect-hint.ts:5:4
3 | function Component({foo}) {
4 | useEffect(() => {
> 5 | foo.current = true;
| ^^^ `foo` cannot be modified
6 | }, [foo]);
7 | }
8 |
Hint: If this value is a Ref (value returned by `useRef()`), rename the variable to end in "Ref".
```

View File

@@ -1,7 +0,0 @@
// Fixture to test that we show a hint to name as `ref` or `-Ref` when attempting
// to assign .current inside an effect
function Component({foo}) {
useEffect(() => {
foo.current = true;
}, [foo]);
}

View File

@@ -26,7 +26,7 @@ function Component(props) {
```
Found 1 error:
Compilation Skipped: Existing memoization could not be preserved
Memoization: Compilation skipped because existing memoization could not be preserved
React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected. The inferred dependency was `props.items`, but the source dependencies were [props?.items, props.cond]. Inferred different dependency than source.

View File

@@ -26,7 +26,7 @@ function Component(props) {
```
Found 1 error:
Compilation Skipped: Existing memoization could not be preserved
Memoization: Compilation skipped because existing memoization could not be preserved
React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected. The inferred dependency was `props.items`, but the source dependencies were [props?.items, props.cond]. Inferred different dependency than source.

View File

@@ -1,34 +0,0 @@
## Input
```javascript
import {knownIncompatible} from 'ReactCompilerKnownIncompatibleTest';
function Component() {
const data = knownIncompatible();
return <div>Error</div>;
}
```
## Error
```
Found 1 error:
Compilation Skipped: Use of incompatible library
This API returns functions which cannot be memoized without leading to stale UI. To prevent this, by default React Compiler will skip memoizing this component/hook. However, you may see issues if values from this API are passed to other components/hooks that are memoized.
error.invalid-known-incompatible-function.ts:4:15
2 |
3 | function Component() {
> 4 | const data = knownIncompatible();
| ^^^^^^^^^^^^^^^^^ useKnownIncompatible is known to be incompatible
5 | return <div>Error</div>;
6 | }
7 |
```

View File

@@ -1,6 +0,0 @@
import {knownIncompatible} from 'ReactCompilerKnownIncompatibleTest';
function Component() {
const data = knownIncompatible();
return <div>Error</div>;
}

View File

@@ -1,33 +0,0 @@
## Input
```javascript
import {useKnownIncompatibleIndirect} from 'ReactCompilerKnownIncompatibleTest';
function Component() {
const {incompatible} = useKnownIncompatibleIndirect();
return <div>{incompatible()}</div>;
}
```
## Error
```
Found 1 error:
Compilation Skipped: Use of incompatible library
This API returns functions which cannot be memoized without leading to stale UI. To prevent this, by default React Compiler will skip memoizing this component/hook. However, you may see issues if values from this API are passed to other components/hooks that are memoized.
error.invalid-known-incompatible-hook-return-property.ts:5:15
3 | function Component() {
4 | const {incompatible} = useKnownIncompatibleIndirect();
> 5 | return <div>{incompatible()}</div>;
| ^^^^^^^^^^^^ useKnownIncompatibleIndirect returns an incompatible() function that is known incompatible
6 | }
7 |
```

View File

@@ -1,6 +0,0 @@
import {useKnownIncompatibleIndirect} from 'ReactCompilerKnownIncompatibleTest';
function Component() {
const {incompatible} = useKnownIncompatibleIndirect();
return <div>{incompatible()}</div>;
}

View File

@@ -1,34 +0,0 @@
## Input
```javascript
import {useKnownIncompatible} from 'ReactCompilerKnownIncompatibleTest';
function Component() {
const data = useKnownIncompatible();
return <div>Error</div>;
}
```
## Error
```
Found 1 error:
Compilation Skipped: Use of incompatible library
This API returns functions which cannot be memoized without leading to stale UI. To prevent this, by default React Compiler will skip memoizing this component/hook. However, you may see issues if values from this API are passed to other components/hooks that are memoized.
error.invalid-known-incompatible-hook.ts:4:15
2 |
3 | function Component() {
> 4 | const data = useKnownIncompatible();
| ^^^^^^^^^^^^^^^^^^^^ useKnownIncompatible is known to be incompatible
5 | return <div>Error</div>;
6 | }
7 |
```

View File

@@ -1,6 +0,0 @@
import {useKnownIncompatible} from 'ReactCompilerKnownIncompatibleTest';
function Component() {
const data = useKnownIncompatible();
return <div>Error</div>;
}

View File

@@ -38,8 +38,6 @@ error.invalid-mutate-context-in-callback.ts:12:4
13 | };
14 | return <div onClick={onClick} />;
15 | }
Hint: If this value is a Ref (value returned by `useRef()`), rename the variable to end in "Ref".
```

View File

@@ -1,44 +0,0 @@
## Input
```javascript
function Component() {
const renderItem = item => {
// Multiple returns so that the return type is a Phi (union)
if (item == null) {
return null;
}
// Normally we assume that it's safe to mutate globals in a function passed
// as a prop, because the prop could be used as an event handler or effect.
// But if the function returns JSX we can assume it's a render helper, ie
// called during render, and thus it's unsafe to mutate globals or call
// other impure code.
global.property = true;
return <Item item={item} value={rand} />;
};
return <ItemList renderItem={renderItem} />;
}
```
## Error
```
Found 1 error:
Error: This value cannot be modified
Modifying a variable defined outside a component or hook is not allowed. Consider using an effect.
error.invalid-mutate-global-in-render-helper-phi-return-prop.ts:12:4
10 | // called during render, and thus it's unsafe to mutate globals or call
11 | // other impure code.
> 12 | global.property = true;
| ^^^^^^ value cannot be modified
13 | return <Item item={item} value={rand} />;
14 | };
15 | return <ItemList renderItem={renderItem} />;
```

View File

@@ -1,16 +0,0 @@
function Component() {
const renderItem = item => {
// Multiple returns so that the return type is a Phi (union)
if (item == null) {
return null;
}
// Normally we assume that it's safe to mutate globals in a function passed
// as a prop, because the prop could be used as an event handler or effect.
// But if the function returns JSX we can assume it's a render helper, ie
// called during render, and thus it's unsafe to mutate globals or call
// other impure code.
global.property = true;
return <Item item={item} value={rand} />;
};
return <ItemList renderItem={renderItem} />;
}

View File

@@ -1,40 +0,0 @@
## Input
```javascript
function Component() {
const renderItem = item => {
// Normally we assume that it's safe to mutate globals in a function passed
// as a prop, because the prop could be used as an event handler or effect.
// But if the function returns JSX we can assume it's a render helper, ie
// called during render, and thus it's unsafe to mutate globals or call
// other impure code.
global.property = true;
return <Item item={item} value={rand} />;
};
return <ItemList renderItem={renderItem} />;
}
```
## Error
```
Found 1 error:
Error: This value cannot be modified
Modifying a variable defined outside a component or hook is not allowed. Consider using an effect.
error.invalid-mutate-global-in-render-helper-prop.ts:8:4
6 | // called during render, and thus it's unsafe to mutate globals or call
7 | // other impure code.
> 8 | global.property = true;
| ^^^^^^ value cannot be modified
9 | return <Item item={item} value={rand} />;
10 | };
11 | return <ItemList renderItem={renderItem} />;
```

View File

@@ -1,12 +0,0 @@
function Component() {
const renderItem = item => {
// Normally we assume that it's safe to mutate globals in a function passed
// as a prop, because the prop could be used as an event handler or effect.
// But if the function returns JSX we can assume it's a render helper, ie
// called during render, and thus it's unsafe to mutate globals or call
// other impure code.
global.property = true;
return <Item item={item} value={rand} />;
};
return <ItemList renderItem={renderItem} />;
}

View File

@@ -20,7 +20,7 @@ function Component(props) {
```
Found 1 error:
Compilation Skipped: Existing memoization could not be preserved
Memoization: Compilation skipped because existing memoization could not be preserved
React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected. The inferred dependency was `props.items.edges.nodes`, but the source dependencies were [props.items?.edges?.nodes]. Inferred different dependency than source.

View File

@@ -25,7 +25,7 @@ function Component(props) {
```
Found 1 error:
Compilation Skipped: React Compiler has skipped optimizing this component because the effect dependencies could not be memoized. Unmemoized effect dependencies can trigger an infinite loop or other unexpected behavior
Memoization: React Compiler has skipped optimizing this component because the effect dependencies could not be memoized. Unmemoized effect dependencies can trigger an infinite loop or other unexpected behavior
error.invalid-useEffect-dep-not-memoized-bc-range-overlaps-hook.ts:9:2
7 |

View File

@@ -22,7 +22,7 @@ function Component(props) {
```
Found 1 error:
Compilation Skipped: React Compiler has skipped optimizing this component because the effect dependencies could not be memoized. Unmemoized effect dependencies can trigger an infinite loop or other unexpected behavior
Memoization: React Compiler has skipped optimizing this component because the effect dependencies could not be memoized. Unmemoized effect dependencies can trigger an infinite loop or other unexpected behavior
error.invalid-useEffect-dep-not-memoized.ts:6:2
4 | function Component(props) {

View File

@@ -22,7 +22,7 @@ function Component(props) {
```
Found 1 error:
Compilation Skipped: React Compiler has skipped optimizing this component because the effect dependencies could not be memoized. Unmemoized effect dependencies can trigger an infinite loop or other unexpected behavior
Memoization: React Compiler has skipped optimizing this component because the effect dependencies could not be memoized. Unmemoized effect dependencies can trigger an infinite loop or other unexpected behavior
error.invalid-useInsertionEffect-dep-not-memoized.ts:6:2
4 | function Component(props) {

View File

@@ -22,7 +22,7 @@ function Component(props) {
```
Found 1 error:
Compilation Skipped: React Compiler has skipped optimizing this component because the effect dependencies could not be memoized. Unmemoized effect dependencies can trigger an infinite loop or other unexpected behavior
Memoization: React Compiler has skipped optimizing this component because the effect dependencies could not be memoized. Unmemoized effect dependencies can trigger an infinite loop or other unexpected behavior
error.invalid-useLayoutEffect-dep-not-memoized.ts:6:2
4 | function Component(props) {

View File

@@ -1,54 +0,0 @@
## Input
```javascript
// @validateNoDynamicallyCreatedComponentsOrHooks
export function getInput(a) {
const Wrapper = () => {
const handleChange = () => {
a.onChange();
};
return <input onChange={handleChange} />;
};
return Wrapper;
}
export const FIXTURE_ENTRYPOINT = {
fn: getInput,
isComponent: false,
params: [{onChange() {}}],
};
```
## Error
```
Found 1 error:
Error: Components and hooks cannot be created dynamically
The function `Wrapper` appears to be a React component, but it's defined inside `getInput`. Components and Hooks should always be declared at module scope
error.nested-component-in-normal-function.ts:2:16
1 | // @validateNoDynamicallyCreatedComponentsOrHooks
> 2 | export function getInput(a) {
| ^^^^^^^^ this function dynamically created a component/hook
3 | const Wrapper = () => {
4 | const handleChange = () => {
5 | a.onChange();
error.nested-component-in-normal-function.ts:3:8
1 | // @validateNoDynamicallyCreatedComponentsOrHooks
2 | export function getInput(a) {
> 3 | const Wrapper = () => {
| ^^^^^^^ the component is created here
4 | const handleChange = () => {
5 | a.onChange();
6 | };
```

View File

@@ -1,18 +0,0 @@
// @validateNoDynamicallyCreatedComponentsOrHooks
export function getInput(a) {
const Wrapper = () => {
const handleChange = () => {
a.onChange();
};
return <input onChange={handleChange} />;
};
return Wrapper;
}
export const FIXTURE_ENTRYPOINT = {
fn: getInput,
isComponent: false,
params: [{onChange() {}}],
};

View File

@@ -1,59 +0,0 @@
## Input
```javascript
// @validateNoDynamicallyCreatedComponentsOrHooks
import {useState} from 'react';
function createCustomHook(config) {
function useConfiguredState() {
const [state, setState] = useState(0);
const increment = () => {
setState(state + config.step);
};
return [state, increment];
}
return useConfiguredState;
}
export const FIXTURE_ENTRYPOINT = {
fn: createCustomHook,
isComponent: false,
params: [{step: 1}],
};
```
## Error
```
Found 1 error:
Error: Components and hooks cannot be created dynamically
The function `useConfiguredState` appears to be a React hook, but it's defined inside `createCustomHook`. Components and Hooks should always be declared at module scope
error.nested-hook-in-normal-function.ts:4:9
2 | import {useState} from 'react';
3 |
> 4 | function createCustomHook(config) {
| ^^^^^^^^^^^^^^^^ this function dynamically created a component/hook
5 | function useConfiguredState() {
6 | const [state, setState] = useState(0);
7 |
error.nested-hook-in-normal-function.ts:5:11
3 |
4 | function createCustomHook(config) {
> 5 | function useConfiguredState() {
| ^^^^^^^^^^^^^^^^^^ the component is created here
6 | const [state, setState] = useState(0);
7 |
8 | const increment = () => {
```

View File

@@ -1,22 +0,0 @@
// @validateNoDynamicallyCreatedComponentsOrHooks
import {useState} from 'react';
function createCustomHook(config) {
function useConfiguredState() {
const [state, setState] = useState(0);
const increment = () => {
setState(state + config.step);
};
return [state, increment];
}
return useConfiguredState;
}
export const FIXTURE_ENTRYPOINT = {
fn: createCustomHook,
isComponent: false,
params: [{step: 1}],
};

View File

@@ -33,7 +33,7 @@ export const FIXTURE_ENTRYPOINT = {
```
Found 1 error:
Compilation Skipped: Existing memoization could not be preserved
Memoization: Compilation skipped because existing memoization could not be preserved
React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected. The inferred dependency was `Ref.current`, but the source dependencies were []. Inferred dependency not present in source.

View File

@@ -33,7 +33,7 @@ export const FIXTURE_ENTRYPOINT = {
```
Found 1 error:
Compilation Skipped: Existing memoization could not be preserved
Memoization: Compilation skipped because existing memoization could not be preserved
React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected. The inferred dependency was `notaref.current`, but the source dependencies were []. Inferred dependency not present in source.

View File

@@ -44,7 +44,7 @@ component Component() {
```
Found 1 error:
Compilation Skipped: Existing memoization could not be preserved
Memoization: Compilation skipped because existing memoization could not be preserved
React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. This value was memoized in source but not in compilation output.

View File

@@ -54,7 +54,7 @@ component Component(id) {
```
Found 3 errors:
Compilation Skipped: Existing memoization could not be preserved
Memoization: Compilation skipped because existing memoization could not be preserved
React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. This value was memoized in source but not in compilation output.
@@ -76,7 +76,7 @@ React Compiler has skipped optimizing this component because the existing manual
18 | const setCurrentIndex = useCallback(
19 | (index: number) => {
Compilation Skipped: Existing memoization could not be preserved
Memoization: Compilation skipped because existing memoization could not be preserved
React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. This dependency may be mutated later, which could cause the value to change unexpectedly.
@@ -88,7 +88,7 @@ React Compiler has skipped optimizing this component because the existing manual
30 |
31 | if (prevId !== id) {
Compilation Skipped: Existing memoization could not be preserved
Memoization: Compilation skipped because existing memoization could not be preserved
React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. This value was memoized in source but not in compilation output.

View File

@@ -52,7 +52,7 @@ export const FIXTURE_ENTRYPOINT = {
```
Found 1 error:
Compilation Skipped: Existing memoization could not be preserved
Memoization: Compilation skipped because existing memoization could not be preserved
React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. This value was memoized in source but not in compilation output.

View File

@@ -30,7 +30,7 @@ export const FIXTURE_ENTRYPOINT = {
```
Found 1 error:
Compilation Skipped: React Compiler has skipped optimizing this component because the effect dependencies could not be memoized. Unmemoized effect dependencies can trigger an infinite loop or other unexpected behavior
Memoization: React Compiler has skipped optimizing this component because the effect dependencies could not be memoized. Unmemoized effect dependencies can trigger an infinite loop or other unexpected behavior
error.validate-memoized-effect-deps-invalidated-dep-value.ts:11:2
9 | const y = [x];

View File

@@ -27,7 +27,7 @@ export const FIXTURE_ENTRYPOINT = {
```
Found 2 errors:
Compilation Skipped: Existing memoization could not be preserved
Memoization: Compilation skipped because existing memoization could not be preserved
React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. This dependency may be mutated later, which could cause the value to change unexpectedly.
@@ -40,7 +40,7 @@ error.validate-object-entries-mutation.ts:6:57
8 | value.updated = true;
9 | });
Compilation Skipped: Existing memoization could not be preserved
Memoization: Compilation skipped because existing memoization could not be preserved
React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. This value was memoized in source but not in compilation output.

View File

@@ -27,7 +27,7 @@ export const FIXTURE_ENTRYPOINT = {
```
Found 2 errors:
Compilation Skipped: Existing memoization could not be preserved
Memoization: Compilation skipped because existing memoization could not be preserved
React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. This dependency may be mutated later, which could cause the value to change unexpectedly.
@@ -40,7 +40,7 @@ error.validate-object-values-mutation.ts:6:55
8 | value.updated = true;
9 | });
Compilation Skipped: Existing memoization could not be preserved
Memoization: Compilation skipped because existing memoization could not be preserved
React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. This value was memoized in source but not in compilation output.

View File

@@ -58,7 +58,7 @@ export const FIXTURE_ENTRYPOINT = {
## Logs
```
{"kind":"CompileError","fnLoc":{"start":{"line":6,"column":0,"index":206},"end":{"line":16,"column":1,"index":433},"filename":"dynamic-gating-bailout-nopanic.ts"},"detail":{"options":{"category":"PreserveManualMemo","severity":"CannotPreserveMemoization","reason":"Existing memoization could not be preserved","description":"React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected. The inferred dependency was `value`, but the source dependencies were []. Inferred dependency not present in source.","suggestions":null,"details":[{"kind":"error","loc":{"start":{"line":9,"column":31,"index":288},"end":{"line":9,"column":52,"index":309},"filename":"dynamic-gating-bailout-nopanic.ts"},"message":"Could not preserve existing manual memoization"}]}}}
{"kind":"CompileError","fnLoc":{"start":{"line":6,"column":0,"index":206},"end":{"line":16,"column":1,"index":433},"filename":"dynamic-gating-bailout-nopanic.ts"},"detail":{"options":{"category":"PreserveManualMemo","severity":"CannotPreserveMemoization","reason":"Compilation skipped because existing memoization could not be preserved","description":"React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected. The inferred dependency was `value`, but the source dependencies were []. Inferred dependency not present in source.","suggestions":null,"details":[{"kind":"error","loc":{"start":{"line":9,"column":31,"index":288},"end":{"line":9,"column":52,"index":309},"filename":"dynamic-gating-bailout-nopanic.ts"},"message":"Could not preserve existing manual memoization"}]}}}
```
### Eval output

View File

@@ -31,7 +31,7 @@ export const FIXTURE_ENTRYPOINT = {
```
Found 2 errors:
Compilation Skipped: Existing memoization could not be preserved
Memoization: Compilation skipped because existing memoization could not be preserved
React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. This dependency may be mutated later, which could cause the value to change unexpectedly.
@@ -44,7 +44,7 @@ error.invalid-useCallback-captures-reassigned-context.ts:11:37
13 | x = makeArray();
14 |
Compilation Skipped: Existing memoization could not be preserved
Memoization: Compilation skipped because existing memoization could not be preserved
React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. This value was memoized in source but not in compilation output.

View File

@@ -32,7 +32,7 @@ export const FIXTURE_ENTRYPOINT = {
```
Found 1 error:
Compilation Skipped: Existing memoization could not be preserved
Memoization: Compilation skipped because existing memoization could not be preserved
React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. This value was memoized in source but not in compilation output.

View File

@@ -31,7 +31,7 @@ export const FIXTURE_ENTRYPOINT = {
```
Found 1 error:
Compilation Skipped: Existing memoization could not be preserved
Memoization: Compilation skipped because existing memoization could not be preserved
React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. This dependency may be mutated later, which could cause the value to change unexpectedly.

View File

@@ -42,7 +42,7 @@ export const FIXTURE_ENTRYPOINT = {
```
Found 1 error:
Compilation Skipped: Existing memoization could not be preserved
Memoization: Compilation skipped because existing memoization could not be preserved
React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. This dependency may be mutated later, which could cause the value to change unexpectedly.

View File

@@ -28,7 +28,7 @@ export const FIXTURE_ENTRYPOINT = {
```
Found 1 error:
Compilation Skipped: Existing memoization could not be preserved
Memoization: Compilation skipped because existing memoization could not be preserved
React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected. The inferred dependency was `propB`, but the source dependencies were [propA, propB.x.y]. Inferred less specific property than source.

View File

@@ -31,7 +31,7 @@ export const FIXTURE_ENTRYPOINT = {
```
Found 2 errors:
Compilation Skipped: Existing memoization could not be preserved
Memoization: Compilation skipped because existing memoization could not be preserved
React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected. The inferred dependency was `propA`, but the source dependencies were [propA.a, propB.x.y]. Inferred less specific property than source.
@@ -60,7 +60,7 @@ error.hoist-useCallback-infer-conditional-value-block.ts:6:21
16 |
17 | export const FIXTURE_ENTRYPOINT = {
Compilation Skipped: Existing memoization could not be preserved
Memoization: Compilation skipped because existing memoization could not be preserved
React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected. The inferred dependency was `propB`, but the source dependencies were [propA.a, propB.x.y]. Inferred less specific property than source.

View File

@@ -32,7 +32,7 @@ export const FIXTURE_ENTRYPOINT = {
```
Found 2 errors:
Compilation Skipped: Existing memoization could not be preserved
Memoization: Compilation skipped because existing memoization could not be preserved
React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. This dependency may be mutated later, which could cause the value to change unexpectedly.
@@ -45,7 +45,7 @@ error.invalid-useCallback-captures-reassigned-context.ts:12:37
14 | x = makeArray();
15 |
Compilation Skipped: Existing memoization could not be preserved
Memoization: Compilation skipped because existing memoization could not be preserved
React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. This value was memoized in source but not in compilation output.

View File

@@ -30,7 +30,7 @@ export const FIXTURE_ENTRYPOINT = {
```
Found 1 error:
Compilation Skipped: Existing memoization could not be preserved
Memoization: Compilation skipped because existing memoization could not be preserved
React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected. The inferred dependency was `ref`, but the source dependencies were []. Inferred dependency not present in source.

View File

@@ -30,7 +30,7 @@ export const FIXTURE_ENTRYPOINT = {
```
Found 1 error:
Compilation Skipped: Existing memoization could not be preserved
Memoization: Compilation skipped because existing memoization could not be preserved
React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. This value was memoized in source but not in compilation output.

View File

@@ -21,7 +21,7 @@ function useHook(x) {
```
Found 1 error:
Compilation Skipped: Existing memoization could not be preserved
Memoization: Compilation skipped because existing memoization could not be preserved
React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected. The inferred dependency was `aliasedX`, but the source dependencies were [x, aliasedProp]. Inferred different dependency than source.

View File

@@ -27,7 +27,7 @@ export const FIXTURE_ENTRYPOINT = {
```
Found 1 error:
Compilation Skipped: Existing memoization could not be preserved
Memoization: Compilation skipped because existing memoization could not be preserved
React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected. The inferred dependency was `propB?.x.y`, but the source dependencies were [propA, propB.x.y]. Inferred different dependency than source.

View File

@@ -26,7 +26,7 @@ function Component({propA, propB}) {
```
Found 1 error:
Compilation Skipped: Existing memoization could not be preserved
Memoization: Compilation skipped because existing memoization could not be preserved
React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected. The inferred dependency was `propB`, but the source dependencies were [propA?.a, propB.x.y]. Inferred less specific property than source.

View File

@@ -19,7 +19,7 @@ function Component({propA}) {
```
Found 1 error:
Compilation Skipped: Existing memoization could not be preserved
Memoization: Compilation skipped because existing memoization could not be preserved
React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected. The inferred dependency was `propA`, but the source dependencies were [propA.x]. Inferred less specific property than source.

View File

@@ -21,7 +21,7 @@ function useHook(x) {
```
Found 1 error:
Compilation Skipped: Existing memoization could not be preserved
Memoization: Compilation skipped because existing memoization could not be preserved
React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected. The inferred dependency was `x`, but the source dependencies were [aliasedX, aliasedProp]. Inferred different dependency than source.

View File

@@ -26,7 +26,7 @@ function Component({propA, propB}) {
```
Found 1 error:
Compilation Skipped: Existing memoization could not be preserved
Memoization: Compilation skipped because existing memoization could not be preserved
React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected. The inferred dependency was `propB`, but the source dependencies were [propA?.a, propB.x.y]. Inferred less specific property than source.

View File

@@ -26,7 +26,7 @@ function Component({propA, propB}) {
```
Found 2 errors:
Compilation Skipped: Existing memoization could not be preserved
Memoization: Compilation skipped because existing memoization could not be preserved
React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected. The inferred dependency was `propA`, but the source dependencies were [propA.a, propB.x.y]. Inferred less specific property than source.
@@ -54,7 +54,7 @@ error.useMemo-infer-less-specific-conditional-value-block.ts:6:17
15 | }
16 |
Compilation Skipped: Existing memoization could not be preserved
Memoization: Compilation skipped because existing memoization could not be preserved
React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected. The inferred dependency was `propB`, but the source dependencies were [propA.a, propB.x.y]. Inferred less specific property than source.

View File

@@ -21,7 +21,7 @@ function Component({propA}) {
```
Found 1 error:
Compilation Skipped: Existing memoization could not be preserved
Memoization: Compilation skipped because existing memoization could not be preserved
React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected. The inferred dependency was `propA`, but the source dependencies were [propA.x]. Inferred less specific property than source.

View File

@@ -19,7 +19,7 @@ function Component({propA}) {
```
Found 1 error:
Compilation Skipped: Existing memoization could not be preserved
Memoization: Compilation skipped because existing memoization could not be preserved
React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected. The inferred dependency was `propA`, but the source dependencies were [propA.x]. Inferred less specific property than source.

View File

@@ -32,7 +32,7 @@ function useFoo(input1) {
```
Found 1 error:
Compilation Skipped: Existing memoization could not be preserved
Memoization: Compilation skipped because existing memoization could not be preserved
React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected. The inferred dependency was `input1`, but the source dependencies were [y]. Inferred different dependency than source.

View File

@@ -26,7 +26,7 @@ function Component(props) {
```
Found 1 error:
Compilation Skipped: Existing memoization could not be preserved
Memoization: Compilation skipped because existing memoization could not be preserved
React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected. The inferred dependency was `props.items`, but the source dependencies were [props?.items, props.cond]. Inferred different dependency than source.

View File

@@ -26,7 +26,7 @@ function Component(props) {
```
Found 1 error:
Compilation Skipped: Existing memoization could not be preserved
Memoization: Compilation skipped because existing memoization could not be preserved
React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected. The inferred dependency was `props.items`, but the source dependencies were [props?.items, props.cond]. Inferred different dependency than source.

View File

@@ -48,10 +48,7 @@ export {
printReactiveFunction,
printReactiveFunctionWithOutlined,
} from './ReactiveScopes';
export {
parseConfigPragmaForTests,
parseConfigPragmaAsString,
} from './Utils/TestUtils';
export {parseConfigPragmaForTests} from './Utils/TestUtils';
declare global {
let __DEV__: boolean | null | undefined;
}

View File

@@ -198,51 +198,6 @@ export function makeSharedRuntimeTypeProvider({
},
},
};
} else if (moduleName === 'ReactCompilerKnownIncompatibleTest') {
/**
* Fake module used for testing validation of known incompatible
* API validation
*/
return {
kind: 'object',
properties: {
useKnownIncompatible: {
kind: 'hook',
positionalParams: [],
restParam: EffectEnum.Read,
returnType: {kind: 'type', name: 'Any'},
knownIncompatible: `useKnownIncompatible is known to be incompatible`,
},
useKnownIncompatibleIndirect: {
kind: 'hook',
positionalParams: [],
restParam: EffectEnum.Read,
returnType: {
kind: 'object',
properties: {
incompatible: {
kind: 'function',
positionalParams: [],
restParam: EffectEnum.Read,
calleeEffect: EffectEnum.Read,
returnType: {kind: 'type', name: 'Any'},
returnValueKind: ValueKindEnum.Mutable,
knownIncompatible: `useKnownIncompatibleIndirect returns an incompatible() function that is known incompatible`,
},
},
},
},
knownIncompatible: {
kind: 'function',
positionalParams: [],
restParam: EffectEnum.Read,
calleeEffect: EffectEnum.Read,
returnType: {kind: 'type', name: 'Any'},
returnValueKind: ValueKindEnum.Mutable,
knownIncompatible: `useKnownIncompatible is known to be incompatible`,
},
},
};
} else if (moduleName === 'ReactCompilerTest') {
/**
* Fake module used for testing validation that type providers return hook

View File

@@ -1,32 +0,0 @@
const ReactCompiler = require('../packages/babel-plugin-react-compiler/dist');
const combinedRules = [
{
name: 'rules-of-hooks',
recommended: true,
description:
'Validates that components and hooks follow the [Rules of Hooks](https://react.dev/reference/rules/rules-of-hooks)',
},
{
name: 'exhaustive-deps',
recommended: true,
description:
'Validates that hooks which accept dependency arrays (`useMemo()`, `useCallback()`, `useEffect()`, etc) ' +
'list all referenced variables in their dependency array. Referencing a value without including it in the ' +
'dependency array can lead to stale UI or callbacks.',
},
...ReactCompiler.LintRules,
];
const printed = combinedRules
.filter(rule => rule.recommended)
.map(rule => {
return `
## \`react-hooks/${rule.name}\`
${rule.description}
`.trim();
})
.join('\n\n');
console.log(printed);

View File

@@ -3,7 +3,7 @@ import Fixture from '../../Fixture';
const React = window.React;
const {Fragment, useRef} = React;
const {Fragment, useEffect, useRef, useState} = React;
export default function FocusCase() {
const fragmentRef = useRef(null);

View File

@@ -2,7 +2,7 @@ import TestCase from '../../TestCase';
import Fixture from '../../Fixture';
const React = window.React;
const {Fragment, useRef, useState} = React;
const {Fragment, useEffect, useRef, useState} = React;
export default function GetClientRectsCase() {
const fragmentRef = useRef(null);

View File

@@ -1,184 +0,0 @@
import TestCase from '../../TestCase';
import Fixture from '../../Fixture';
import ScrollIntoViewCaseComplex from './ScrollIntoViewCaseComplex';
import ScrollIntoViewCaseSimple from './ScrollIntoViewCaseSimple';
import ScrollIntoViewTargetElement from './ScrollIntoViewTargetElement';
const React = window.React;
const {Fragment, useRef, useState, useEffect} = React;
const ReactDOM = window.ReactDOM;
function Controls({
alignToTop,
setAlignToTop,
scrollVertical,
exampleType,
setExampleType,
}) {
return (
<div>
<label>
Example Type:
<select
value={exampleType}
onChange={e => setExampleType(e.target.value)}>
<option value="simple">Simple</option>
<option value="multiple">Multiple Scroll Containers</option>
<option value="horizontal">Horizontal</option>
<option value="empty">Empty Fragment</option>
</select>
</label>
<div>
<label>
Align to Top:
<input
type="checkbox"
checked={alignToTop}
onChange={e => setAlignToTop(e.target.checked)}
/>
</label>
</div>
<div>
<button onClick={scrollVertical}>scrollIntoView()</button>
</div>
</div>
);
}
export default function ScrollIntoViewCase() {
const [exampleType, setExampleType] = useState('simple');
const [alignToTop, setAlignToTop] = useState(true);
const [caseInViewport, setCaseInViewport] = useState(false);
const fragmentRef = useRef(null);
const testCaseRef = useRef(null);
const noChildRef = useRef(null);
const scrollContainerRef = useRef(null);
const scrollVertical = () => {
fragmentRef.current.experimental_scrollIntoView(alignToTop);
};
const scrollVerticalNoChildren = () => {
noChildRef.current.experimental_scrollIntoView(alignToTop);
};
useEffect(() => {
const observer = new IntersectionObserver(entries => {
entries.forEach(entry => {
if (entry.isIntersecting) {
setCaseInViewport(true);
} else {
setCaseInViewport(false);
}
});
});
testCaseRef.current.observeUsing(observer);
const lastRef = testCaseRef.current;
return () => {
lastRef.unobserveUsing(observer);
observer.disconnect();
};
});
return (
<Fragment ref={testCaseRef}>
<TestCase title="ScrollIntoView">
<TestCase.Steps>
<li>Toggle alignToTop and click the buttons to scroll</li>
</TestCase.Steps>
<TestCase.ExpectedResult>
<p>When the Fragment has children:</p>
<p>
In order to handle the case where children are split between
multiple scroll containers, we call scrollIntoView on each child in
reverse order.
</p>
<p>When the Fragment does not have children:</p>
<p>
The Fragment still represents a virtual space. We can scroll to the
nearest edge by selecting the host sibling before if
alignToTop=false, or after if alignToTop=true|undefined. We'll fall
back to the other sibling or parent in the case that the preferred
sibling target doesn't exist.
</p>
</TestCase.ExpectedResult>
<Fixture>
<Fixture.Controls>
<Controls
alignToTop={alignToTop}
setAlignToTop={setAlignToTop}
scrollVertical={scrollVertical}
exampleType={exampleType}
setExampleType={setExampleType}
/>
</Fixture.Controls>
{exampleType === 'simple' && (
<Fragment ref={fragmentRef}>
<ScrollIntoViewCaseSimple />
</Fragment>
)}
{exampleType === 'horizontal' && (
<div
style={{
display: 'flex',
overflowX: 'auto',
flexDirection: 'row',
border: '1px solid #ccc',
padding: '1rem 10rem',
marginBottom: '1rem',
width: '100%',
whiteSpace: 'nowrap',
justifyContent: 'space-between',
}}>
<Fragment ref={fragmentRef}>
<ScrollIntoViewCaseSimple />
</Fragment>
</div>
)}
{exampleType === 'multiple' && (
<Fragment>
<div
style={{
height: '50vh',
overflowY: 'auto',
border: '1px solid black',
marginBottom: '1rem',
}}
ref={scrollContainerRef}
/>
<Fragment ref={fragmentRef}>
<ScrollIntoViewCaseComplex
caseInViewport={caseInViewport}
scrollContainerRef={scrollContainerRef}
/>
</Fragment>
</Fragment>
)}
{exampleType === 'empty' && (
<Fragment>
<ScrollIntoViewTargetElement
color="lightyellow"
id="ABOVE EMPTY FRAGMENT"
/>
<Fragment ref={fragmentRef}></Fragment>
<ScrollIntoViewTargetElement
color="lightblue"
id="BELOW EMPTY FRAGMENT"
/>
</Fragment>
)}
<Fixture.Controls>
<Controls
alignToTop={alignToTop}
setAlignToTop={setAlignToTop}
scrollVertical={scrollVertical}
exampleType={exampleType}
setExampleType={setExampleType}
/>
</Fixture.Controls>
</Fixture>
</TestCase>
</Fragment>
);
}

View File

@@ -1,50 +0,0 @@
import ScrollIntoViewTargetElement from './ScrollIntoViewTargetElement';
const React = window.React;
const {Fragment, useRef, useState, useEffect} = React;
const ReactDOM = window.ReactDOM;
export default function ScrollIntoViewCaseComplex({
caseInViewport,
scrollContainerRef,
}) {
const [didMount, setDidMount] = useState(false);
// Hack to portal child into the scroll container
// after the first render. This is to simulate a case where
// an item is portaled into another scroll container.
useEffect(() => {
if (!didMount) {
setDidMount(true);
}
}, []);
return (
<Fragment>
{caseInViewport && (
<div
style={{position: 'fixed', top: 0, backgroundColor: 'red'}}
id="header">
Fixed header
</div>
)}
{didMount &&
ReactDOM.createPortal(
<ScrollIntoViewTargetElement color="red" id="FROM_PORTAL" />,
scrollContainerRef.current
)}
<ScrollIntoViewTargetElement color="lightgreen" id="A" />
<ScrollIntoViewTargetElement color="lightcoral" id="B" />
<ScrollIntoViewTargetElement color="lightblue" id="C" />
{caseInViewport && (
<div
style={{
position: 'fixed',
bottom: 0,
backgroundColor: 'purple',
}}
id="footer">
Fixed footer
</div>
)}
</Fragment>
);
}

View File

@@ -1,14 +0,0 @@
import ScrollIntoViewTargetElement from './ScrollIntoViewTargetElement';
const React = window.React;
const {Fragment} = React;
export default function ScrollIntoViewCaseSimple() {
return (
<Fragment>
<ScrollIntoViewTargetElement color="lightyellow" id="SCROLLABLE-1" />
<ScrollIntoViewTargetElement color="lightpink" id="SCROLLABLE-2" />
<ScrollIntoViewTargetElement color="lightcyan" id="SCROLLABLE-3" />
</Fragment>
);
}

View File

@@ -1,18 +0,0 @@
const React = window.React;
export default function ScrollIntoViewTargetElement({color, id, top}) {
return (
<div
id={id}
style={{
height: 500,
minWidth: 300,
backgroundColor: color,
marginTop: top ? '50vh' : 0,
marginBottom: 100,
flexShrink: 0,
}}>
{id}
</div>
);
}

View File

@@ -5,7 +5,6 @@ import IntersectionObserverCase from './IntersectionObserverCase';
import ResizeObserverCase from './ResizeObserverCase';
import FocusCase from './FocusCase';
import GetClientRectsCase from './GetClientRectsCase';
import ScrollIntoViewCase from './ScrollIntoViewCase';
const React = window.React;
@@ -18,7 +17,6 @@ export default function FragmentRefsPage() {
<ResizeObserverCase />
<FocusCase />
<GetClientRectsCase />
<ScrollIntoViewCase />
</FixtureSet>
);
}

View File

@@ -2,23 +2,14 @@ import './polyfills';
import loadReact, {isLocal} from './react-loader';
if (isLocal()) {
Promise.all([
import('react'),
import('react-dom'),
import('react-dom/client'),
])
.then(([React, ReactDOM, ReactDOMClient]) => {
if (
React === undefined ||
ReactDOM === undefined ||
ReactDOMClient === undefined
) {
Promise.all([import('react'), import('react-dom/client')])
.then(([React, ReactDOMClient]) => {
if (React === undefined || ReactDOMClient === undefined) {
throw new Error(
'Unable to load React. Build experimental and then run `yarn dev` again'
);
}
window.React = React;
window.ReactDOM = ReactDOM;
window.ReactDOMClient = ReactDOMClient;
})
.then(() => import('./components/App'))

View File

@@ -15,7 +15,6 @@ const TerserPlugin = require('terser-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin');
const DevToolsIgnorePlugin = require('devtools-ignore-webpack-plugin');
const getCSSModuleLocalIdent = require('react-dev-utils/getCSSModuleLocalIdent');
const paths = require('./paths');
const modules = require('./modules');
@@ -686,15 +685,6 @@ module.exports = function (webpackEnv) {
},
}),
// Fork Start
new DevToolsIgnorePlugin({
shouldIgnorePath: function (path) {
return (
path.includes('/node_modules/') ||
path.includes('/webpack/') ||
path.endsWith('/src/index.js')
);
},
}),
new ReactFlightWebpackPlugin({
isServer: false,
clientReferences: {

View File

@@ -29,7 +29,6 @@
"concurrently": "^7.3.0",
"css-loader": "^6.5.1",
"css-minimizer-webpack-plugin": "^3.2.0",
"devtools-ignore-webpack-plugin": "^0.2.0",
"dotenv": "^10.0.0",
"dotenv-expand": "^5.1.0",
"file-loader": "^6.2.0",

View File

@@ -58,8 +58,7 @@ function filterStackFrame(sourceURL, functionName) {
sourceURL !== '' &&
!sourceURL.startsWith('node:') &&
!sourceURL.includes('node_modules') &&
!sourceURL.endsWith('library.js') &&
!sourceURL.includes('/server/region.js')
!sourceURL.endsWith('library.js')
);
}
@@ -74,7 +73,13 @@ function getDebugChannel(req) {
return activeDebugChannels.get(requestId);
}
async function renderApp(res, returnValue, formState, noCache, debugChannel) {
async function renderApp(
res,
returnValue,
formState,
noCache,
promiseForDebugChannel
) {
const {renderToPipeableStream} = await import(
'react-server-dom-webpack/server'
);
@@ -126,7 +131,7 @@ async function renderApp(res, returnValue, formState, noCache, debugChannel) {
// For client-invoked server actions we refresh the tree and return a return value.
const payload = {root, returnValue, formState};
const {pipe} = renderToPipeableStream(payload, moduleMap, {
debugChannel,
debugChannel: await promiseForDebugChannel,
filterStackFrame,
});
pipe(res);
@@ -379,20 +384,23 @@ app.on('error', function (error) {
if (process.env.NODE_ENV === 'development') {
// Open a websocket server for Debug information
const WebSocket = require('ws');
const webSocketServer = new WebSocket.Server({noServer: true});
const webSocketServer = new WebSocket.Server({
server: httpServer,
path: '/debug-channel',
});
webSocketServer.on('connection', (ws, req) => {
const url = new URL(req.url, `http://${req.headers.host}`);
const requestId = url.searchParams.get('id');
activeDebugChannels.set(requestId, ws);
ws.on('close', (code, reason) => {
activeDebugChannels.delete(requestId);
});
httpServer.on('upgrade', (request, socket, head) => {
const DEBUG_CHANNEL_PATH = '/debug-channel?';
if (request.url.startsWith(DEBUG_CHANNEL_PATH)) {
const requestId = request.url.slice(DEBUG_CHANNEL_PATH.length);
const promiseForWs = new Promise(resolve => {
webSocketServer.handleUpgrade(request, socket, head, ws => {
ws.on('close', () => {
activeDebugChannels.delete(requestId);
});
resolve(ws);
});
});
activeDebugChannels.set(requestId, promiseForWs);
} else {
socket.destroy();
}
});
}

View File

@@ -14,52 +14,18 @@ function findSourceMapURL(fileName) {
);
}
async function createWebSocketStream(url) {
const ws = new WebSocket(url);
ws.binaryType = 'arraybuffer';
await new Promise((resolve, reject) => {
ws.addEventListener('open', resolve, {once: true});
ws.addEventListener('error', reject, {once: true});
});
const writable = new WritableStream({
write(chunk) {
ws.send(chunk);
},
close() {
ws.close();
},
abort(reason) {
ws.close(1000, reason && String(reason));
},
});
const readable = new ReadableStream({
start(controller) {
ws.addEventListener('message', event => {
controller.enqueue(event.data);
});
ws.addEventListener('close', () => {
controller.close();
});
ws.addEventListener('error', err => {
controller.error(err);
});
},
});
return {readable, writable};
}
let updateRoot;
async function callServer(id, args) {
let response;
if (process.env.NODE_ENV === 'development') {
if (
process.env.NODE_ENV === 'development' &&
typeof WebSocketStream === 'function'
) {
const requestId = crypto.randomUUID();
const debugChannel = await createWebSocketStream(
`ws://localhost:3001/debug-channel?id=${requestId}`
const wss = new WebSocketStream(
'ws://localhost:3001/debug-channel?' + requestId
);
const debugChannel = await wss.opened;
response = createFromFetch(
fetch('/', {
method: 'POST',
@@ -108,11 +74,15 @@ function Shell({data}) {
async function hydrateApp() {
let response;
if (process.env.NODE_ENV === 'development') {
if (
process.env.NODE_ENV === 'development' &&
typeof WebSocketStream === 'function'
) {
const requestId = crypto.randomUUID();
const debugChannel = await createWebSocketStream(
`ws://localhost:3001/debug-channel?id=${requestId}`
const wss = new WebSocketStream(
'ws://localhost:3001/debug-channel?' + requestId
);
const debugChannel = await wss.opened;
response = createFromFetch(
fetch('/', {
headers: {

View File

@@ -4614,11 +4614,6 @@ detect-port-alt@^1.1.6:
address "^1.0.1"
debug "^2.6.0"
devtools-ignore-webpack-plugin@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/devtools-ignore-webpack-plugin/-/devtools-ignore-webpack-plugin-0.2.0.tgz#a7b3d1bd0f593c7fee5cbb7534b07860e5e2447c"
integrity sha512-4P+1Y1VhSt1MRBRF6my8N1bs9nNMOFfIFSBHI6u18W73iCHWXNHTSWYeMoQQ72PIIHrP1q4koKpYg1Em3jb9Rw==
didyoumean@^1.2.2:
version "1.2.2"
resolved "https://registry.yarnpkg.com/didyoumean/-/didyoumean-1.2.2.tgz#989346ffe9e839b4555ecf5666edea0d3e8ad037"
@@ -8655,7 +8650,16 @@ string-length@^5.0.1:
char-regex "^2.0.0"
strip-ansi "^7.0.1"
"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
"string-width-cjs@npm:string-width@^4.2.0":
version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
dependencies:
emoji-regex "^8.0.0"
is-fullwidth-code-point "^3.0.0"
strip-ansi "^6.0.1"
string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
@@ -8726,7 +8730,14 @@ string_decoder@^1.1.1:
dependencies:
safe-buffer "~5.2.0"
"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1:
"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
dependencies:
ansi-regex "^5.0.1"
strip-ansi@^6.0.0, strip-ansi@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
@@ -9441,7 +9452,16 @@ wordwrap@~1.0.0:
resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb"
integrity sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0:
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0":
version "7.0.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
dependencies:
ansi-styles "^4.0.0"
string-width "^4.1.0"
strip-ansi "^6.0.0"
wrap-ansi@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==

View File

@@ -1,20 +0,0 @@
{
"env": [
"bom",
"cssom",
"dom",
"geometry",
"html",
"node",
"serviceworkers",
"streams",
"web-animations"
],
"ignore": [
"create-react-class",
"jest",
"regenerator-runtime",
"webpack",
"ws"
]
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,414 +0,0 @@
// flow-typed signature: ad7b684aa8897ecb82bcc3e009b9fc30
// flow-typed version: 3e51657e95/cssom/flow_>=v0.261.x
declare class StyleSheet {
disabled: boolean;
+href: string;
+media: MediaList;
+ownerNode: Node;
+parentStyleSheet: ?StyleSheet;
+title: string;
+type: string;
}
declare class StyleSheetList {
@@iterator(): Iterator<StyleSheet>;
length: number;
[index: number]: StyleSheet;
}
declare class MediaList {
@@iterator(): Iterator<string>;
mediaText: string;
length: number;
item(index: number): ?string;
deleteMedium(oldMedium: string): void;
appendMedium(newMedium: string): void;
[index: number]: string;
}
declare class CSSStyleSheet extends StyleSheet {
+cssRules: CSSRuleList;
+ownerRule: ?CSSRule;
deleteRule(index: number): void;
insertRule(rule: string, index: number): number;
replace(text: string): Promise<CSSStyleSheet>;
replaceSync(text: string): void;
}
declare class CSSGroupingRule extends CSSRule {
+cssRules: CSSRuleList;
deleteRule(index: number): void;
insertRule(rule: string, index: number): number;
}
declare class CSSConditionRule extends CSSGroupingRule {
conditionText: string;
}
declare class CSSMediaRule extends CSSConditionRule {
+media: MediaList;
}
declare class CSSStyleRule extends CSSRule {
selectorText: string;
+style: CSSStyleDeclaration;
}
declare class CSSSupportsRule extends CSSConditionRule {}
declare class CSSRule {
cssText: string;
+parentRule: ?CSSRule;
+parentStyleSheet: ?CSSStyleSheet;
+type: number;
static STYLE_RULE: number;
static MEDIA_RULE: number;
static FONT_FACE_RULE: number;
static PAGE_RULE: number;
static IMPORT_RULE: number;
static CHARSET_RULE: number;
static UNKNOWN_RULE: number;
static KEYFRAMES_RULE: number;
static KEYFRAME_RULE: number;
static NAMESPACE_RULE: number;
static COUNTER_STYLE_RULE: number;
static SUPPORTS_RULE: number;
static DOCUMENT_RULE: number;
static FONT_FEATURE_VALUES_RULE: number;
static VIEWPORT_RULE: number;
static REGION_STYLE_RULE: number;
}
declare class CSSKeyframeRule extends CSSRule {
keyText: string;
+style: CSSStyleDeclaration;
}
declare class CSSKeyframesRule extends CSSRule {
name: string;
+cssRules: CSSRuleList;
appendRule(rule: string): void;
deleteRule(select: string): void;
findRule(select: string): CSSKeyframeRule | null;
}
declare class CSSRuleList {
@@iterator(): Iterator<CSSRule>;
length: number;
item(index: number): ?CSSRule;
[index: number]: CSSRule;
}
declare class CSSStyleDeclaration {
@@iterator(): Iterator<string>;
/* DOM CSS Properties */
alignContent: string;
alignItems: string;
alignSelf: string;
all: string;
animation: string;
animationDelay: string;
animationDirection: string;
animationDuration: string;
animationFillMode: string;
animationIterationCount: string;
animationName: string;
animationPlayState: string;
animationTimingFunction: string;
backdropFilter: string;
webkitBackdropFilter: string;
backfaceVisibility: string;
background: string;
backgroundAttachment: string;
backgroundBlendMode: string;
backgroundClip: string;
backgroundColor: string;
backgroundImage: string;
backgroundOrigin: string;
backgroundPosition: string;
backgroundPositionX: string;
backgroundPositionY: string;
backgroundRepeat: string;
backgroundSize: string;
blockSize: string;
border: string;
borderBlockEnd: string;
borderBlockEndColor: string;
borderBlockEndStyle: string;
borderBlockEndWidth: string;
borderBlockStart: string;
borderBlockStartColor: string;
borderBlockStartStyle: string;
borderBlockStartWidth: string;
borderBottom: string;
borderBottomColor: string;
borderBottomLeftRadius: string;
borderBottomRightRadius: string;
borderBottomStyle: string;
borderBottomWidth: string;
borderCollapse: string;
borderColor: string;
borderImage: string;
borderImageOutset: string;
borderImageRepeat: string;
borderImageSlice: string;
borderImageSource: string;
borderImageWidth: string;
borderInlineEnd: string;
borderInlineEndColor: string;
borderInlineEndStyle: string;
borderInlineEndWidth: string;
borderInlineStart: string;
borderInlineStartColor: string;
borderInlineStartStyle: string;
borderInlineStartWidth: string;
borderLeft: string;
borderLeftColor: string;
borderLeftStyle: string;
borderLeftWidth: string;
borderRadius: string;
borderRight: string;
borderRightColor: string;
borderRightStyle: string;
borderRightWidth: string;
borderSpacing: string;
borderStyle: string;
borderTop: string;
borderTopColor: string;
borderTopLeftRadius: string;
borderTopRightRadius: string;
borderTopStyle: string;
borderTopWidth: string;
borderWidth: string;
bottom: string;
boxDecorationBreak: string;
boxShadow: string;
boxSizing: string;
breakAfter: string;
breakBefore: string;
breakInside: string;
captionSide: string;
clear: string;
clip: string;
clipPath: string;
color: string;
columns: string;
columnCount: string;
columnFill: string;
columnGap: string;
columnRule: string;
columnRuleColor: string;
columnRuleStyle: string;
columnRuleWidth: string;
columnSpan: string;
columnWidth: string;
contain: string;
content: string;
counterIncrement: string;
counterReset: string;
cursor: string;
direction: string;
display: string;
emptyCells: string;
filter: string;
flex: string;
flexBasis: string;
flexDirection: string;
flexFlow: string;
flexGrow: string;
flexShrink: string;
flexWrap: string;
float: string;
font: string;
fontFamily: string;
fontFeatureSettings: string;
fontKerning: string;
fontLanguageOverride: string;
fontSize: string;
fontSizeAdjust: string;
fontStretch: string;
fontStyle: string;
fontSynthesis: string;
fontVariant: string;
fontVariantAlternates: string;
fontVariantCaps: string;
fontVariantEastAsian: string;
fontVariantLigatures: string;
fontVariantNumeric: string;
fontVariantPosition: string;
fontWeight: string;
grad: string;
grid: string;
gridArea: string;
gridAutoColumns: string;
gridAutoFlow: string;
gridAutoPosition: string;
gridAutoRows: string;
gridColumn: string;
gridColumnStart: string;
gridColumnEnd: string;
gridRow: string;
gridRowStart: string;
gridRowEnd: string;
gridTemplate: string;
gridTemplateAreas: string;
gridTemplateRows: string;
gridTemplateColumns: string;
height: string;
hyphens: string;
imageRendering: string;
imageResolution: string;
imageOrientation: string;
imeMode: string;
inherit: string;
initial: string;
inlineSize: string;
isolation: string;
justifyContent: string;
left: string;
letterSpacing: string;
lineBreak: string;
lineHeight: string;
listStyle: string;
listStyleImage: string;
listStylePosition: string;
listStyleType: string;
margin: string;
marginBlockEnd: string;
marginBlockStart: string;
marginBottom: string;
marginInlineEnd: string;
marginInlineStart: string;
marginLeft: string;
marginRight: string;
marginTop: string;
marks: string;
mask: string;
maskType: string;
maxBlockSize: string;
maxHeight: string;
maxInlineSize: string;
maxWidth: string;
minBlockSize: string;
minHeight: string;
minInlineSize: string;
minWidth: string;
mixBlendMode: string;
mozTransform: string;
mozTransformOrigin: string;
mozTransitionDelay: string;
mozTransitionDuration: string;
mozTransitionProperty: string;
mozTransitionTimingFunction: string;
objectFit: string;
objectPosition: string;
offsetBlockEnd: string;
offsetBlockStart: string;
offsetInlineEnd: string;
offsetInlineStart: string;
opacity: string;
order: string;
orphans: string;
outline: string;
outlineColor: string;
outlineOffset: string;
outlineStyle: string;
outlineWidth: string;
overflow: string;
overflowWrap: string;
overflowX: string;
overflowY: string;
padding: string;
paddingBlockEnd: string;
paddingBlockStart: string;
paddingBottom: string;
paddingInlineEnd: string;
paddingInlineStart: string;
paddingLeft: string;
paddingRight: string;
paddingTop: string;
pageBreakAfter: string;
pageBreakBefore: string;
pageBreakInside: string;
perspective: string;
perspectiveOrigin: string;
pointerEvents: string;
position: string;
quotes: string;
rad: string;
resize: string;
right: string;
rubyAlign: string;
rubyMerge: string;
rubyPosition: string;
scrollBehavior: string;
scrollSnapCoordinate: string;
scrollSnapDestination: string;
scrollSnapPointsX: string;
scrollSnapPointsY: string;
scrollSnapType: string;
shapeImageThreshold: string;
shapeMargin: string;
shapeOutside: string;
tableLayout: string;
tabSize: string;
textAlign: string;
textAlignLast: string;
textCombineUpright: string;
textDecoration: string;
textDecorationColor: string;
textDecorationLine: string;
textDecorationStyle: string;
textIndent: string;
textOrientation: string;
textOverflow: string;
textRendering: string;
textShadow: string;
textTransform: string;
textUnderlinePosition: string;
top: string;
touchAction: string;
transform: string;
transformOrigin: string;
transformStyle: string;
transition: string;
transitionDelay: string;
transitionDuration: string;
transitionProperty: string;
transitionTimingFunction: string;
turn: string;
unicodeBidi: string;
unicodeRange: string;
userSelect: string;
verticalAlign: string;
visibility: string;
webkitOverflowScrolling: string;
webkitTransform: string;
webkitTransformOrigin: string;
webkitTransitionDelay: string;
webkitTransitionDuration: string;
webkitTransitionProperty: string;
webkitTransitionTimingFunction: string;
whiteSpace: string;
widows: string;
width: string;
willChange: string;
wordBreak: string;
wordSpacing: string;
wordWrap: string;
writingMode: string;
zIndex: string;
cssFloat: string;
cssText: string;
getPropertyPriority(property: string): string;
getPropertyValue(property: string): string;
item(index: number): string;
[index: number]: string;
length: number;
parentRule: CSSRule;
removeProperty(property: string): string;
setProperty(property: string, value: ?string, priority: ?string): void;
setPropertyPriority(property: string, priority: string): void;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,270 +0,0 @@
// flow-typed signature: c29a716c1825927cdfc3ad29fe929754
// flow-typed version: 52ab99c6db/geometry/flow_>=v0.261.x
// https://www.w3.org/TR/geometry-1/
type DOMMatrix2DInit =
| {|
a: number,
b: number,
c: number,
d: number,
e: number,
f: number,
|}
| {|
m11: number,
m12: number,
m21: number,
m22: number,
m41: number,
m42: number,
|};
type DOMMatrixInit =
| {|
...DOMMatrix2DInit,
is2D: true,
|}
| {|
...DOMMatrix2DInit,
is2D: false,
m13: number,
m14: number,
m23: number,
m24: number,
m31: number,
m32: number,
m33: number,
m34: number,
m43: number,
m44: number,
|};
type DOMPointInit = {|
w: number,
x: number,
y: number,
z: number,
|};
type DOMQuadInit = {|
p1: DOMPointInit,
p2: DOMPointInit,
p3: DOMPointInit,
p4: DOMPointInit,
|};
type DOMRectInit = {|
height: number,
width: number,
x: number,
y: number,
|};
declare class DOMMatrix extends DOMMatrixReadOnly {
a: number;
b: number;
c: number;
d: number;
e: number;
f: number;
m11: number;
m12: number;
m13: number;
m14: number;
m21: number;
m22: number;
m23: number;
m24: number;
m31: number;
m32: number;
m33: number;
m34: number;
m41: number;
m42: number;
m43: number;
m44: number;
static fromFloat32Array(array32: Float32Array): DOMMatrix;
static fromFloat64Array(array64: Float64Array): DOMMatrix;
static fromMatrix(other?: DOMMatrixInit): DOMMatrix;
constructor(init?: string | Array<number>): void;
invertSelf(): DOMMatrix;
multiplySelf(other?: DOMMatrixInit): DOMMatrix;
preMultiplySelf(other?: DOMMatrixInit): DOMMatrix;
rotateAxisAngleSelf(
x?: number,
y?: number,
z?: number,
angle?: number
): DOMMatrix;
rotateFromVectorSelf(x?: number, y?: number): DOMMatrix;
rotateSelf(rotX?: number, rotY?: number, rotZ?: number): DOMMatrix;
scale3dSelf(
scale?: number,
originX?: number,
originY?: number,
originZ?: number
): DOMMatrix;
scaleSelf(
scaleX?: number,
scaleY?: number,
scaleZ?: number,
originX?: number,
originY?: number,
originZ?: number
): DOMMatrix;
setMatrixValue(transformList: string): DOMMatrix;
skewXSelf(sx?: number): DOMMatrix;
skewYSelf(sy?: number): DOMMatrix;
translateSelf(tx?: number, ty?: number, tz?: number): DOMMatrix;
}
declare class DOMMatrixReadOnly {
+a: number;
+b: number;
+c: number;
+d: number;
+e: number;
+f: number;
+is2D: boolean;
+isIdentity: boolean;
+m11: number;
+m12: number;
+m13: number;
+m14: number;
+m21: number;
+m22: number;
+m23: number;
+m24: number;
+m31: number;
+m32: number;
+m33: number;
+m34: number;
+m41: number;
+m42: number;
+m43: number;
+m44: number;
static fromFloat32Array(array32: Float32Array): DOMMatrixReadOnly;
static fromFloat64Array(array64: Float64Array): DOMMatrixReadOnly;
static fromMatrix(other?: DOMMatrixInit): DOMMatrixReadOnly;
constructor(init?: string | Array<number>): void;
flipX(): DOMMatrix;
flipY(): DOMMatrix;
inverse(): DOMMatrix;
multiply(other?: DOMMatrixInit): DOMMatrix;
rotate(rotX?: number, rotY?: number, rotZ?: number): DOMMatrix;
rotateAxisAngle(
x?: number,
y?: number,
z?: number,
angle?: number
): DOMMatrix;
rotateFromVector(x?: number, y?: number): DOMMatrix;
scale(
scaleX?: number,
scaleY?: number,
scaleZ?: number,
originX?: number,
originY?: number,
originZ?: number
): DOMMatrix;
scale3d(
scale?: number,
originX?: number,
originY?: number,
originZ?: number
): DOMMatrix;
scaleNonUniform(scaleX?: number, scaleY?: number): DOMMatrix;
skewX(sx?: number): DOMMatrix;
skewY(sy?: number): DOMMatrix;
toFloat32Array(): Float32Array;
toFloat64Array(): Float64Array;
toJSON(): Object;
transformPoint(point?: DOMPointInit): DOMPoint;
translate(tx?: number, ty?: number, tz?: number): DOMMatrix;
toString(): string;
}
declare class DOMPoint extends DOMPointReadOnly {
w: number;
x: number;
y: number;
z: number;
static fromPoint(other?: DOMPointInit): DOMPoint;
constructor(x?: number, y?: number, z?: number, w?: number): void;
}
declare class DOMPointReadOnly {
+w: number;
+x: number;
+y: number;
+z: number;
static fromPoint(other?: DOMPointInit): DOMPointReadOnly;
constructor(x?: number, y?: number, z?: number, w?: number): void;
matrixTransform(matrix?: DOMMatrixInit): DOMPoint;
toJSON(): Object;
}
declare class DOMQuad {
+p1: DOMPoint;
+p2: DOMPoint;
+p3: DOMPoint;
+p4: DOMPoint;
static fromQuad(other?: DOMQuadInit): DOMQuad;
static fromRect(other?: DOMRectInit): DOMQuad;
constructor(
p1?: DOMPointInit,
p2?: DOMPointInit,
p3?: DOMPointInit,
p4?: DOMPointInit
): void;
getBounds(): DOMRect;
toJSON(): Object;
}
declare class DOMRect extends DOMRectReadOnly {
height: number;
width: number;
x: number;
y: number;
constructor(x?: number, y?: number, width?: number, height?: number): void;
static fromRect(other?: DOMRectInit): DOMRect;
}
declare class DOMRectList {
+length: number;
@@iterator(): Iterator<DOMRect>;
item(index: number): DOMRect;
[index: number]: DOMRect;
}
declare class DOMRectReadOnly {
+bottom: number;
+height: number;
+left: number;
+right: number;
+top: number;
+width: number;
+x: number;
+y: number;
constructor(x?: number, y?: number, width?: number, height?: number): void;
static fromRect(other?: DOMRectInit): DOMRectReadOnly;
toJSON(): Object;
}

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More