Compare commits
33 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bb9505c980 | ||
|
|
c5362a380f | ||
|
|
89a803fcec | ||
|
|
8d7b5e4903 | ||
|
|
3434ff4f4b | ||
|
|
bd5b1b7639 | ||
|
|
0a1f1fcd50 | ||
|
|
b870042915 | ||
|
|
33a1095d72 | ||
|
|
213594860f | ||
|
|
9c2e2b8475 | ||
|
|
4123f6b771 | ||
|
|
cb1e73be04 | ||
|
|
cacc20e37c | ||
|
|
bb7c9c1b8a | ||
|
|
44f8451ede | ||
|
|
ad4ecb6e6e | ||
|
|
26e87b5f15 | ||
|
|
75dc0026d6 | ||
|
|
df10309e2b | ||
|
|
e42f3d30ca | ||
|
|
67e743fba5 | ||
|
|
9eede45646 | ||
|
|
090777d78a | ||
|
|
4049cfeeab | ||
|
|
e67e3bed92 | ||
|
|
06cfa99f37 | ||
|
|
05addfc663 | ||
|
|
d260b0d8b8 | ||
|
|
425ba0ad6d | ||
|
|
6de32a5a07 | ||
|
|
698bb4deb7 | ||
|
|
11d7bcf88c |
@@ -28,3 +28,6 @@ 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/
|
||||
|
||||
10
.eslintrc.js
10
.eslintrc.js
@@ -547,12 +547,10 @@ module.exports = {
|
||||
},
|
||||
|
||||
globals: {
|
||||
$ElementType: 'readonly',
|
||||
$Flow$ModuleRef: 'readonly',
|
||||
$FlowFixMe: 'readonly',
|
||||
$Keys: 'readonly',
|
||||
$NonMaybeType: 'readonly',
|
||||
$PropertyType: 'readonly',
|
||||
$ReadOnly: 'readonly',
|
||||
$ReadOnlyArray: 'readonly',
|
||||
$ArrayBufferView: 'readonly',
|
||||
@@ -567,6 +565,7 @@ module.exports = {
|
||||
BigInt: 'readonly',
|
||||
BigInt64Array: 'readonly',
|
||||
BigUint64Array: 'readonly',
|
||||
CacheType: 'readonly',
|
||||
Class: 'readonly',
|
||||
ClientRect: 'readonly',
|
||||
CopyInspectedElementPath: 'readonly',
|
||||
@@ -581,13 +580,15 @@ module.exports = {
|
||||
IteratorResult: 'readonly',
|
||||
JSONValue: 'readonly',
|
||||
JSResourceReference: 'readonly',
|
||||
mixin$Animatable: 'readonly',
|
||||
MouseEventHandler: 'readonly',
|
||||
NavigateEvent: 'readonly',
|
||||
PerformanceMeasureOptions: 'readonly',
|
||||
PropagationPhases: 'readonly',
|
||||
PropertyDescriptor: 'readonly',
|
||||
React$AbstractComponent: 'readonly',
|
||||
PropertyDescriptorMap: 'readonly',
|
||||
Proxy$traps: 'readonly',
|
||||
React$Component: 'readonly',
|
||||
React$ComponentType: 'readonly',
|
||||
React$Config: 'readonly',
|
||||
React$Context: 'readonly',
|
||||
React$Element: 'readonly',
|
||||
@@ -619,7 +620,6 @@ module.exports = {
|
||||
PropertyIndexedKeyframes: 'readonly',
|
||||
KeyframeAnimationOptions: 'readonly',
|
||||
GetAnimationsOptions: 'readonly',
|
||||
Animatable: 'readonly',
|
||||
ScrollTimeline: 'readonly',
|
||||
EventListenerOptionsOrUseCapture: 'readonly',
|
||||
FocusOptions: 'readonly',
|
||||
|
||||
2
.github/workflows/compiler_playground.yml
vendored
2
.github/workflows/compiler_playground.yml
vendored
@@ -57,8 +57,6 @@ 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()'
|
||||
|
||||
17
.github/workflows/runtime_build_and_test.yml
vendored
17
.github/workflows/runtime_build_and_test.yml
vendored
@@ -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,9 +811,18 @@ jobs:
|
||||
pattern: _build_*
|
||||
path: build
|
||||
merge-multiple: true
|
||||
- run: |
|
||||
npx playwright install
|
||||
sudo npx playwright install-deps
|
||||
- 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: ./scripts/ci/run_devtools_e2e_tests.js
|
||||
env:
|
||||
RELEASE_CHANNEL: experimental
|
||||
|
||||
103
compiler/apps/playground/components/Editor/ConfigEditor.tsx
Normal file
103
compiler/apps/playground/components/Editor/ConfigEditor.tsx
Normal file
@@ -0,0 +1,103 @@
|
||||
/**
|
||||
* 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>
|
||||
);
|
||||
}
|
||||
@@ -37,6 +37,7 @@ import {
|
||||
type Store,
|
||||
} from '../../lib/stores';
|
||||
import {useStore, useStoreDispatch} from '../StoreContext';
|
||||
import ConfigEditor from './ConfigEditor';
|
||||
import Input from './Input';
|
||||
import {
|
||||
CompilerOutput,
|
||||
@@ -46,6 +47,7 @@ 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,
|
||||
@@ -291,7 +293,13 @@ 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();
|
||||
@@ -328,6 +336,7 @@ 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>
|
||||
|
||||
@@ -36,6 +36,14 @@ 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.
|
||||
*/
|
||||
@@ -458,7 +466,8 @@ export class CompilerError extends Error {
|
||||
case ErrorSeverity.InvalidJS:
|
||||
case ErrorSeverity.InvalidReact:
|
||||
case ErrorSeverity.InvalidConfig:
|
||||
case ErrorSeverity.UnsupportedJS: {
|
||||
case ErrorSeverity.UnsupportedJS:
|
||||
case ErrorSeverity.IncompatibleLibrary: {
|
||||
return true;
|
||||
}
|
||||
case ErrorSeverity.CannotPreserveMemoization:
|
||||
@@ -506,8 +515,9 @@ function printErrorSummary(severity: ErrorSeverity, message: string): string {
|
||||
severityCategory = 'Error';
|
||||
break;
|
||||
}
|
||||
case ErrorSeverity.IncompatibleLibrary:
|
||||
case ErrorSeverity.CannotPreserveMemoization: {
|
||||
severityCategory = 'Memoization';
|
||||
severityCategory = 'Compilation Skipped';
|
||||
break;
|
||||
}
|
||||
case ErrorSeverity.Invariant: {
|
||||
@@ -541,9 +551,15 @@ 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',
|
||||
|
||||
@@ -703,6 +719,16 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
|
||||
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',
|
||||
recommended: true,
|
||||
};
|
||||
}
|
||||
case ErrorCategory.FBT: {
|
||||
return {
|
||||
category,
|
||||
@@ -857,6 +883,15 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
|
||||
recommended: true,
|
||||
};
|
||||
}
|
||||
case ErrorCategory.IncompatibleLibrary: {
|
||||
return {
|
||||
category,
|
||||
name: 'incompatible-library',
|
||||
description:
|
||||
'Validates against usage of libraries which are incompatible with memoization (manual or automatic)',
|
||||
recommended: true,
|
||||
};
|
||||
}
|
||||
default: {
|
||||
assertExhaustive(category, `Unsupported category ${category}`);
|
||||
}
|
||||
|
||||
@@ -494,7 +494,20 @@ 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;
|
||||
}
|
||||
@@ -839,6 +852,73 @@ 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,
|
||||
@@ -877,11 +957,6 @@ 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: {
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
@@ -50,6 +50,7 @@ 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([
|
||||
@@ -650,6 +651,13 @@ 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>;
|
||||
@@ -853,10 +861,16 @@ export class Environment {
|
||||
#resolveModuleType(moduleName: string, loc: SourceLocation): Global | null {
|
||||
let moduleType = this.#moduleTypes.get(moduleName);
|
||||
if (moduleType === undefined) {
|
||||
if (this.config.moduleTypeProvider == null) {
|
||||
/*
|
||||
* 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) {
|
||||
return null;
|
||||
}
|
||||
const unparsedModuleConfig = this.config.moduleTypeProvider(moduleName);
|
||||
const unparsedModuleConfig = moduleTypeProvider(moduleName);
|
||||
if (unparsedModuleConfig != null) {
|
||||
const parsedModuleConfig = TypeSchema.safeParse(unparsedModuleConfig);
|
||||
if (!parsedModuleConfig.success) {
|
||||
|
||||
@@ -1001,6 +1001,7 @@ export function installTypeConfig(
|
||||
mutableOnlyIfOperandsAreMutable:
|
||||
typeConfig.mutableOnlyIfOperandsAreMutable === true,
|
||||
aliasing: typeConfig.aliasing,
|
||||
knownIncompatible: typeConfig.knownIncompatible ?? null,
|
||||
});
|
||||
}
|
||||
case 'hook': {
|
||||
@@ -1019,6 +1020,7 @@ export function installTypeConfig(
|
||||
returnValueKind: typeConfig.returnValueKind ?? ValueKind.Frozen,
|
||||
noAlias: typeConfig.noAlias === true,
|
||||
aliasing: typeConfig.aliasing,
|
||||
knownIncompatible: typeConfig.knownIncompatible ?? null,
|
||||
});
|
||||
}
|
||||
case 'object': {
|
||||
|
||||
@@ -323,6 +323,22 @@ 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;
|
||||
|
||||
@@ -332,6 +332,7 @@ export type FunctionSignature = {
|
||||
mutableOnlyIfOperandsAreMutable?: boolean;
|
||||
|
||||
impure?: boolean;
|
||||
knownIncompatible?: string | null | undefined;
|
||||
|
||||
canonicalName?: string;
|
||||
|
||||
|
||||
@@ -880,7 +880,8 @@ 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) {
|
||||
return `:T${type.kind}<${type.shapeId}>`;
|
||||
const returnType = printType(type.return);
|
||||
return `:T${type.kind}<${type.shapeId}>()${returnType !== '' ? `: ${returnType}` : ''}`;
|
||||
} else {
|
||||
return `:T${type.kind}`;
|
||||
}
|
||||
@@ -983,7 +984,7 @@ export function printAliasingEffect(effect: AliasingEffect): string {
|
||||
case 'MutateConditionally':
|
||||
case 'MutateTransitive':
|
||||
case 'MutateTransitiveConditionally': {
|
||||
return `${effect.kind} ${printPlaceForAliasEffect(effect.value)}`;
|
||||
return `${effect.kind} ${printPlaceForAliasEffect(effect.value)}${effect.kind === 'Mutate' && effect.reason?.kind === 'AssignCurrentProperty' ? ' (assign `.current`)' : ''}`;
|
||||
}
|
||||
case 'MutateFrozen': {
|
||||
return `MutateFrozen ${printPlaceForAliasEffect(effect.place)} reason=${JSON.stringify(effect.error.reason)}`;
|
||||
|
||||
@@ -251,6 +251,7 @@ 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'),
|
||||
@@ -264,6 +265,7 @@ 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 = {
|
||||
@@ -274,6 +276,7 @@ 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'),
|
||||
@@ -283,6 +286,7 @@ 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 =
|
||||
|
||||
@@ -27,6 +27,7 @@ import {
|
||||
InstructionKind,
|
||||
InstructionValue,
|
||||
isArrayType,
|
||||
isJsxType,
|
||||
isMapType,
|
||||
isPrimitiveType,
|
||||
isRefOrRefValue,
|
||||
@@ -1871,6 +1872,23 @@ 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;
|
||||
}
|
||||
@@ -2152,6 +2170,27 @@ 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 {
|
||||
|
||||
@@ -27,7 +27,7 @@ import {
|
||||
} from '../HIR/visitors';
|
||||
import {assertExhaustive, getOrInsertWith} from '../Utils/utils';
|
||||
import {Err, Ok, Result} from '../Utils/Result';
|
||||
import {AliasingEffect} from './AliasingEffects';
|
||||
import {AliasingEffect, MutationReason} from './AliasingEffects';
|
||||
|
||||
/**
|
||||
* This pass builds an abstract model of the heap and interprets the effects of the
|
||||
@@ -101,6 +101,7 @@ export function inferMutationAliasingRanges(
|
||||
transitive: boolean;
|
||||
kind: MutationKind;
|
||||
place: Place;
|
||||
reason: MutationReason | null;
|
||||
}> = [];
|
||||
const renders: Array<{index: number; place: Place}> = [];
|
||||
|
||||
@@ -176,6 +177,7 @@ export function inferMutationAliasingRanges(
|
||||
effect.kind === 'MutateTransitive'
|
||||
? MutationKind.Definite
|
||||
: MutationKind.Conditional,
|
||||
reason: null,
|
||||
place: effect.value,
|
||||
});
|
||||
} else if (
|
||||
@@ -190,6 +192,7 @@ export function inferMutationAliasingRanges(
|
||||
effect.kind === 'Mutate'
|
||||
? MutationKind.Definite
|
||||
: MutationKind.Conditional,
|
||||
reason: effect.kind === 'Mutate' ? (effect.reason ?? null) : null,
|
||||
place: effect.value,
|
||||
});
|
||||
} else if (
|
||||
@@ -241,6 +244,7 @@ export function inferMutationAliasingRanges(
|
||||
mutation.transitive,
|
||||
mutation.kind,
|
||||
mutation.place.loc,
|
||||
mutation.reason,
|
||||
errors,
|
||||
);
|
||||
}
|
||||
@@ -267,6 +271,7 @@ export function inferMutationAliasingRanges(
|
||||
functionEffects.push({
|
||||
kind: 'Mutate',
|
||||
value: {...place, loc: node.local.loc},
|
||||
reason: node.mutationReason,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -507,6 +512,7 @@ export function inferMutationAliasingRanges(
|
||||
true,
|
||||
MutationKind.Conditional,
|
||||
into.loc,
|
||||
null,
|
||||
ignoredErrors,
|
||||
);
|
||||
for (const from of tracked) {
|
||||
@@ -580,6 +586,7 @@ type Node = {
|
||||
transitive: {kind: MutationKind; loc: SourceLocation} | null;
|
||||
local: {kind: MutationKind; loc: SourceLocation} | null;
|
||||
lastMutated: number;
|
||||
mutationReason: MutationReason | null;
|
||||
value:
|
||||
| {kind: 'Object'}
|
||||
| {kind: 'Phi'}
|
||||
@@ -599,6 +606,7 @@ class AliasingState {
|
||||
transitive: null,
|
||||
local: null,
|
||||
lastMutated: 0,
|
||||
mutationReason: null,
|
||||
value,
|
||||
});
|
||||
}
|
||||
@@ -697,6 +705,7 @@ class AliasingState {
|
||||
transitive: boolean,
|
||||
startKind: MutationKind,
|
||||
loc: SourceLocation,
|
||||
reason: MutationReason | null,
|
||||
errors: CompilerError,
|
||||
): void {
|
||||
const seen = new Map<Identifier, MutationKind>();
|
||||
@@ -717,6 +726,7 @@ class AliasingState {
|
||||
if (node == null) {
|
||||
continue;
|
||||
}
|
||||
node.mutationReason ??= reason;
|
||||
node.lastMutated = Math.max(node.lastMutated, index);
|
||||
if (end != null) {
|
||||
node.id.mutableRange.end = makeInstructionId(
|
||||
|
||||
@@ -777,6 +777,15 @@ 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,6 +182,11 @@ export function parseConfigPragmaForTests(
|
||||
environment?: PartialEnvironmentConfig;
|
||||
},
|
||||
): PluginOptions {
|
||||
const overridePragma = parseConfigPragmaAsString(pragma);
|
||||
if (overridePragma !== '') {
|
||||
return parseConfigStringAsJS(overridePragma, defaults);
|
||||
}
|
||||
|
||||
const environment = parseConfigPragmaEnvironmentForTest(
|
||||
pragma,
|
||||
defaults.environment ?? {},
|
||||
@@ -217,3 +222,104 @@ 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);
|
||||
}
|
||||
|
||||
@@ -284,8 +284,7 @@ function validateInferredDep(
|
||||
CompilerDiagnostic.create({
|
||||
category: ErrorCategory.PreserveManualMemo,
|
||||
severity: ErrorSeverity.CannotPreserveMemoization,
|
||||
reason:
|
||||
'Compilation skipped because existing memoization could not be preserved',
|
||||
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. ',
|
||||
@@ -539,8 +538,7 @@ class Visitor extends ReactiveFunctionVisitor<VisitorState> {
|
||||
CompilerDiagnostic.create({
|
||||
category: ErrorCategory.PreserveManualMemo,
|
||||
severity: ErrorSeverity.CannotPreserveMemoization,
|
||||
reason:
|
||||
'Compilation skipped because existing memoization could not be preserved',
|
||||
reason: '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.',
|
||||
@@ -588,8 +586,7 @@ class Visitor extends ReactiveFunctionVisitor<VisitorState> {
|
||||
CompilerDiagnostic.create({
|
||||
category: ErrorCategory.PreserveManualMemo,
|
||||
severity: ErrorSeverity.CannotPreserveMemoization,
|
||||
reason:
|
||||
'Compilation skipped because existing memoization could not be preserved',
|
||||
reason: '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
|
||||
|
||||
@@ -24,9 +24,18 @@ function useThing(fn) {
|
||||
```
|
||||
Found 1 error:
|
||||
|
||||
Error: Expected a non-reserved identifier name
|
||||
Error: `this` is not supported syntax
|
||||
|
||||
`this` is a reserved word in JavaScript and cannot be used as an 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 | }
|
||||
```
|
||||
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
|
||||
## 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".
|
||||
```
|
||||
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
// 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]);
|
||||
}
|
||||
@@ -26,7 +26,7 @@ function Component(props) {
|
||||
```
|
||||
Found 1 error:
|
||||
|
||||
Memoization: Compilation skipped because existing memoization could not be preserved
|
||||
Compilation Skipped: 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.
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ function Component(props) {
|
||||
```
|
||||
Found 1 error:
|
||||
|
||||
Memoization: Compilation skipped because existing memoization could not be preserved
|
||||
Compilation Skipped: 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.
|
||||
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
|
||||
## 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 |
|
||||
```
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
import {knownIncompatible} from 'ReactCompilerKnownIncompatibleTest';
|
||||
|
||||
function Component() {
|
||||
const data = knownIncompatible();
|
||||
return <div>Error</div>;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
|
||||
## 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 |
|
||||
```
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
import {useKnownIncompatibleIndirect} from 'ReactCompilerKnownIncompatibleTest';
|
||||
|
||||
function Component() {
|
||||
const {incompatible} = useKnownIncompatibleIndirect();
|
||||
return <div>{incompatible()}</div>;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
|
||||
## 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 |
|
||||
```
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
import {useKnownIncompatible} from 'ReactCompilerKnownIncompatibleTest';
|
||||
|
||||
function Component() {
|
||||
const data = useKnownIncompatible();
|
||||
return <div>Error</div>;
|
||||
}
|
||||
@@ -38,6 +38,8 @@ 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".
|
||||
```
|
||||
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
|
||||
## 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} />;
|
||||
```
|
||||
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
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} />;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
|
||||
## 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} />;
|
||||
```
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
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} />;
|
||||
}
|
||||
@@ -20,7 +20,7 @@ function Component(props) {
|
||||
```
|
||||
Found 1 error:
|
||||
|
||||
Memoization: Compilation skipped because existing memoization could not be preserved
|
||||
Compilation Skipped: 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.
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ function Component(props) {
|
||||
```
|
||||
Found 1 error:
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
error.invalid-useEffect-dep-not-memoized-bc-range-overlaps-hook.ts:9:2
|
||||
7 |
|
||||
|
||||
@@ -22,7 +22,7 @@ function Component(props) {
|
||||
```
|
||||
Found 1 error:
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
error.invalid-useEffect-dep-not-memoized.ts:6:2
|
||||
4 | function Component(props) {
|
||||
|
||||
@@ -22,7 +22,7 @@ function Component(props) {
|
||||
```
|
||||
Found 1 error:
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
error.invalid-useInsertionEffect-dep-not-memoized.ts:6:2
|
||||
4 | function Component(props) {
|
||||
|
||||
@@ -22,7 +22,7 @@ function Component(props) {
|
||||
```
|
||||
Found 1 error:
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
error.invalid-useLayoutEffect-dep-not-memoized.ts:6:2
|
||||
4 | function Component(props) {
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
|
||||
## 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 | };
|
||||
```
|
||||
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
// @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() {}}],
|
||||
};
|
||||
@@ -0,0 +1,59 @@
|
||||
|
||||
## 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 = () => {
|
||||
```
|
||||
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
// @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}],
|
||||
};
|
||||
@@ -33,7 +33,7 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
```
|
||||
Found 1 error:
|
||||
|
||||
Memoization: Compilation skipped because existing memoization could not be preserved
|
||||
Compilation Skipped: 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.
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
```
|
||||
Found 1 error:
|
||||
|
||||
Memoization: Compilation skipped because existing memoization could not be preserved
|
||||
Compilation Skipped: 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.
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ component Component() {
|
||||
```
|
||||
Found 1 error:
|
||||
|
||||
Memoization: Compilation skipped because existing memoization could not be preserved
|
||||
Compilation Skipped: 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.
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ component Component(id) {
|
||||
```
|
||||
Found 3 errors:
|
||||
|
||||
Memoization: Compilation skipped because existing memoization could not be preserved
|
||||
Compilation Skipped: 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) => {
|
||||
|
||||
Memoization: Compilation skipped because existing memoization could not be preserved
|
||||
Compilation Skipped: 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) {
|
||||
|
||||
Memoization: Compilation skipped because existing memoization could not be preserved
|
||||
Compilation Skipped: 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.
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
```
|
||||
Found 1 error:
|
||||
|
||||
Memoization: Compilation skipped because existing memoization could not be preserved
|
||||
Compilation Skipped: 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.
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
```
|
||||
Found 1 error:
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
error.validate-memoized-effect-deps-invalidated-dep-value.ts:11:2
|
||||
9 | const y = [x];
|
||||
|
||||
@@ -27,7 +27,7 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
```
|
||||
Found 2 errors:
|
||||
|
||||
Memoization: Compilation skipped because existing memoization could not be preserved
|
||||
Compilation Skipped: 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 | });
|
||||
|
||||
Memoization: Compilation skipped because existing memoization could not be preserved
|
||||
Compilation Skipped: 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.
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
```
|
||||
Found 2 errors:
|
||||
|
||||
Memoization: Compilation skipped because existing memoization could not be preserved
|
||||
Compilation Skipped: 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 | });
|
||||
|
||||
Memoization: Compilation skipped because existing memoization could not be preserved
|
||||
Compilation Skipped: 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.
|
||||
|
||||
|
||||
@@ -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":"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"}]}}}
|
||||
{"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"}]}}}
|
||||
```
|
||||
|
||||
### Eval output
|
||||
|
||||
@@ -31,7 +31,7 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
```
|
||||
Found 2 errors:
|
||||
|
||||
Memoization: Compilation skipped because existing memoization could not be preserved
|
||||
Compilation Skipped: 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 |
|
||||
|
||||
Memoization: Compilation skipped because existing memoization could not be preserved
|
||||
Compilation Skipped: 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.
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
```
|
||||
Found 1 error:
|
||||
|
||||
Memoization: Compilation skipped because existing memoization could not be preserved
|
||||
Compilation Skipped: 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.
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
```
|
||||
Found 1 error:
|
||||
|
||||
Memoization: Compilation skipped because existing memoization could not be preserved
|
||||
Compilation Skipped: 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.
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
```
|
||||
Found 1 error:
|
||||
|
||||
Memoization: Compilation skipped because existing memoization could not be preserved
|
||||
Compilation Skipped: 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.
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
```
|
||||
Found 1 error:
|
||||
|
||||
Memoization: Compilation skipped because existing memoization could not be preserved
|
||||
Compilation Skipped: 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.
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
```
|
||||
Found 2 errors:
|
||||
|
||||
Memoization: Compilation skipped because existing memoization could not be preserved
|
||||
Compilation Skipped: 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 = {
|
||||
|
||||
Memoization: Compilation skipped because existing memoization could not be preserved
|
||||
Compilation Skipped: 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.
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
```
|
||||
Found 2 errors:
|
||||
|
||||
Memoization: Compilation skipped because existing memoization could not be preserved
|
||||
Compilation Skipped: 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 |
|
||||
|
||||
Memoization: Compilation skipped because existing memoization could not be preserved
|
||||
Compilation Skipped: 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.
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
```
|
||||
Found 1 error:
|
||||
|
||||
Memoization: Compilation skipped because existing memoization could not be preserved
|
||||
Compilation Skipped: 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.
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
```
|
||||
Found 1 error:
|
||||
|
||||
Memoization: Compilation skipped because existing memoization could not be preserved
|
||||
Compilation Skipped: 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.
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ function useHook(x) {
|
||||
```
|
||||
Found 1 error:
|
||||
|
||||
Memoization: Compilation skipped because existing memoization could not be preserved
|
||||
Compilation Skipped: 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.
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
```
|
||||
Found 1 error:
|
||||
|
||||
Memoization: Compilation skipped because existing memoization could not be preserved
|
||||
Compilation Skipped: 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.
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ function Component({propA, propB}) {
|
||||
```
|
||||
Found 1 error:
|
||||
|
||||
Memoization: Compilation skipped because existing memoization could not be preserved
|
||||
Compilation Skipped: 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.
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ function Component({propA}) {
|
||||
```
|
||||
Found 1 error:
|
||||
|
||||
Memoization: Compilation skipped because existing memoization could not be preserved
|
||||
Compilation Skipped: 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.
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ function useHook(x) {
|
||||
```
|
||||
Found 1 error:
|
||||
|
||||
Memoization: Compilation skipped because existing memoization could not be preserved
|
||||
Compilation Skipped: 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.
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ function Component({propA, propB}) {
|
||||
```
|
||||
Found 1 error:
|
||||
|
||||
Memoization: Compilation skipped because existing memoization could not be preserved
|
||||
Compilation Skipped: 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.
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ function Component({propA, propB}) {
|
||||
```
|
||||
Found 2 errors:
|
||||
|
||||
Memoization: Compilation skipped because existing memoization could not be preserved
|
||||
Compilation Skipped: 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 |
|
||||
|
||||
Memoization: Compilation skipped because existing memoization could not be preserved
|
||||
Compilation Skipped: 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.
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ function Component({propA}) {
|
||||
```
|
||||
Found 1 error:
|
||||
|
||||
Memoization: Compilation skipped because existing memoization could not be preserved
|
||||
Compilation Skipped: 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.
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ function Component({propA}) {
|
||||
```
|
||||
Found 1 error:
|
||||
|
||||
Memoization: Compilation skipped because existing memoization could not be preserved
|
||||
Compilation Skipped: 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.
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ function useFoo(input1) {
|
||||
```
|
||||
Found 1 error:
|
||||
|
||||
Memoization: Compilation skipped because existing memoization could not be preserved
|
||||
Compilation Skipped: 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.
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ function Component(props) {
|
||||
```
|
||||
Found 1 error:
|
||||
|
||||
Memoization: Compilation skipped because existing memoization could not be preserved
|
||||
Compilation Skipped: 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.
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ function Component(props) {
|
||||
```
|
||||
Found 1 error:
|
||||
|
||||
Memoization: Compilation skipped because existing memoization could not be preserved
|
||||
Compilation Skipped: 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.
|
||||
|
||||
|
||||
@@ -48,7 +48,10 @@ export {
|
||||
printReactiveFunction,
|
||||
printReactiveFunctionWithOutlined,
|
||||
} from './ReactiveScopes';
|
||||
export {parseConfigPragmaForTests} from './Utils/TestUtils';
|
||||
export {
|
||||
parseConfigPragmaForTests,
|
||||
parseConfigPragmaAsString,
|
||||
} from './Utils/TestUtils';
|
||||
declare global {
|
||||
let __DEV__: boolean | null | undefined;
|
||||
}
|
||||
|
||||
@@ -198,6 +198,51 @@ 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
|
||||
|
||||
@@ -3,7 +3,7 @@ import Fixture from '../../Fixture';
|
||||
|
||||
const React = window.React;
|
||||
|
||||
const {Fragment, useEffect, useRef, useState} = React;
|
||||
const {Fragment, useRef} = React;
|
||||
|
||||
export default function FocusCase() {
|
||||
const fragmentRef = useRef(null);
|
||||
|
||||
@@ -2,7 +2,7 @@ import TestCase from '../../TestCase';
|
||||
import Fixture from '../../Fixture';
|
||||
|
||||
const React = window.React;
|
||||
const {Fragment, useEffect, useRef, useState} = React;
|
||||
const {Fragment, useRef, useState} = React;
|
||||
|
||||
export default function GetClientRectsCase() {
|
||||
const fragmentRef = useRef(null);
|
||||
|
||||
@@ -0,0 +1,184 @@
|
||||
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>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
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>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
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>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
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>
|
||||
);
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import IntersectionObserverCase from './IntersectionObserverCase';
|
||||
import ResizeObserverCase from './ResizeObserverCase';
|
||||
import FocusCase from './FocusCase';
|
||||
import GetClientRectsCase from './GetClientRectsCase';
|
||||
import ScrollIntoViewCase from './ScrollIntoViewCase';
|
||||
|
||||
const React = window.React;
|
||||
|
||||
@@ -17,6 +18,7 @@ export default function FragmentRefsPage() {
|
||||
<ResizeObserverCase />
|
||||
<FocusCase />
|
||||
<GetClientRectsCase />
|
||||
<ScrollIntoViewCase />
|
||||
</FixtureSet>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2,14 +2,23 @@ import './polyfills';
|
||||
import loadReact, {isLocal} from './react-loader';
|
||||
|
||||
if (isLocal()) {
|
||||
Promise.all([import('react'), import('react-dom/client')])
|
||||
.then(([React, ReactDOMClient]) => {
|
||||
if (React === undefined || ReactDOMClient === undefined) {
|
||||
Promise.all([
|
||||
import('react'),
|
||||
import('react-dom'),
|
||||
import('react-dom/client'),
|
||||
])
|
||||
.then(([React, ReactDOM, ReactDOMClient]) => {
|
||||
if (
|
||||
React === undefined ||
|
||||
ReactDOM === 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'))
|
||||
|
||||
20
flow-typed.config.json
Normal file
20
flow-typed.config.json
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"env": [
|
||||
"bom",
|
||||
"cssom",
|
||||
"dom",
|
||||
"geometry",
|
||||
"html",
|
||||
"node",
|
||||
"serviceworkers",
|
||||
"streams",
|
||||
"web-animations"
|
||||
],
|
||||
"ignore": [
|
||||
"create-react-class",
|
||||
"jest",
|
||||
"regenerator-runtime",
|
||||
"webpack",
|
||||
"ws"
|
||||
]
|
||||
}
|
||||
2719
flow-typed/environments/bom.js
vendored
Normal file
2719
flow-typed/environments/bom.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
414
flow-typed/environments/cssom.js
vendored
Normal file
414
flow-typed/environments/cssom.js
vendored
Normal file
@@ -0,0 +1,414 @@
|
||||
// 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;
|
||||
}
|
||||
3676
flow-typed/environments/dom.js
vendored
Normal file
3676
flow-typed/environments/dom.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
270
flow-typed/environments/geometry.js
vendored
Normal file
270
flow-typed/environments/geometry.js
vendored
Normal file
@@ -0,0 +1,270 @@
|
||||
// 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;
|
||||
}
|
||||
1710
flow-typed/environments/html.js
vendored
Normal file
1710
flow-typed/environments/html.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
4286
flow-typed/environments/node.js
vendored
Normal file
4286
flow-typed/environments/node.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
248
flow-typed/environments/serviceworkers.js
vendored
Normal file
248
flow-typed/environments/serviceworkers.js
vendored
Normal file
@@ -0,0 +1,248 @@
|
||||
// flow-typed signature: f6bda44505d6258bae702a65ee2878f2
|
||||
// flow-typed version: 840509ea9d/serviceworkers/flow_>=v0.261.x
|
||||
|
||||
type FrameType = 'auxiliary' | 'top-level' | 'nested' | 'none';
|
||||
type VisibilityState = 'hidden' | 'visible' | 'prerender' | 'unloaded';
|
||||
|
||||
declare class WindowClient extends Client {
|
||||
visibilityState: VisibilityState;
|
||||
focused: boolean;
|
||||
focus(): Promise<WindowClient>;
|
||||
navigate(url: string): Promise<WindowClient>;
|
||||
}
|
||||
|
||||
declare class Client {
|
||||
id: string;
|
||||
reserved: boolean;
|
||||
url: string;
|
||||
frameType: FrameType;
|
||||
postMessage(message: any, transfer?: Iterator<any> | Array<any>): void;
|
||||
}
|
||||
|
||||
declare class ExtendableEvent extends Event {
|
||||
waitUntil(f: Promise<mixed>): void;
|
||||
}
|
||||
|
||||
type NotificationEvent$Init = {
|
||||
...Event$Init,
|
||||
notification: Notification,
|
||||
action?: string,
|
||||
...
|
||||
};
|
||||
|
||||
declare class NotificationEvent extends ExtendableEvent {
|
||||
constructor(type: string, eventInitDict?: NotificationEvent$Init): void;
|
||||
+notification: Notification;
|
||||
+action: string;
|
||||
}
|
||||
|
||||
type ForeignFetchOptions = {
|
||||
scopes: Iterator<string>,
|
||||
origins: Iterator<string>,
|
||||
...
|
||||
};
|
||||
|
||||
declare class InstallEvent extends ExtendableEvent {
|
||||
registerForeignFetch(options: ForeignFetchOptions): void;
|
||||
}
|
||||
|
||||
declare class FetchEvent extends ExtendableEvent {
|
||||
request: Request;
|
||||
clientId: string;
|
||||
isReload: boolean;
|
||||
respondWith(response: Response | Promise<Response>): void;
|
||||
preloadResponse: Promise<?Response>;
|
||||
}
|
||||
|
||||
type ClientType = 'window' | 'worker' | 'sharedworker' | 'all';
|
||||
type ClientQueryOptions = {
|
||||
includeUncontrolled?: boolean,
|
||||
includeReserved?: boolean,
|
||||
type?: ClientType,
|
||||
...
|
||||
};
|
||||
|
||||
declare class Clients {
|
||||
get(id: string): Promise<?Client>;
|
||||
matchAll(options?: ClientQueryOptions): Promise<Array<Client>>;
|
||||
openWindow(url: string): Promise<?WindowClient>;
|
||||
claim(): Promise<void>;
|
||||
}
|
||||
|
||||
type ServiceWorkerState =
|
||||
| 'installing'
|
||||
| 'installed'
|
||||
| 'activating'
|
||||
| 'activated'
|
||||
| 'redundant';
|
||||
|
||||
declare class ServiceWorker extends EventTarget {
|
||||
scriptURL: string;
|
||||
state: ServiceWorkerState;
|
||||
|
||||
postMessage(message: any, transfer?: Iterator<any>): void;
|
||||
|
||||
onstatechange?: EventHandler;
|
||||
}
|
||||
|
||||
declare class NavigationPreloadState {
|
||||
enabled: boolean;
|
||||
headerValue: string;
|
||||
}
|
||||
|
||||
declare class NavigationPreloadManager {
|
||||
enable: Promise<void>;
|
||||
disable: Promise<void>;
|
||||
setHeaderValue(value: string): Promise<void>;
|
||||
getState: Promise<NavigationPreloadState>;
|
||||
}
|
||||
|
||||
type PushSubscriptionOptions = {
|
||||
userVisibleOnly?: boolean,
|
||||
applicationServerKey?: string | ArrayBuffer | $ArrayBufferView,
|
||||
...
|
||||
};
|
||||
|
||||
declare class PushSubscriptionJSON {
|
||||
endpoint: string;
|
||||
expirationTime: number | null;
|
||||
keys: {[string]: string, ...};
|
||||
}
|
||||
|
||||
declare class PushSubscription {
|
||||
+endpoint: string;
|
||||
+expirationTime: number | null;
|
||||
+options: PushSubscriptionOptions;
|
||||
getKey(name: string): ArrayBuffer | null;
|
||||
toJSON(): PushSubscriptionJSON;
|
||||
unsubscribe(): Promise<boolean>;
|
||||
}
|
||||
|
||||
declare class PushManager {
|
||||
+supportedContentEncodings: Array<string>;
|
||||
subscribe(options?: PushSubscriptionOptions): Promise<PushSubscription>;
|
||||
getSubscription(): Promise<PushSubscription | null>;
|
||||
permissionState(
|
||||
options?: PushSubscriptionOptions
|
||||
): Promise<'granted' | 'denied' | 'prompt'>;
|
||||
}
|
||||
|
||||
type ServiceWorkerUpdateViaCache = 'imports' | 'all' | 'none';
|
||||
|
||||
type GetNotificationOptions = {
|
||||
tag?: string,
|
||||
...
|
||||
};
|
||||
|
||||
declare class ServiceWorkerRegistration extends EventTarget {
|
||||
+installing: ?ServiceWorker;
|
||||
+waiting: ?ServiceWorker;
|
||||
+active: ?ServiceWorker;
|
||||
+navigationPreload: NavigationPreloadManager;
|
||||
+scope: string;
|
||||
+updateViaCache: ServiceWorkerUpdateViaCache;
|
||||
+pushManager: PushManager;
|
||||
|
||||
getNotifications?: (
|
||||
filter?: GetNotificationOptions
|
||||
) => Promise<$ReadOnlyArray<Notification>>;
|
||||
showNotification?: (
|
||||
title: string,
|
||||
options?: NotificationOptions
|
||||
) => Promise<void>;
|
||||
update(): Promise<void>;
|
||||
unregister(): Promise<boolean>;
|
||||
|
||||
onupdatefound?: EventHandler;
|
||||
}
|
||||
|
||||
type WorkerType = 'classic' | 'module';
|
||||
|
||||
type RegistrationOptions = {
|
||||
scope?: string,
|
||||
type?: WorkerType,
|
||||
updateViaCache?: ServiceWorkerUpdateViaCache,
|
||||
...
|
||||
};
|
||||
|
||||
declare class ServiceWorkerContainer extends EventTarget {
|
||||
+controller: ?ServiceWorker;
|
||||
+ready: Promise<ServiceWorkerRegistration>;
|
||||
|
||||
getRegistration(
|
||||
clientURL?: string
|
||||
): Promise<ServiceWorkerRegistration | void>;
|
||||
getRegistrations(): Promise<Iterator<ServiceWorkerRegistration>>;
|
||||
register(
|
||||
scriptURL: string | TrustedScriptURL,
|
||||
options?: RegistrationOptions
|
||||
): Promise<ServiceWorkerRegistration>;
|
||||
startMessages(): void;
|
||||
|
||||
oncontrollerchange?: EventHandler;
|
||||
onmessage?: EventHandler;
|
||||
onmessageerror?: EventHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* This feature has been removed from the Web standards.
|
||||
*/
|
||||
declare class ServiceWorkerMessageEvent extends Event {
|
||||
data: any;
|
||||
lastEventId: string;
|
||||
origin: string;
|
||||
ports: Array<MessagePort>;
|
||||
source: ?(ServiceWorker | MessagePort);
|
||||
}
|
||||
|
||||
declare class ExtendableMessageEvent extends ExtendableEvent {
|
||||
data: any;
|
||||
lastEventId: string;
|
||||
origin: string;
|
||||
ports: Array<MessagePort>;
|
||||
source: ?(ServiceWorker | MessagePort);
|
||||
}
|
||||
|
||||
type CacheQueryOptions = {
|
||||
ignoreSearch?: boolean,
|
||||
ignoreMethod?: boolean,
|
||||
ignoreVary?: boolean,
|
||||
cacheName?: string,
|
||||
...
|
||||
};
|
||||
|
||||
declare class Cache {
|
||||
match(request: RequestInfo, options?: CacheQueryOptions): Promise<Response>;
|
||||
matchAll(
|
||||
request: RequestInfo,
|
||||
options?: CacheQueryOptions
|
||||
): Promise<Array<Response>>;
|
||||
add(request: RequestInfo): Promise<void>;
|
||||
addAll(requests: Array<RequestInfo>): Promise<void>;
|
||||
put(request: RequestInfo, response: Response): Promise<void>;
|
||||
delete(request: RequestInfo, options?: CacheQueryOptions): Promise<boolean>;
|
||||
keys(
|
||||
request?: RequestInfo,
|
||||
options?: CacheQueryOptions
|
||||
): Promise<Array<Request>>;
|
||||
}
|
||||
|
||||
declare class CacheStorage {
|
||||
match(request: RequestInfo, options?: CacheQueryOptions): Promise<Response>;
|
||||
has(cacheName: string): Promise<true>;
|
||||
open(cacheName: string): Promise<Cache>;
|
||||
delete(cacheName: string): Promise<boolean>;
|
||||
keys(): Promise<Array<string>>;
|
||||
}
|
||||
|
||||
// Service worker global scope
|
||||
// https://www.w3.org/TR/service-workers/#service-worker-global-scope
|
||||
declare var clients: Clients;
|
||||
declare var caches: CacheStorage;
|
||||
declare var registration: ServiceWorkerRegistration;
|
||||
declare function skipWaiting(): Promise<void>;
|
||||
declare var onactivate: ?EventHandler;
|
||||
declare var oninstall: ?EventHandler;
|
||||
declare var onfetch: ?EventHandler;
|
||||
declare var onforeignfetch: ?EventHandler;
|
||||
declare var onmessage: ?EventHandler;
|
||||
136
flow-typed/environments/streams.js
vendored
Normal file
136
flow-typed/environments/streams.js
vendored
Normal file
@@ -0,0 +1,136 @@
|
||||
// flow-typed signature: e6e6768618776352dd676f63502aea4d
|
||||
// flow-typed version: 40e7dfcbd5/streams/flow_>=v0.261.x
|
||||
|
||||
type TextEncodeOptions = {options?: boolean, ...};
|
||||
|
||||
declare class ReadableStreamController {
|
||||
constructor(
|
||||
stream: ReadableStream,
|
||||
underlyingSource: UnderlyingSource,
|
||||
size: number,
|
||||
highWaterMark: number
|
||||
): void;
|
||||
|
||||
desiredSize: number;
|
||||
|
||||
close(): void;
|
||||
enqueue(chunk: any): void;
|
||||
error(error: Error): void;
|
||||
}
|
||||
|
||||
declare class ReadableStreamBYOBRequest {
|
||||
constructor(controller: ReadableStreamController, view: $TypedArray): void;
|
||||
|
||||
view: $TypedArray;
|
||||
|
||||
respond(bytesWritten: number): ?any;
|
||||
respondWithNewView(view: $TypedArray): ?any;
|
||||
}
|
||||
|
||||
declare class ReadableByteStreamController extends ReadableStreamController {
|
||||
constructor(
|
||||
stream: ReadableStream,
|
||||
underlyingSource: UnderlyingSource,
|
||||
highWaterMark: number
|
||||
): void;
|
||||
|
||||
byobRequest: ReadableStreamBYOBRequest;
|
||||
}
|
||||
|
||||
declare class ReadableStreamReader {
|
||||
constructor(stream: ReadableStream): void;
|
||||
|
||||
closed: boolean;
|
||||
|
||||
cancel(reason: string): void;
|
||||
read(): Promise<{
|
||||
value: ?any,
|
||||
done: boolean,
|
||||
...
|
||||
}>;
|
||||
releaseLock(): void;
|
||||
}
|
||||
|
||||
declare interface UnderlyingSource {
|
||||
autoAllocateChunkSize?: number;
|
||||
type?: string;
|
||||
|
||||
start?: (controller: ReadableStreamController) => ?Promise<void>;
|
||||
pull?: (controller: ReadableStreamController) => ?Promise<void>;
|
||||
cancel?: (reason: string) => ?Promise<void>;
|
||||
}
|
||||
|
||||
declare class TransformStream {
|
||||
readable: ReadableStream;
|
||||
writable: WritableStream;
|
||||
}
|
||||
|
||||
interface PipeThroughTransformStream {
|
||||
readable: ReadableStream;
|
||||
writable: WritableStream;
|
||||
}
|
||||
|
||||
type PipeToOptions = {
|
||||
preventClose?: boolean,
|
||||
preventAbort?: boolean,
|
||||
preventCancel?: boolean,
|
||||
...
|
||||
};
|
||||
|
||||
type QueuingStrategy = {
|
||||
highWaterMark: number,
|
||||
size(chunk: ?any): number,
|
||||
...
|
||||
};
|
||||
|
||||
declare class ReadableStream {
|
||||
constructor(
|
||||
underlyingSource: ?UnderlyingSource,
|
||||
queuingStrategy: ?QueuingStrategy
|
||||
): void;
|
||||
|
||||
locked: boolean;
|
||||
|
||||
cancel(reason: string): void;
|
||||
getReader(): ReadableStreamReader;
|
||||
pipeThrough(transform: PipeThroughTransformStream, options: ?any): void;
|
||||
pipeTo(dest: WritableStream, options: ?PipeToOptions): Promise<void>;
|
||||
tee(): [ReadableStream, ReadableStream];
|
||||
}
|
||||
|
||||
declare interface WritableStreamController {
|
||||
error(error: Error): void;
|
||||
}
|
||||
|
||||
declare interface UnderlyingSink {
|
||||
autoAllocateChunkSize?: number;
|
||||
type?: string;
|
||||
|
||||
abort?: (reason: string) => ?Promise<void>;
|
||||
close?: (controller: WritableStreamController) => ?Promise<void>;
|
||||
start?: (controller: WritableStreamController) => ?Promise<void>;
|
||||
write?: (chunk: any, controller: WritableStreamController) => ?Promise<void>;
|
||||
}
|
||||
|
||||
declare interface WritableStreamWriter {
|
||||
closed: Promise<any>;
|
||||
desiredSize?: number;
|
||||
ready: Promise<any>;
|
||||
|
||||
abort(reason: string): ?Promise<any>;
|
||||
close(): Promise<any>;
|
||||
releaseLock(): void;
|
||||
write(chunk: any): Promise<any>;
|
||||
}
|
||||
|
||||
declare class WritableStream {
|
||||
constructor(
|
||||
underlyingSink: ?UnderlyingSink,
|
||||
queuingStrategy: QueuingStrategy
|
||||
): void;
|
||||
|
||||
locked: boolean;
|
||||
|
||||
abort(reason: string): void;
|
||||
getWriter(): WritableStreamWriter;
|
||||
}
|
||||
193
flow-typed/environments/web-animations.js
vendored
Normal file
193
flow-typed/environments/web-animations.js
vendored
Normal file
@@ -0,0 +1,193 @@
|
||||
// flow-typed signature: 4631a74b6a0e6a1b4de2ba8c7bb141d6
|
||||
// flow-typed version: 3e51657e95/web-animations/flow_>=v0.261.x
|
||||
|
||||
// https://www.w3.org/TR/web-animations-1/
|
||||
|
||||
type AnimationPlayState = 'idle' | 'running' | 'paused' | 'finished';
|
||||
|
||||
type AnimationReplaceState = 'active' | 'removed' | 'persisted';
|
||||
|
||||
type CompositeOperation = 'replace' | 'add' | 'accumulate';
|
||||
|
||||
type CompositeOperationOrAuto = 'replace' | 'add' | 'accumulate' | 'auto';
|
||||
|
||||
type FillMode = 'none' | 'forwards' | 'backwards' | 'both' | 'auto';
|
||||
|
||||
// This is actually web-animations-2
|
||||
type IterationCompositeOperation = 'replace' | 'accumulate';
|
||||
|
||||
type PlaybackDirection =
|
||||
| 'normal'
|
||||
| 'reverse'
|
||||
| 'alternate'
|
||||
| 'alternate-reverse';
|
||||
|
||||
type AnimationPlaybackEvent$Init = Event$Init & {
|
||||
currentTime?: number | null,
|
||||
timelineTime?: number | null,
|
||||
...
|
||||
};
|
||||
|
||||
type BaseComputedKeyframe = {|
|
||||
composite: CompositeOperationOrAuto,
|
||||
computedOffset: number,
|
||||
easing: string,
|
||||
offset: number | null,
|
||||
|};
|
||||
|
||||
type BaseKeyframe = {|
|
||||
composite: CompositeOperationOrAuto,
|
||||
easing: string,
|
||||
offset: number | null,
|
||||
|};
|
||||
|
||||
type BasePropertyIndexedKeyframe = {|
|
||||
composite: CompositeOperationOrAuto | Array<CompositeOperationOrAuto>,
|
||||
easing: string | Array<string>,
|
||||
offset: number | null | Array<number | null>,
|
||||
|};
|
||||
|
||||
type ComputedEffectTiming = {|
|
||||
...EffectTiming,
|
||||
currentIteration: number | null,
|
||||
progress: number | null,
|
||||
|};
|
||||
|
||||
type ComputedKeyframe = {
|
||||
composite: CompositeOperationOrAuto,
|
||||
computedOffset: number,
|
||||
easing: string,
|
||||
offset: number | null,
|
||||
[property: string]: string | number | null | void,
|
||||
...
|
||||
};
|
||||
|
||||
type DocumentTimelineOptions = {|
|
||||
originTime: number,
|
||||
|};
|
||||
|
||||
type EffectTiming = {|
|
||||
direction: PlaybackDirection,
|
||||
easing: string,
|
||||
fill: FillMode,
|
||||
iterations: number,
|
||||
iterationStart: number,
|
||||
|};
|
||||
|
||||
type GetAnimationsOptions = {|
|
||||
pseudoElement: string | null,
|
||||
subtree: boolean,
|
||||
|};
|
||||
|
||||
type KeyframeAnimationOptions = {|
|
||||
...KeyframeEffectOptions,
|
||||
id: string,
|
||||
timeline: AnimationTimeline | null,
|
||||
|};
|
||||
|
||||
type KeyframeEffectOptions = {|
|
||||
...EffectTiming,
|
||||
composite: CompositeOperation,
|
||||
pseudoElement: string | null,
|
||||
|};
|
||||
|
||||
type Keyframe = {
|
||||
composite?: CompositeOperationOrAuto,
|
||||
easing?: string,
|
||||
offset?: number | null,
|
||||
[property: string]: string | number | null | void,
|
||||
...
|
||||
};
|
||||
|
||||
type OptionalEffectTiming = Partial<EffectTiming>;
|
||||
|
||||
type PropertyIndexedKeyframes = {
|
||||
composite?: CompositeOperationOrAuto | CompositeOperationOrAuto[],
|
||||
easing?: string | string[],
|
||||
offset?: number | (number | null)[],
|
||||
[property: string]:
|
||||
| string
|
||||
| string[]
|
||||
| number
|
||||
| null
|
||||
| (number | null)[]
|
||||
| void,
|
||||
...
|
||||
};
|
||||
|
||||
declare class Animation extends EventTarget {
|
||||
constructor(
|
||||
effect?: AnimationEffect | null,
|
||||
timeline?: AnimationTimeline | null
|
||||
): void;
|
||||
|
||||
id: string;
|
||||
effect: AnimationEffect | null;
|
||||
timeline: AnimationTimeline | null;
|
||||
startTime: number | null;
|
||||
currentTime: number | null;
|
||||
playbackRate: number;
|
||||
+playState: AnimationPlayState;
|
||||
+replaceState: AnimationReplaceState;
|
||||
+pending: boolean;
|
||||
+ready: Promise<Animation>;
|
||||
+finished: Promise<Animation>;
|
||||
onfinish: ?(ev: AnimationPlaybackEvent) => mixed;
|
||||
oncancel: ?(ev: AnimationPlaybackEvent) => mixed;
|
||||
onremove: ?(ev: AnimationPlaybackEvent) => mixed;
|
||||
cancel(): void;
|
||||
finish(): void;
|
||||
play(): void;
|
||||
pause(): void;
|
||||
updatePlaybackRate(playbackRate: number): void;
|
||||
reverse(): void;
|
||||
persist(): void;
|
||||
commitStyles(): void;
|
||||
}
|
||||
|
||||
declare class AnimationEffect {
|
||||
getTiming(): EffectTiming;
|
||||
getComputedTiming(): ComputedEffectTiming;
|
||||
updateTiming(timing?: OptionalEffectTiming): void;
|
||||
}
|
||||
|
||||
declare class AnimationPlaybackEvent extends Event {
|
||||
constructor(
|
||||
type: string,
|
||||
animationEventInitDict?: AnimationPlaybackEvent$Init
|
||||
): void;
|
||||
+currentTime: number | null;
|
||||
+timelineTime: number | null;
|
||||
}
|
||||
|
||||
declare class AnimationTimeline {
|
||||
+currentTime: number | null;
|
||||
}
|
||||
|
||||
declare class DocumentTimeline extends AnimationTimeline {
|
||||
constructor(options?: DocumentTimelineOptions): void;
|
||||
}
|
||||
|
||||
declare class KeyframeEffect extends AnimationEffect {
|
||||
constructor(
|
||||
target: Element | null,
|
||||
keyframes: Keyframe[] | PropertyIndexedKeyframes | null,
|
||||
options?: number | KeyframeEffectOptions
|
||||
): void;
|
||||
constructor(source: KeyframeEffect): void;
|
||||
|
||||
target: Element | null;
|
||||
composite: CompositeOperation;
|
||||
// This is actually web-animations-2
|
||||
iterationComposite: IterationCompositeOperation;
|
||||
getKeyframes(): ComputedKeyframe[];
|
||||
setKeyframes(keyframes: Keyframe[] | PropertyIndexedKeyframes | null): void;
|
||||
}
|
||||
|
||||
declare class mixin$Animatable {
|
||||
animate(
|
||||
keyframes: Keyframe[] | PropertyIndexedKeyframes | null,
|
||||
options?: number | KeyframeAnimationOptions
|
||||
): Animation;
|
||||
getAnimations(options?: GetAnimationsOptions): Array<Animation>;
|
||||
}
|
||||
60
flow-typed/npm/error-stack-parser_v2.x.x.js
vendored
Normal file
60
flow-typed/npm/error-stack-parser_v2.x.x.js
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
// flow-typed signature: 132e48034ef4756600e1d98681a166b5
|
||||
// flow-typed version: c6154227d1/error-stack-parser_v2.x.x/flow_>=v0.104.x
|
||||
|
||||
declare module 'error-stack-parser' {
|
||||
declare interface StackFrame {
|
||||
constructor(object: StackFrame): StackFrame;
|
||||
|
||||
isConstructor?: boolean;
|
||||
getIsConstructor(): boolean;
|
||||
setIsConstructor(): void;
|
||||
|
||||
isEval?: boolean;
|
||||
getIsEval(): boolean;
|
||||
setIsEval(): void;
|
||||
|
||||
isNative?: boolean;
|
||||
getIsNative(): boolean;
|
||||
setIsNative(): void;
|
||||
|
||||
isTopLevel?: boolean;
|
||||
getIsTopLevel(): boolean;
|
||||
setIsTopLevel(): void;
|
||||
|
||||
columnNumber?: number;
|
||||
getColumnNumber(): number;
|
||||
setColumnNumber(): void;
|
||||
|
||||
lineNumber?: number;
|
||||
getLineNumber(): number;
|
||||
setLineNumber(): void;
|
||||
|
||||
fileName?: string;
|
||||
getFileName(): string;
|
||||
setFileName(): void;
|
||||
|
||||
functionName?: string;
|
||||
getFunctionName(): string;
|
||||
setFunctionName(): void;
|
||||
|
||||
source?: string;
|
||||
getSource(): string;
|
||||
setSource(): void;
|
||||
|
||||
args?: any[];
|
||||
getArgs(): any[];
|
||||
setArgs(): void;
|
||||
|
||||
evalOrigin?: StackFrame;
|
||||
getEvalOrigin(): StackFrame;
|
||||
setEvalOrigin(): void;
|
||||
|
||||
toString(): string;
|
||||
}
|
||||
|
||||
declare class ErrorStackParser {
|
||||
parse(error: Error): Array<StackFrame>;
|
||||
}
|
||||
|
||||
declare module.exports: ErrorStackParser;
|
||||
}
|
||||
27
flow-typed/npm/minimist_v1.x.x.js
vendored
Normal file
27
flow-typed/npm/minimist_v1.x.x.js
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
// flow-typed signature: d48da8db828529253fc20b80747846ea
|
||||
// flow-typed version: c6154227d1/minimist_v1.x.x/flow_>=v0.104.x
|
||||
|
||||
declare module 'minimist' {
|
||||
declare type minimistOptions = {
|
||||
string?: string | Array<string>,
|
||||
boolean?: boolean | string | Array<string>,
|
||||
alias?: {[arg: string]: string | Array<string>, ...},
|
||||
default?: {[arg: string]: any, ...},
|
||||
stopEarly?: boolean,
|
||||
// TODO: Strings as keys don't work...
|
||||
// '--'? boolean,
|
||||
unknown?: (param: string) => boolean,
|
||||
...
|
||||
};
|
||||
|
||||
declare type minimistOutput = {
|
||||
[flag: string]: string | boolean,
|
||||
_: Array<string>,
|
||||
...
|
||||
};
|
||||
|
||||
declare module.exports: (
|
||||
argv: Array<string>,
|
||||
opts?: minimistOptions
|
||||
) => minimistOutput;
|
||||
}
|
||||
10
package.json
10
package.json
@@ -74,14 +74,15 @@
|
||||
"eslint-plugin-react-internal": "link:./scripts/eslint-rules",
|
||||
"fbjs-scripts": "^3.0.1",
|
||||
"filesize": "^6.0.1",
|
||||
"flow-bin": "^0.261",
|
||||
"flow-remove-types": "^2.261",
|
||||
"flow-bin": "^0.279.0",
|
||||
"flow-remove-types": "^2.279.0",
|
||||
"flow-typed": "^4.1.1",
|
||||
"glob": "^7.1.6",
|
||||
"glob-stream": "^6.1.0",
|
||||
"google-closure-compiler": "^20230206.0.0",
|
||||
"gzip-size": "^5.1.1",
|
||||
"hermes-eslint": "^0.25.1",
|
||||
"hermes-parser": "^0.25.1",
|
||||
"hermes-eslint": "^0.32.0",
|
||||
"hermes-parser": "^0.32.0",
|
||||
"jest": "^29.4.2",
|
||||
"jest-cli": "^29.4.2",
|
||||
"jest-diff": "^29.4.2",
|
||||
@@ -126,6 +127,7 @@
|
||||
"build-for-devtools-prod": "yarn build-for-devtools --type=NODE_PROD",
|
||||
"build-for-flight-dev": "cross-env RELEASE_CHANNEL=experimental node ./scripts/rollup/build.js react/index,react/jsx,react.react-server,react-dom/index,react-dom/client,react-dom/server,react-dom.react-server,react-dom-server.node,react-dom-server-legacy.node,scheduler,react-server-dom-webpack/ --type=NODE_DEV,ESM_PROD,NODE_ES2015 && mv ./build/node_modules ./build/oss-experimental",
|
||||
"build-for-vt-dev": "cross-env RELEASE_CHANNEL=experimental node ./scripts/rollup/build.js react/index,react/jsx,react-dom/index,react-dom/client,react-dom/server,react-dom-server.node,react-dom-server-legacy.node,scheduler --type=NODE_DEV && mv ./build/node_modules ./build/oss-experimental",
|
||||
"flow-typed-install": "yarn flow-typed install --skip --skipFlowRestart --ignore-deps=dev",
|
||||
"linc": "node ./scripts/tasks/linc.js",
|
||||
"lint": "node ./scripts/tasks/eslint.js",
|
||||
"lint-build": "node ./scripts/rollup/validate/index.js",
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
"dependencies": {
|
||||
"@babel/core": "^7.24.4",
|
||||
"@babel/parser": "^7.24.4",
|
||||
"@babel/plugin-transform-private-methods": "^7.24.4",
|
||||
"@babel/plugin-proposal-private-methods": "^7.18.6",
|
||||
"hermes-parser": "^0.25.1",
|
||||
"zod": "^3.22.4",
|
||||
"zod-validation-error": "^3.0.3"
|
||||
|
||||
@@ -11,6 +11,7 @@ const {MessageChannel} = require('node:worker_threads');
|
||||
|
||||
export default function enqueueTask(task: () => void): void {
|
||||
const channel = new MessageChannel();
|
||||
// $FlowFixMe[prop-missing]
|
||||
channel.port1.onmessage = () => {
|
||||
channel.port1.close();
|
||||
task();
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user