Merge c9cfbfda7e into sapling-pr-archive-poteto

This commit is contained in:
lauren
2024-12-26 13:43:26 -05:00
committed by GitHub
119 changed files with 5867 additions and 1751 deletions
+2
View File
@@ -23,6 +23,7 @@ chrome-user-data
.vscode
*.swp
*.swo
*.vsix
packages/react-devtools-core/dist
packages/react-devtools-extensions/chrome/build
@@ -37,3 +38,4 @@ packages/react-devtools-fusebox/dist
packages/react-devtools-inline/dist
packages/react-devtools-shell/dist
packages/react-devtools-timeline/dist
+3 -3
View File
@@ -26,11 +26,11 @@
"react-is": "0.0.0-experimental-4beb1fd8-20241118"
},
"devDependencies": {
"@rollup/plugin-commonjs": "^25.0.7",
"@rollup/plugin-commonjs": "^28.0.2",
"@rollup/plugin-json": "^6.1.0",
"@rollup/plugin-node-resolve": "^15.2.3",
"@rollup/plugin-node-resolve": "^16.0.0",
"@rollup/plugin-terser": "^0.4.4",
"@rollup/plugin-typescript": "^11.1.6",
"@rollup/plugin-typescript": "^12.1.2",
"@tsconfig/strictest": "^2.0.5",
"concurrently": "^7.4.0",
"folder-hash": "^4.0.4",
@@ -42,6 +42,7 @@
"babel-jest": "^29.0.3",
"babel-plugin-fbt": "^1.0.0",
"babel-plugin-fbt-runtime": "^1.0.0",
"cosmiconfig": "^9.0.0",
"eslint": "^8.57.1",
"invariant": "^2.2.4",
"jest": "^29.0.3",
@@ -15,7 +15,7 @@ import terser from '@rollup/plugin-terser';
import prettier from 'rollup-plugin-prettier';
import banner2 from 'rollup-plugin-banner2';
const NO_INLINE = new Set(['@babel/types']);
const NO_INLINE = new Set([]);
const DEV_ROLLUP_CONFIG = {
input: 'src/index.ts',
@@ -24,6 +24,7 @@ const DEV_ROLLUP_CONFIG = {
format: 'cjs',
sourcemap: false,
exports: 'named',
inlineDynamicImports: true,
},
plugins: [
typescript({
@@ -6,7 +6,12 @@
*/
import type * as BabelCore from '@babel/core';
import {compileProgram, parsePluginOptions} from '../Entrypoint';
import {
compileProgram,
findReactConfig,
parsePluginOptions,
type PluginOptions,
} from '../Entrypoint';
import {
injectReanimatedFlag,
pipelineUsesReanimatedPlugin,
@@ -29,7 +34,18 @@ export default function BabelPluginReactCompiler(
* want Forget to run true to source as possible.
*/
Program(prog, pass): void {
let opts = parsePluginOptions(pass.opts);
const reactConfig = findReactConfig();
let opts: PluginOptions | null = null;
if (reactConfig != null) {
opts = parsePluginOptions(reactConfig.config);
if (pass.opts != null) {
console.warn(
`Duplicate React Compiler config found, defaulting to reactrc found in: ${reactConfig.filepath}`,
);
}
} else {
opts = parsePluginOptions(pass.opts);
}
const isDev =
(typeof __DEV__ !== 'undefined' && __DEV__ === true) ||
process.env['NODE_ENV'] === 'development';
@@ -16,6 +16,7 @@ import {
import {hasOwnProperty} from '../Utils/utils';
import {fromZodError} from 'zod-validation-error';
import {CompilerPipelineValue} from './Pipeline';
import {type CosmiconfigResult, cosmiconfigSync} from 'cosmiconfig';
const PanicThresholdOptionsSchema = z.enum([
/*
@@ -286,3 +287,11 @@ export function parseTargetConfig(value: unknown): CompilerReactTarget {
function isCompilerFlag(s: string): s is keyof PluginOptions {
return hasOwnProperty(defaultOptions, s);
}
export function findReactConfig(): CosmiconfigResult {
const explorerSync = cosmiconfigSync('react', {
searchStrategy: 'project',
cache: true,
});
return explorerSync.search();
}
@@ -98,6 +98,7 @@ import {validateNoJSXInTryStatement} from '../Validation/ValidateNoJSXInTryState
import {propagateScopeDependenciesHIR} from '../HIR/PropagateScopeDependenciesHIR';
import {outlineJSX} from '../Optimization/OutlineJsx';
import {optimizePropsMethodCalls} from '../Optimization/OptimizePropsMethodCalls';
import {transformFire} from '../Transform';
export type CompilerPipelineValue =
| {kind: 'ast'; name: string; value: CodegenFunction}
@@ -197,6 +198,11 @@ function runWithEnvironment(
validateHooksUsage(hir);
}
if (env.config.enableFire) {
transformFire(hir);
log({kind: 'hir', name: 'TransformFire', value: hir});
}
if (env.config.validateNoCapitalizedCalls) {
validateNoCapitalizedCalls(hir);
}
@@ -564,6 +564,14 @@ export function compileProgram(
if (environment.enableChangeDetectionForDebugging != null) {
externalFunctions.push(environment.enableChangeDetectionForDebugging);
}
const hasFireRewrite = compiledFns.some(c => c.compiledFn.hasFireRewrite);
if (environment.enableFire && hasFireRewrite) {
externalFunctions.push({
source: getReactCompilerRuntimeModule(pass.opts),
importSpecifierName: 'useFire',
});
}
} catch (err) {
handleError(err, pass, null);
return;
@@ -787,6 +787,7 @@ export class Environment {
fnType: ReactFunctionType;
useMemoCacheIdentifier: string;
hasLoweredContextAccess: boolean;
hasFireRewrite: boolean;
#contextIdentifiers: Set<t.Identifier>;
#hoistedIdentifiers: Set<t.Identifier>;
@@ -811,6 +812,7 @@ export class Environment {
this.#shapes = new Map(DEFAULT_SHAPES);
this.#globals = new Map(DEFAULT_GLOBALS);
this.hasLoweredContextAccess = false;
this.hasFireRewrite = false;
if (
config.disableMemoizationForDebugging &&
@@ -897,6 +897,14 @@ export function printSourceLocation(loc: SourceLocation): string {
}
}
export function printSourceLocationLine(loc: SourceLocation): string {
if (typeof loc === 'symbol') {
return 'generated';
} else {
return `${loc.start.line}:${loc.end.line}`;
}
}
export function printAliases(aliases: DisjointSet<Identifier>): string {
const aliasSets = aliases.buildSets();
@@ -103,6 +103,11 @@ export type CodegenFunction = {
* This is true if the compiler has the lowered useContext calls.
*/
hasLoweredContextAccess: boolean;
/**
* This is true if the compiler has compiled a fire to a useFire call
*/
hasFireRewrite: boolean;
};
export function codegenFunction(
@@ -355,6 +360,7 @@ function codegenReactiveFunction(
prunedMemoValues: countMemoBlockVisitor.prunedMemoValues,
outlined: [],
hasLoweredContextAccess: fn.env.hasLoweredContextAccess,
hasFireRewrite: fn.env.hasFireRewrite,
});
}
@@ -0,0 +1,760 @@
/**
* 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 {
CompilerError,
CompilerErrorDetailOptions,
ErrorSeverity,
SourceLocation,
} from '..';
import {
ArrayExpression,
CallExpression,
Effect,
Environment,
FunctionExpression,
GeneratedSource,
HIRFunction,
Identifier,
IdentifierId,
Instruction,
InstructionId,
InstructionKind,
InstructionValue,
isUseEffectHookType,
LoadLocal,
makeInstructionId,
Place,
promoteTemporary,
} from '../HIR';
import {createTemporaryPlace, markInstructionIds} from '../HIR/HIRBuilder';
import {getOrInsertWith} from '../Utils/utils';
import {BuiltInFireId, DefaultNonmutatingHook} from '../HIR/ObjectShape';
import {eachInstructionOperand} from '../HIR/visitors';
import {printSourceLocationLine} from '../HIR/PrintHIR';
/*
* TODO(jmbrown):
* - traverse object methods
* - method calls
* - React.useEffect calls
*/
const CANNOT_COMPILE_FIRE = 'Cannot compile `fire`';
export function transformFire(fn: HIRFunction): void {
const context = new Context(fn.env);
replaceFireFunctions(fn, context);
if (!context.hasErrors()) {
ensureNoMoreFireUses(fn, context);
}
context.throwIfErrorsFound();
}
function replaceFireFunctions(fn: HIRFunction, context: Context): void {
let hasRewrite = false;
for (const [, block] of fn.body.blocks) {
const rewriteInstrs = new Map<InstructionId, Array<Instruction>>();
const deleteInstrs = new Set<InstructionId>();
for (const instr of block.instructions) {
const {value, lvalue} = instr;
if (
value.kind === 'CallExpression' &&
isUseEffectHookType(value.callee.identifier) &&
value.args.length > 0 &&
value.args[0].kind === 'Identifier'
) {
const lambda = context.getFunctionExpression(
value.args[0].identifier.id,
);
if (lambda != null) {
const capturedCallees =
visitFunctionExpressionAndPropagateFireDependencies(
lambda,
context,
true,
);
// Add useFire calls for all fire calls in found in the lambda
const newInstrs = [];
for (const [
fireCalleePlace,
fireCalleeInfo,
] of capturedCallees.entries()) {
if (!context.hasCalleeWithInsertedFire(fireCalleePlace)) {
context.addCalleeWithInsertedFire(fireCalleePlace);
const loadUseFireInstr = makeLoadUseFireInstruction(fn.env);
const loadFireCalleeInstr = makeLoadFireCalleeInstruction(
fn.env,
fireCalleeInfo.capturedCalleeIdentifier,
);
const callUseFireInstr = makeCallUseFireInstruction(
fn.env,
loadUseFireInstr.lvalue,
loadFireCalleeInstr.lvalue,
);
const storeUseFireInstr = makeStoreUseFireInstruction(
fn.env,
callUseFireInstr.lvalue,
fireCalleeInfo.fireFunctionBinding,
);
newInstrs.push(
loadUseFireInstr,
loadFireCalleeInstr,
callUseFireInstr,
storeUseFireInstr,
);
// We insert all of these instructions before the useEffect is loaded
const loadUseEffectInstrId = context.getLoadGlobalInstrId(
value.callee.identifier.id,
);
if (loadUseEffectInstrId == null) {
context.pushError({
loc: value.loc,
description: null,
severity: ErrorSeverity.Invariant,
reason: '[InsertFire] No LoadGlobal found for useEffect call',
suggestions: null,
});
continue;
}
rewriteInstrs.set(loadUseEffectInstrId, newInstrs);
}
}
ensureNoRemainingCalleeCaptures(
lambda.loweredFunc.func,
context,
capturedCallees,
);
if (
value.args.length > 1 &&
value.args[1] != null &&
value.args[1].kind === 'Identifier'
) {
const depArray = value.args[1];
const depArrayExpression = context.getArrayExpression(
depArray.identifier.id,
);
if (depArrayExpression != null) {
for (const dependency of depArrayExpression.elements) {
if (dependency.kind === 'Identifier') {
const loadOfDependency = context.getLoadLocalInstr(
dependency.identifier.id,
);
if (loadOfDependency != null) {
const replacedDepArrayItem = capturedCallees.get(
loadOfDependency.place.identifier.id,
);
if (replacedDepArrayItem != null) {
loadOfDependency.place =
replacedDepArrayItem.fireFunctionBinding;
}
}
}
}
} else {
context.pushError({
loc: value.args[1].loc,
description:
'You must use an array literal for an effect dependency array when that effect uses `fire()`',
severity: ErrorSeverity.Invariant,
reason: CANNOT_COMPILE_FIRE,
suggestions: null,
});
}
} else if (value.args.length > 1 && value.args[1].kind === 'Spread') {
context.pushError({
loc: value.args[1].place.loc,
description:
'You must use an array literal for an effect dependency array when that effect uses `fire()`',
severity: ErrorSeverity.Invariant,
reason: CANNOT_COMPILE_FIRE,
suggestions: null,
});
}
}
} else if (
value.kind === 'CallExpression' &&
value.callee.identifier.type.kind === 'Function' &&
value.callee.identifier.type.shapeId === BuiltInFireId &&
context.inUseEffectLambda()
) {
/*
* We found a fire(callExpr()) call. We remove the `fire()` call and replace the callExpr()
* with a freshly generated fire function binding. We'll insert the useFire call before the
* useEffect call, which happens in the CallExpression (useEffect) case above.
*/
/*
* We only allow fire to be called with a CallExpression: `fire(f())`
* TODO: add support for method calls: `fire(this.method())`
*/
if (value.args.length === 1 && value.args[0].kind === 'Identifier') {
const callExpr = context.getCallExpression(
value.args[0].identifier.id,
);
if (callExpr != null) {
const calleeId = callExpr.callee.identifier.id;
const loadLocal = context.getLoadLocalInstr(calleeId);
if (loadLocal == null) {
context.pushError({
loc: value.loc,
description: null,
severity: ErrorSeverity.Invariant,
reason:
'[InsertFire] No loadLocal found for fire call argument',
suggestions: null,
});
continue;
}
const fireFunctionBinding =
context.getOrGenerateFireFunctionBinding(
loadLocal.place,
value.loc,
);
loadLocal.place = {...fireFunctionBinding};
// Delete the fire call expression
deleteInstrs.add(instr.id);
} else {
context.pushError({
loc: value.loc,
description:
'`fire()` can only receive a function call such as `fire(fn(a,b)). Method calls and other expressions are not allowed',
severity: ErrorSeverity.InvalidReact,
reason: CANNOT_COMPILE_FIRE,
suggestions: null,
});
}
} else {
let description: string =
'fire() can only take in a single call expression as an argument';
if (value.args.length === 0) {
description += ' but received none';
} else if (value.args.length > 1) {
description += ' but received multiple arguments';
} else if (value.args[0].kind === 'Spread') {
description += ' but received a spread argument';
}
context.pushError({
loc: value.loc,
description,
severity: ErrorSeverity.InvalidReact,
reason: CANNOT_COMPILE_FIRE,
suggestions: null,
});
}
} else if (value.kind === 'CallExpression') {
context.addCallExpression(lvalue.identifier.id, value);
} else if (
value.kind === 'FunctionExpression' &&
context.inUseEffectLambda()
) {
visitFunctionExpressionAndPropagateFireDependencies(
value,
context,
false,
);
} else if (value.kind === 'FunctionExpression') {
context.addFunctionExpression(lvalue.identifier.id, value);
} else if (value.kind === 'LoadLocal') {
context.addLoadLocalInstr(lvalue.identifier.id, value);
} else if (
value.kind === 'LoadGlobal' &&
value.binding.kind === 'ImportSpecifier' &&
value.binding.module === 'react' &&
value.binding.imported === 'fire' &&
context.inUseEffectLambda()
) {
deleteInstrs.add(instr.id);
} else if (value.kind === 'LoadGlobal') {
context.addLoadGlobalInstrId(lvalue.identifier.id, instr.id);
} else if (value.kind === 'ArrayExpression') {
context.addArrayExpression(lvalue.identifier.id, value);
}
}
block.instructions = rewriteInstructions(rewriteInstrs, block.instructions);
block.instructions = deleteInstructions(deleteInstrs, block.instructions);
if (rewriteInstrs.size > 0 || deleteInstrs.size > 0) {
hasRewrite = true;
fn.env.hasFireRewrite = true;
}
}
if (hasRewrite) {
markInstructionIds(fn.body);
}
}
/**
* Traverses a function expression to find fire calls fire(foo()) and replaces them with
* fireFoo().
*
* When a function captures a fire call we need to update its context to reflect the newly created
* fire function bindings and update the LoadLocals referenced by the function's dependencies.
*
* @param isUseEffect is necessary so we can keep track of when we should additionally insert
* useFire hooks calls.
*/
function visitFunctionExpressionAndPropagateFireDependencies(
fnExpr: FunctionExpression,
context: Context,
enteringUseEffect: boolean,
): FireCalleesToFireFunctionBinding {
let withScope = enteringUseEffect
? context.withUseEffectLambdaScope.bind(context)
: context.withFunctionScope.bind(context);
const calleesCapturedByFnExpression = withScope(() =>
replaceFireFunctions(fnExpr.loweredFunc.func, context),
);
/*
* Make a mapping from each dependency to the corresponding LoadLocal for it so that
* we can replace the loaded place with the generated fire function binding
*/
const loadLocalsToDepLoads = new Map<IdentifierId, LoadLocal>();
for (const dep of fnExpr.loweredFunc.dependencies) {
const loadLocal = context.getLoadLocalInstr(dep.identifier.id);
if (loadLocal != null) {
loadLocalsToDepLoads.set(loadLocal.place.identifier.id, loadLocal);
}
}
const replacedCallees = new Map<IdentifierId, Place>();
for (const [
calleeIdentifierId,
loadedFireFunctionBindingPlace,
] of calleesCapturedByFnExpression.entries()) {
/*
* Given the ids of captured fire callees, look at the deps for loads of those identifiers
* and replace them with the new fire function binding
*/
const loadLocal = loadLocalsToDepLoads.get(calleeIdentifierId);
if (loadLocal == null) {
context.pushError({
loc: fnExpr.loc,
description: null,
severity: ErrorSeverity.Invariant,
reason:
'[InsertFire] No loadLocal found for fire call argument for lambda',
suggestions: null,
});
continue;
}
const oldPlaceId = loadLocal.place.identifier.id;
loadLocal.place = {
...loadedFireFunctionBindingPlace.fireFunctionBinding,
};
replacedCallees.set(
oldPlaceId,
loadedFireFunctionBindingPlace.fireFunctionBinding,
);
}
// For each replaced callee, update the context of the function expression to track it
for (
let contextIdx = 0;
contextIdx < fnExpr.loweredFunc.func.context.length;
contextIdx++
) {
const contextItem = fnExpr.loweredFunc.func.context[contextIdx];
const replacedCallee = replacedCallees.get(contextItem.identifier.id);
if (replacedCallee != null) {
fnExpr.loweredFunc.func.context[contextIdx] = replacedCallee;
}
}
context.mergeCalleesFromInnerScope(calleesCapturedByFnExpression);
return calleesCapturedByFnExpression;
}
/*
* eachInstructionOperand is not sufficient for our cases because:
* 1. fire is a global, which will not appear
* 2. The HIR may be malformed, so can't rely on function deps and must
* traverse the whole function.
*/
function* eachReachablePlace(fn: HIRFunction): Iterable<Place> {
for (const [, block] of fn.body.blocks) {
for (const instr of block.instructions) {
if (
instr.value.kind === 'FunctionExpression' ||
instr.value.kind === 'ObjectMethod'
) {
yield* eachReachablePlace(instr.value.loweredFunc.func);
} else {
yield* eachInstructionOperand(instr);
}
}
}
}
function ensureNoRemainingCalleeCaptures(
fn: HIRFunction,
context: Context,
capturedCallees: FireCalleesToFireFunctionBinding,
): void {
for (const place of eachReachablePlace(fn)) {
const calleeInfo = capturedCallees.get(place.identifier.id);
if (calleeInfo != null) {
const calleeName =
calleeInfo.capturedCalleeIdentifier.name?.kind === 'named'
? calleeInfo.capturedCalleeIdentifier.name.value
: '<unknown>';
context.pushError({
loc: place.loc,
description: `All uses of ${calleeName} must be either used with a fire() call in \
this effect or not used with a fire() call at all. ${calleeName} was used with fire() on line \
${printSourceLocationLine(calleeInfo.fireLoc)} in this effect`,
severity: ErrorSeverity.InvalidReact,
reason: CANNOT_COMPILE_FIRE,
suggestions: null,
});
}
}
}
function ensureNoMoreFireUses(fn: HIRFunction, context: Context): void {
for (const place of eachReachablePlace(fn)) {
if (
place.identifier.type.kind === 'Function' &&
place.identifier.type.shapeId === BuiltInFireId
) {
context.pushError({
loc: place.identifier.loc,
description: 'Cannot use `fire` outside of a useEffect function',
severity: ErrorSeverity.Invariant,
reason: CANNOT_COMPILE_FIRE,
suggestions: null,
});
}
}
}
function makeLoadUseFireInstruction(env: Environment): Instruction {
const useFirePlace = createTemporaryPlace(env, GeneratedSource);
useFirePlace.effect = Effect.Read;
useFirePlace.identifier.type = DefaultNonmutatingHook;
const instrValue: InstructionValue = {
kind: 'LoadGlobal',
binding: {
kind: 'ImportSpecifier',
name: 'useFire',
module: 'react',
imported: 'useFire',
},
loc: GeneratedSource,
};
return {
id: makeInstructionId(0),
value: instrValue,
lvalue: {...useFirePlace},
loc: GeneratedSource,
};
}
function makeLoadFireCalleeInstruction(
env: Environment,
fireCalleeIdentifier: Identifier,
): Instruction {
const loadedFireCallee = createTemporaryPlace(env, GeneratedSource);
const fireCallee: Place = {
kind: 'Identifier',
identifier: fireCalleeIdentifier,
reactive: false,
effect: Effect.Unknown,
loc: fireCalleeIdentifier.loc,
};
return {
id: makeInstructionId(0),
value: {
kind: 'LoadLocal',
loc: GeneratedSource,
place: {...fireCallee},
},
lvalue: {...loadedFireCallee},
loc: GeneratedSource,
};
}
function makeCallUseFireInstruction(
env: Environment,
useFirePlace: Place,
argPlace: Place,
): Instruction {
const useFireCallResultPlace = createTemporaryPlace(env, GeneratedSource);
useFireCallResultPlace.effect = Effect.Read;
const useFireCall: CallExpression = {
kind: 'CallExpression',
callee: {...useFirePlace},
args: [argPlace],
loc: GeneratedSource,
};
return {
id: makeInstructionId(0),
value: useFireCall,
lvalue: {...useFireCallResultPlace},
loc: GeneratedSource,
};
}
function makeStoreUseFireInstruction(
env: Environment,
useFireCallResultPlace: Place,
fireFunctionBindingPlace: Place,
): Instruction {
promoteTemporary(fireFunctionBindingPlace.identifier);
const fireFunctionBindingLValuePlace = createTemporaryPlace(
env,
GeneratedSource,
);
return {
id: makeInstructionId(0),
value: {
kind: 'StoreLocal',
lvalue: {
kind: InstructionKind.Const,
place: {...fireFunctionBindingPlace},
},
value: {...useFireCallResultPlace},
type: null,
loc: GeneratedSource,
},
lvalue: fireFunctionBindingLValuePlace,
loc: GeneratedSource,
};
}
type FireCalleesToFireFunctionBinding = Map<
IdentifierId,
{
fireFunctionBinding: Place;
capturedCalleeIdentifier: Identifier;
fireLoc: SourceLocation;
}
>;
class Context {
#env: Environment;
#errors: CompilerError = new CompilerError();
/*
* Used to look up the call expression passed to a `fire(callExpr())`. Gives back
* the `callExpr()`.
*/
#callExpressions = new Map<IdentifierId, CallExpression>();
/*
* We keep track of function expressions so that we can traverse them when
* we encounter a lambda passed to a useEffect call
*/
#functionExpressions = new Map<IdentifierId, FunctionExpression>();
/*
* Mapping from lvalue ids to the LoadLocal for it. Allows us to replace dependency LoadLocals.
*/
#loadLocals = new Map<IdentifierId, LoadLocal>();
/*
* Maps all of the fire callees found in a component/hook to the generated fire function places
* we create for them. Allows us to reuse already-inserted useFire results
*/
#fireCalleesToFireFunctions: Map<IdentifierId, Place> = new Map();
/*
* The callees for which we have already created fire bindings. Used to skip inserting a new
* useFire call for a fire callee if one has already been created.
*/
#calleesWithInsertedFire = new Set<IdentifierId>();
/*
* A mapping from fire callees to the created fire function bindings that are reachable from this
* scope.
*
* We additionally keep track of the captured callee identifier so that we can properly reference
* it in the place where we LoadLocal the callee as an argument to useFire.
*/
#capturedCalleeIdentifierIds: FireCalleesToFireFunctionBinding = new Map();
/*
* We only transform fire calls if we're syntactically within a useEffect lambda (for now)
*/
#inUseEffectLambda = false;
/*
* Mapping from useEffect callee identifier ids to the instruction id of the
* load global instruction for the useEffect call. We use this to insert the
* useFire calls before the useEffect call
*/
#loadGlobalInstructionIds = new Map<IdentifierId, InstructionId>();
constructor(env: Environment) {
this.#env = env;
}
/*
* We keep track of array expressions so we can rewrite dependency arrays passed to useEffect
* to use the fire functions
*/
#arrayExpressions = new Map<IdentifierId, ArrayExpression>();
pushError(error: CompilerErrorDetailOptions): void {
this.#errors.push(error);
}
withFunctionScope(fn: () => void): FireCalleesToFireFunctionBinding {
fn();
return this.#capturedCalleeIdentifierIds;
}
withUseEffectLambdaScope(fn: () => void): FireCalleesToFireFunctionBinding {
const capturedCalleeIdentifierIds = this.#capturedCalleeIdentifierIds;
const inUseEffectLambda = this.#inUseEffectLambda;
this.#capturedCalleeIdentifierIds = new Map();
this.#inUseEffectLambda = true;
const resultCapturedCalleeIdentifierIds = this.withFunctionScope(fn);
this.#capturedCalleeIdentifierIds = capturedCalleeIdentifierIds;
this.#inUseEffectLambda = inUseEffectLambda;
return resultCapturedCalleeIdentifierIds;
}
addCallExpression(id: IdentifierId, callExpr: CallExpression): void {
this.#callExpressions.set(id, callExpr);
}
getCallExpression(id: IdentifierId): CallExpression | undefined {
return this.#callExpressions.get(id);
}
addLoadLocalInstr(id: IdentifierId, loadLocal: LoadLocal): void {
this.#loadLocals.set(id, loadLocal);
}
getLoadLocalInstr(id: IdentifierId): LoadLocal | undefined {
return this.#loadLocals.get(id);
}
getOrGenerateFireFunctionBinding(
callee: Place,
fireLoc: SourceLocation,
): Place {
const fireFunctionBinding = getOrInsertWith(
this.#fireCalleesToFireFunctions,
callee.identifier.id,
() => createTemporaryPlace(this.#env, GeneratedSource),
);
this.#capturedCalleeIdentifierIds.set(callee.identifier.id, {
fireFunctionBinding,
capturedCalleeIdentifier: callee.identifier,
fireLoc,
});
return fireFunctionBinding;
}
mergeCalleesFromInnerScope(
innerCallees: FireCalleesToFireFunctionBinding,
): void {
for (const [id, calleeInfo] of innerCallees.entries()) {
this.#capturedCalleeIdentifierIds.set(id, calleeInfo);
}
}
addCalleeWithInsertedFire(id: IdentifierId): void {
this.#calleesWithInsertedFire.add(id);
}
hasCalleeWithInsertedFire(id: IdentifierId): boolean {
return this.#calleesWithInsertedFire.has(id);
}
inUseEffectLambda(): boolean {
return this.#inUseEffectLambda;
}
addFunctionExpression(id: IdentifierId, fn: FunctionExpression): void {
this.#functionExpressions.set(id, fn);
}
getFunctionExpression(id: IdentifierId): FunctionExpression | undefined {
return this.#functionExpressions.get(id);
}
addLoadGlobalInstrId(id: IdentifierId, instrId: InstructionId): void {
this.#loadGlobalInstructionIds.set(id, instrId);
}
getLoadGlobalInstrId(id: IdentifierId): InstructionId | undefined {
return this.#loadGlobalInstructionIds.get(id);
}
addArrayExpression(id: IdentifierId, array: ArrayExpression): void {
this.#arrayExpressions.set(id, array);
}
getArrayExpression(id: IdentifierId): ArrayExpression | undefined {
return this.#arrayExpressions.get(id);
}
hasErrors(): boolean {
return this.#errors.hasErrors();
}
throwIfErrorsFound(): void {
if (this.hasErrors()) throw this.#errors;
}
}
function deleteInstructions(
deleteInstrs: Set<InstructionId>,
instructions: Array<Instruction>,
): Array<Instruction> {
if (deleteInstrs.size > 0) {
const newInstrs = instructions.filter(instr => !deleteInstrs.has(instr.id));
return newInstrs;
}
return instructions;
}
function rewriteInstructions(
rewriteInstrs: Map<InstructionId, Array<Instruction>>,
instructions: Array<Instruction>,
): Array<Instruction> {
if (rewriteInstrs.size > 0) {
const newInstrs = [];
for (const instr of instructions) {
const newInstrsAtId = rewriteInstrs.get(instr.id);
if (newInstrsAtId != null) {
newInstrs.push(...newInstrsAtId, instr);
} else {
newInstrs.push(instr);
}
}
return newInstrs;
}
return instructions;
}
@@ -0,0 +1,7 @@
/**
* 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.
*/
export {transformFire} from './TransformFire';
@@ -305,6 +305,14 @@ function validateNoRefAccessInRenderImpl(
);
break;
}
case 'TypeCastExpression': {
env.set(
instr.lvalue.identifier.id,
env.get(instr.value.value.identifier.id) ??
refTypeOfType(instr.lvalue),
);
break;
}
case 'LoadContext':
case 'LoadLocal': {
env.set(
@@ -0,0 +1,60 @@
## Input
```javascript
import {useRef} from 'react';
function useArrayOfRef() {
const ref = useRef(null);
const callback = value => {
ref.current = value;
};
return [callback] as const;
}
export const FIXTURE_ENTRYPOINT = {
fn: () => {
useArrayOfRef();
return 'ok';
},
params: [{}],
};
```
## Code
```javascript
import { c as _c } from "react/compiler-runtime";
import { useRef } from "react";
function useArrayOfRef() {
const $ = _c(1);
const ref = useRef(null);
let t0;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
const callback = (value) => {
ref.current = value;
};
t0 = [callback];
$[0] = t0;
} else {
t0 = $[0];
}
return t0 as const;
}
export const FIXTURE_ENTRYPOINT = {
fn: () => {
useArrayOfRef();
return "ok";
},
params: [{}],
};
```
### Eval output
(kind: ok) "ok"
@@ -0,0 +1,17 @@
import {useRef} from 'react';
function useArrayOfRef() {
const ref = useRef(null);
const callback = value => {
ref.current = value;
};
return [callback] as const;
}
export const FIXTURE_ENTRYPOINT = {
fn: () => {
useArrayOfRef();
return 'ok';
},
params: [{}],
};
@@ -0,0 +1,53 @@
## Input
```javascript
// @enableFire
import {fire} from 'react';
function Component(props) {
const foo = props => {
console.log(props);
};
useEffect(() => {
fire(foo(props));
});
return null;
}
```
## Code
```javascript
import { useFire } from "react/compiler-runtime";
import { c as _c } from "react/compiler-runtime"; // @enableFire
import { fire } from "react";
function Component(props) {
const $ = _c(3);
const foo = _temp;
const t0 = useFire(foo);
let t1;
if ($[0] !== props || $[1] !== t0) {
t1 = () => {
t0(props);
};
$[0] = props;
$[1] = t0;
$[2] = t1;
} else {
t1 = $[2];
}
useEffect(t1);
return null;
}
function _temp(props_0) {
console.log(props_0);
}
```
### Eval output
(kind: exception) Fixture not implemented
@@ -0,0 +1,13 @@
// @enableFire
import {fire} from 'react';
function Component(props) {
const foo = props => {
console.log(props);
};
useEffect(() => {
fire(foo(props));
});
return null;
}
@@ -0,0 +1,74 @@
## Input
```javascript
// @enableFire
import {fire} from 'react';
function Component(props) {
const foo = props => {
console.log(props);
};
useEffect(() => {
function nested() {
function nestedAgain() {
function nestedThrice() {
fire(foo(props));
}
nestedThrice();
}
nestedAgain();
}
nested();
});
return null;
}
```
## Code
```javascript
import { useFire } from "react/compiler-runtime";
import { c as _c } from "react/compiler-runtime"; // @enableFire
import { fire } from "react";
function Component(props) {
const $ = _c(3);
const foo = _temp;
const t0 = useFire(foo);
let t1;
if ($[0] !== props || $[1] !== t0) {
t1 = () => {
const nested = function nested() {
const nestedAgain = function nestedAgain() {
const nestedThrice = function nestedThrice() {
t0(props);
};
nestedThrice();
};
nestedAgain();
};
nested();
};
$[0] = props;
$[1] = t0;
$[2] = t1;
} else {
t1 = $[2];
}
useEffect(t1);
return null;
}
function _temp(props_0) {
console.log(props_0);
}
```
### Eval output
(kind: exception) Fixture not implemented
@@ -0,0 +1,22 @@
// @enableFire
import {fire} from 'react';
function Component(props) {
const foo = props => {
console.log(props);
};
useEffect(() => {
function nested() {
function nestedAgain() {
function nestedThrice() {
fire(foo(props));
}
nestedThrice();
}
nestedAgain();
}
nested();
});
return null;
}
@@ -0,0 +1,37 @@
## Input
```javascript
// @enableFire
import {fire, useEffect} from 'react';
function Component(props) {
const foo = props => {
console.log(props);
};
if (props.cond) {
useEffect(() => {
fire(foo(props));
});
}
return null;
}
```
## Error
```
8 |
9 | if (props.cond) {
> 10 | useEffect(() => {
| ^^^^^^^^^ InvalidReact: Hooks must always be called in a consistent order, and may not be called conditionally. See the Rules of Hooks (https://react.dev/warnings/invalid-hook-call-warning) (10:10)
11 | fire(foo(props));
12 | });
13 | }
```
@@ -0,0 +1,16 @@
// @enableFire
import {fire, useEffect} from 'react';
function Component(props) {
const foo = props => {
console.log(props);
};
if (props.cond) {
useEffect(() => {
fire(foo(props));
});
}
return null;
}
@@ -0,0 +1,39 @@
## Input
```javascript
// @enableFire
import {fire} from 'react';
function Component(props) {
const foo = props => {
console.log(props);
};
useEffect(() => {
function nested() {
fire(foo(props));
foo(props);
}
nested();
});
return null;
}
```
## Error
```
9 | function nested() {
10 | fire(foo(props));
> 11 | foo(props);
| ^^^ InvalidReact: Cannot compile `fire`. All uses of foo must be either used with a fire() call in this effect or not used with a fire() call at all. foo was used with fire() on line 10:10 in this effect (11:11)
12 | }
13 |
14 | nested();
```
@@ -0,0 +1,18 @@
// @enableFire
import {fire} from 'react';
function Component(props) {
const foo = props => {
console.log(props);
};
useEffect(() => {
function nested() {
fire(foo(props));
foo(props);
}
nested();
});
return null;
}
@@ -0,0 +1,34 @@
## Input
```javascript
// @enableFire
import {fire} from 'react';
function Component({bar, baz}) {
const foo = () => {
console.log(bar, baz);
};
useEffect(() => {
fire(foo(bar), baz);
});
return null;
}
```
## Error
```
7 | };
8 | useEffect(() => {
> 9 | fire(foo(bar), baz);
| ^^^^^^^^^^^^^^^^^^^ InvalidReact: Cannot compile `fire`. fire() can only take in a single call expression as an argument but received multiple arguments (9:9)
10 | });
11 |
12 | return null;
```
@@ -0,0 +1,13 @@
// @enableFire
import {fire} from 'react';
function Component({bar, baz}) {
const foo = () => {
console.log(bar, baz);
};
useEffect(() => {
fire(foo(bar), baz);
});
return null;
}
@@ -0,0 +1,40 @@
## Input
```javascript
// @enable
import {fire} from 'react';
function Component(props) {
const foo = props => {
console.log(props);
};
useEffect(() => {
useEffect(() => {
function nested() {
fire(foo(props));
}
nested();
});
});
return null;
}
```
## Error
```
7 | };
8 | useEffect(() => {
> 9 | useEffect(() => {
| ^^^^^^^^^ InvalidReact: Hooks must be called at the top level in the body of a function component or custom hook, and may not be called within function expressions. See the Rules of Hooks (https://react.dev/warnings/invalid-hook-call-warning). Cannot call useEffect within a function component (9:9)
10 | function nested() {
11 | fire(foo(props));
12 | }
```
@@ -0,0 +1,19 @@
// @enable
import {fire} from 'react';
function Component(props) {
const foo = props => {
console.log(props);
};
useEffect(() => {
useEffect(() => {
function nested() {
fire(foo(props));
}
nested();
});
});
return null;
}
@@ -0,0 +1,34 @@
## Input
```javascript
// @enableFire
import {fire} from 'react';
function Component(props) {
const foo = () => {
console.log(props);
};
useEffect(() => {
fire(props);
});
return null;
}
```
## Error
```
7 | };
8 | useEffect(() => {
> 9 | fire(props);
| ^^^^^^^^^^^ InvalidReact: Cannot compile `fire`. `fire()` can only receive a function call such as `fire(fn(a,b)). Method calls and other expressions are not allowed (9:9)
10 | });
11 |
12 | return null;
```
@@ -0,0 +1,13 @@
// @enableFire
import {fire} from 'react';
function Component(props) {
const foo = () => {
console.log(props);
};
useEffect(() => {
fire(props);
});
return null;
}
@@ -0,0 +1,38 @@
## Input
```javascript
// @enableFire
import {fire, useCallback} from 'react';
function Component({props, bar}) {
const foo = () => {
console.log(props);
};
fire(foo(props));
useCallback(() => {
fire(foo(props));
}, [foo, props]);
return null;
}
```
## Error
```
6 | console.log(props);
7 | };
> 8 | fire(foo(props));
| ^^^^ Invariant: Cannot compile `fire`. Cannot use `fire` outside of a useEffect function (8:8)
Invariant: Cannot compile `fire`. Cannot use `fire` outside of a useEffect function (11:11)
9 |
10 | useCallback(() => {
11 | fire(foo(props));
```
@@ -0,0 +1,15 @@
// @enableFire
import {fire, useCallback} from 'react';
function Component({props, bar}) {
const foo = () => {
console.log(props);
};
fire(foo(props));
useCallback(() => {
fire(foo(props));
}, [foo, props]);
return null;
}
@@ -0,0 +1,37 @@
## Input
```javascript
// @enableFire
import {fire} from 'react';
function Component(props) {
const foo = props => {
console.log(props);
};
const deps = [foo, props];
useEffect(() => {
fire(foo(props));
}, deps);
return null;
}
```
## Error
```
11 | useEffect(() => {
12 | fire(foo(props));
> 13 | }, deps);
| ^^^^ Invariant: Cannot compile `fire`. You must use an array literal for an effect dependency array when that effect uses `fire()` (13:13)
14 |
15 | return null;
16 | }
```
@@ -0,0 +1,16 @@
// @enableFire
import {fire} from 'react';
function Component(props) {
const foo = props => {
console.log(props);
};
const deps = [foo, props];
useEffect(() => {
fire(foo(props));
}, deps);
return null;
}
@@ -0,0 +1,37 @@
## Input
```javascript
// @enableFire
import {fire} from 'react';
function Component(props) {
const foo = props => {
console.log(props);
};
const deps = [foo, props];
useEffect(() => {
fire(foo(props));
}, ...deps);
return null;
}
```
## Error
```
11 | useEffect(() => {
12 | fire(foo(props));
> 13 | }, ...deps);
| ^^^^ Invariant: Cannot compile `fire`. You must use an array literal for an effect dependency array when that effect uses `fire()` (13:13)
14 |
15 | return null;
16 | }
```
@@ -0,0 +1,19 @@
// @enableFire
import {fire} from 'react';
function Component(props) {
const foo = props => {
console.log(props);
};
const deps = [foo, props];
useEffect(
() => {
fire(foo(props));
},
...deps
);
return null;
}
@@ -0,0 +1,34 @@
## Input
```javascript
// @enableFire
import {fire} from 'react';
function Component(props) {
const foo = () => {
console.log(props);
};
useEffect(() => {
fire(...foo);
});
return null;
}
```
## Error
```
7 | };
8 | useEffect(() => {
> 9 | fire(...foo);
| ^^^^^^^^^^^^ InvalidReact: Cannot compile `fire`. fire() can only take in a single call expression as an argument but received a spread argument (9:9)
10 | });
11 |
12 | return null;
```
@@ -0,0 +1,13 @@
// @enableFire
import {fire} from 'react';
function Component(props) {
const foo = () => {
console.log(props);
};
useEffect(() => {
fire(...foo);
});
return null;
}
@@ -0,0 +1,34 @@
## Input
```javascript
// @enableFire
import {fire} from 'react';
function Component(props) {
const foo = () => {
console.log(props);
};
useEffect(() => {
fire(props.foo());
});
return null;
}
```
## Error
```
7 | };
8 | useEffect(() => {
> 9 | fire(props.foo());
| ^^^^^^^^^^^^^^^^^ InvalidReact: Cannot compile `fire`. `fire()` can only receive a function call such as `fire(fn(a,b)). Method calls and other expressions are not allowed (9:9)
10 | });
11 |
12 | return null;
```
@@ -0,0 +1,13 @@
// @enableFire
import {fire} from 'react';
function Component(props) {
const foo = () => {
console.log(props);
};
useEffect(() => {
fire(props.foo());
});
return null;
}
@@ -0,0 +1,60 @@
## Input
```javascript
// @enableFire @inferEffectDependencies
import {fire, useEffect} from 'react';
function Component(props) {
const foo = arg => {
console.log(arg, props.bar);
};
useEffect(() => {
fire(foo(props));
});
return null;
}
```
## Code
```javascript
import { useFire } from "react/compiler-runtime";
import { c as _c } from "react/compiler-runtime"; // @enableFire @inferEffectDependencies
import { fire, useEffect } from "react";
function Component(props) {
const $ = _c(5);
let t0;
if ($[0] !== props.bar) {
t0 = (arg) => {
console.log(arg, props.bar);
};
$[0] = props.bar;
$[1] = t0;
} else {
t0 = $[1];
}
const foo = t0;
const t1 = useFire(foo);
let t2;
if ($[2] !== props || $[3] !== t1) {
t2 = () => {
t1(props);
};
$[2] = props;
$[3] = t1;
$[4] = t2;
} else {
t2 = $[4];
}
useEffect(t2, [t1, props]);
return null;
}
```
### Eval output
(kind: exception) Fixture not implemented
@@ -0,0 +1,13 @@
// @enableFire @inferEffectDependencies
import {fire, useEffect} from 'react';
function Component(props) {
const foo = arg => {
console.log(arg, props.bar);
};
useEffect(() => {
fire(foo(props));
});
return null;
}
@@ -0,0 +1,66 @@
## Input
```javascript
// @enableFire
import {fire} from 'react';
function Component(props) {
const foo = props => {
console.log(props);
};
useEffect(() => {
fire(foo(props));
function nested() {
fire(foo(props));
function innerNested() {
fire(foo(props));
}
}
nested();
});
return null;
}
```
## Code
```javascript
import { useFire } from "react/compiler-runtime";
import { c as _c } from "react/compiler-runtime"; // @enableFire
import { fire } from "react";
function Component(props) {
const $ = _c(3);
const foo = _temp;
const t0 = useFire(foo);
let t1;
if ($[0] !== props || $[1] !== t0) {
t1 = () => {
t0(props);
const nested = function nested() {
t0(props);
};
nested();
};
$[0] = props;
$[1] = t0;
$[2] = t1;
} else {
t1 = $[2];
}
useEffect(t1);
return null;
}
function _temp(props_0) {
console.log(props_0);
}
```
### Eval output
(kind: exception) Fixture not implemented
@@ -0,0 +1,21 @@
// @enableFire
import {fire} from 'react';
function Component(props) {
const foo = props => {
console.log(props);
};
useEffect(() => {
fire(foo(props));
function nested() {
fire(foo(props));
function innerNested() {
fire(foo(props));
}
}
nested();
});
return null;
}
@@ -0,0 +1,62 @@
## Input
```javascript
// @enableFire
import {fire} from 'react';
function Component(props) {
const foo = () => {
console.log(props);
};
useEffect(() => {
fire(foo(props));
fire(foo(props));
});
return null;
}
```
## Code
```javascript
import { useFire } from "react/compiler-runtime";
import { c as _c } from "react/compiler-runtime"; // @enableFire
import { fire } from "react";
function Component(props) {
const $ = _c(5);
let t0;
if ($[0] !== props) {
t0 = () => {
console.log(props);
};
$[0] = props;
$[1] = t0;
} else {
t0 = $[1];
}
const foo = t0;
const t1 = useFire(foo);
let t2;
if ($[2] !== props || $[3] !== t1) {
t2 = () => {
t1(props);
t1(props);
};
$[2] = props;
$[3] = t1;
$[4] = t2;
} else {
t2 = $[4];
}
useEffect(t2);
return null;
}
```
### Eval output
(kind: exception) Fixture not implemented
@@ -0,0 +1,14 @@
// @enableFire
import {fire} from 'react';
function Component(props) {
const foo = () => {
console.log(props);
};
useEffect(() => {
fire(foo(props));
fire(foo(props));
});
return null;
}
@@ -0,0 +1,57 @@
## Input
```javascript
// @enableFire
import {fire} from 'react';
function Component(props) {
const foo = props => {
console.log(props);
};
useEffect(() => {
fire(foo(props));
}, [foo, props]);
return null;
}
```
## Code
```javascript
import { useFire } from "react/compiler-runtime";
import { c as _c } from "react/compiler-runtime"; // @enableFire
import { fire } from "react";
function Component(props) {
const $ = _c(4);
const foo = _temp;
const t0 = useFire(foo);
let t1;
let t2;
if ($[0] !== props || $[1] !== t0) {
t1 = () => {
t0(props);
};
t2 = [t0, props];
$[0] = props;
$[1] = t0;
$[2] = t1;
$[3] = t2;
} else {
t1 = $[2];
t2 = $[3];
}
useEffect(t1, t2);
return null;
}
function _temp(props_0) {
console.log(props_0);
}
```
### Eval output
(kind: exception) Fixture not implemented
@@ -0,0 +1,13 @@
// @enableFire
import {fire} from 'react';
function Component(props) {
const foo = props => {
console.log(props);
};
useEffect(() => {
fire(foo(props));
}, [foo, props]);
return null;
}
@@ -0,0 +1,81 @@
## Input
```javascript
// @enableFire
import {fire} from 'react';
function Component({bar, baz}) {
const foo = () => {
console.log(bar);
};
useEffect(() => {
fire(foo(bar));
fire(baz(bar));
});
useEffect(() => {
fire(foo(bar));
});
return null;
}
```
## Code
```javascript
import { useFire } from "react/compiler-runtime";
import { c as _c } from "react/compiler-runtime"; // @enableFire
import { fire } from "react";
function Component(t0) {
const $ = _c(9);
const { bar, baz } = t0;
let t1;
if ($[0] !== bar) {
t1 = () => {
console.log(bar);
};
$[0] = bar;
$[1] = t1;
} else {
t1 = $[1];
}
const foo = t1;
const t2 = useFire(foo);
const t3 = useFire(baz);
let t4;
if ($[2] !== bar || $[3] !== t2 || $[4] !== t3) {
t4 = () => {
t2(bar);
t3(bar);
};
$[2] = bar;
$[3] = t2;
$[4] = t3;
$[5] = t4;
} else {
t4 = $[5];
}
useEffect(t4);
let t5;
if ($[6] !== bar || $[7] !== t2) {
t5 = () => {
t2(bar);
};
$[6] = bar;
$[7] = t2;
$[8] = t5;
} else {
t5 = $[8];
}
useEffect(t5);
return null;
}
```
### Eval output
(kind: exception) Fixture not implemented
@@ -0,0 +1,18 @@
// @enableFire
import {fire} from 'react';
function Component({bar, baz}) {
const foo = () => {
console.log(bar);
};
useEffect(() => {
fire(foo(bar));
fire(baz(bar));
});
useEffect(() => {
fire(foo(bar));
});
return null;
}
@@ -0,0 +1,30 @@
## Input
```javascript
// @enableFire
import {fire} from 'react';
function Component(props) {
useEffect();
return null;
}
```
## Code
```javascript
// @enableFire
import { fire } from "react";
function Component(props) {
useEffect();
return null;
}
```
### Eval output
(kind: exception) Fixture not implemented
@@ -0,0 +1,8 @@
// @enableFire
import {fire} from 'react';
function Component(props) {
useEffect();
return null;
}
@@ -29,6 +29,7 @@ const DEV_ROLLUP_CONFIG = {
file: 'dist/index.js',
format: 'cjs',
sourcemap: false,
inlineDynamicImports: true,
},
treeshake: {
moduleSideEffects: false,
@@ -33,6 +33,7 @@ const DEV_ROLLUP_CONFIG = {
format: 'cjs',
sourcemap: false,
exports: 'named',
inlineDynamicImports: true,
},
plugins: [
typescript({
@@ -9,7 +9,7 @@
"src"
],
"peerDependencies": {
"react": "^17.0.0 || ^18.0.0 || ^19.0.0"
"react": "^17.0.0 || ^18.0.0 || ^19.0.0 || ^0.0.0-experimental"
},
"scripts": {
"build": "rimraf dist && rollup --config --bundleConfigAsCjs",
@@ -21,6 +21,7 @@ const PROD_ROLLUP_CONFIG = {
file: 'dist/index.js',
format: 'cjs',
sourcemap: true,
inlineDynamicImports: true,
},
plugins: [
typescript({
@@ -0,0 +1,3 @@
**/node_modules
client
server
+1
View File
@@ -0,0 +1 @@
ignore-engines true
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) Meta Platforms, Inc. and affiliates.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
@@ -0,0 +1,22 @@
{
"private": "true",
"name": "react-forgive-client",
"version": "0.0.0",
"description": "Experimental LSP client",
"license": "MIT",
"scripts": {
"build": "echo 'no build'",
"test": "echo 'no tests'"
},
"repository": {
"type": "git",
"url": "git+https://github.com/facebook/react.git",
"directory": "compiler/packages/react-forgive"
},
"dependencies": {
"vscode-languageclient": "^9.0.1"
},
"devDependencies": {
"@types/vscode": "^1.95.0"
}
}
@@ -0,0 +1,62 @@
import * as path from 'path';
import {ExtensionContext, window as Window} from 'vscode';
import {
LanguageClient,
LanguageClientOptions,
ServerOptions,
TransportKind,
} from 'vscode-languageclient/node';
let client: LanguageClient;
export function activate(context: ExtensionContext) {
const serverModule = context.asAbsolutePath(path.join('dist', 'server.js'));
// If the extension is launched in debug mode then the debug server options are used
// Otherwise the run options are used
const serverOptions: ServerOptions = {
run: {
module: serverModule,
transport: TransportKind.ipc,
options: {cwd: process.cwd()},
},
debug: {
module: serverModule,
transport: TransportKind.ipc,
options: {cwd: process.cwd()},
},
};
const clientOptions: LanguageClientOptions = {
documentSelector: [
{scheme: 'file', language: 'javascriptreact'},
{scheme: 'file', language: 'typescriptreact'},
],
progressOnInitialization: true,
};
// Create the language client and start the client.
try {
client = new LanguageClient(
'react-forgive',
'React Analyzer',
serverOptions,
clientOptions,
);
} catch {
Window.showErrorMessage(
`React Analyzer couldn't be started. See the output channel for details.`,
);
return;
}
client.registerProposedFeatures();
client.start();
}
export function deactivate(): Thenable<void> | undefined {
if (client !== undefined) {
return client.stop();
}
}
@@ -0,0 +1,59 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@types/vscode@^1.95.0":
version "1.96.0"
resolved "https://registry.yarnpkg.com/@types/vscode/-/vscode-1.96.0.tgz#3181004bf25d71677ae4aacdd7605a3fd7edf08e"
integrity sha512-qvZbSZo+K4ZYmmDuaodMbAa67Pl6VDQzLKFka6rq+3WUTY4Kro7Bwoi0CuZLO/wema0ygcmpwow7zZfPJTs5jg==
balanced-match@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
brace-expansion@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae"
integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==
dependencies:
balanced-match "^1.0.0"
minimatch@^5.1.0:
version "5.1.6"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96"
integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==
dependencies:
brace-expansion "^2.0.1"
semver@^7.3.7:
version "7.6.3"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143"
integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==
vscode-jsonrpc@8.2.0:
version "8.2.0"
resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz#f43dfa35fb51e763d17cd94dcca0c9458f35abf9"
integrity sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==
vscode-languageclient@^9.0.1:
version "9.0.1"
resolved "https://registry.yarnpkg.com/vscode-languageclient/-/vscode-languageclient-9.0.1.tgz#cdfe20267726c8d4db839dc1e9d1816e1296e854"
integrity sha512-JZiimVdvimEuHh5olxhxkht09m3JzUGwggb5eRUkzzJhZ2KjCN0nh55VfiED9oez9DyF8/fz1g1iBV3h+0Z2EA==
dependencies:
minimatch "^5.1.0"
semver "^7.3.7"
vscode-languageserver-protocol "3.17.5"
vscode-languageserver-protocol@3.17.5:
version "3.17.5"
resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz#864a8b8f390835572f4e13bd9f8313d0e3ac4bea"
integrity sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==
dependencies:
vscode-jsonrpc "8.2.0"
vscode-languageserver-types "3.17.5"
vscode-languageserver-types@3.17.5:
version "3.17.5"
resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz#3273676f0cf2eab40b3f44d085acbb7f08a39d8a"
integrity sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==
@@ -0,0 +1,58 @@
{
"name": "react-forgive",
"displayName": "React Analyzer",
"description": "React LSP",
"license": "MIT",
"version": "0.0.0",
"repository": {
"type": "git",
"url": "git+https://github.com/facebook/react.git",
"directory": "compiler/packages/react-forgive"
},
"categories": [
"Programming Languages"
],
"keywords": [
"react",
"react analyzer",
"react compiler"
],
"publisher": "Meta",
"engines": {
"vscode": "^1.75.0"
},
"activationEvents": [
"onLanguage:javascriptreact",
"onLanguage:typescriptreact"
],
"main": "./dist/extension.js",
"contributes": {
"commands": [
{
"command": "react-forgive.toggleAll",
"title": "React Analyzer: Toggle on/off"
}
]
},
"scripts": {
"compile": "rimraf dist && concurrently -n server,client \"yarn run esbuild:server --sourcemap\" \"yarn run esbuild:client --sourcemap\"",
"dev": "yarn run package && yarn run install-ext",
"esbuild:client": "esbuild ./client/src/extension.ts --bundle --outfile=dist/extension.js --external:vscode --format=cjs --platform=node",
"esbuild:server": "esbuild ./server/src/index.ts --bundle --outfile=dist/server.js --external:vscode --format=cjs --platform=node",
"install-ext": "code --install-extension react-forgive-0.0.0.vsix",
"lint": "eslint src --ext ts",
"package": "rm -f react-forgive-0.0.0.vsix && vsce package --yarn",
"postinstall": "cd client && yarn install && cd ../server && yarn install && cd ..",
"pretest": "yarn run compile && yarn run lint",
"test": "vscode-test",
"vscode:prepublish": "yarn run compile",
"watch": "concurrently --kill-others -n server,client \"run esbuild:server --sourcemap --watch\" \"run esbuild:client --sourcemap --watch\""
},
"devDependencies": {
"@eslint/js": "^9.13.0",
"@types/node": "^20",
"esbuild": "^0.24.0",
"eslint": "^9.13.0",
"typescript-eslint": "^8.16.0"
}
}
@@ -0,0 +1,27 @@
{
"private": "true",
"name": "react-forgive-server",
"version": "0.0.0",
"description": "Experimental LSP server",
"license": "MIT",
"main": "dist/index.js",
"scripts": {
"build": "rimraf dist && rollup --config --bundleConfigAsCjs",
"test": "echo 'no tests'"
},
"repository": {
"type": "git",
"url": "git+https://github.com/facebook/react.git",
"directory": "compiler/packages/react-forgive"
},
"dependencies": {
"@babel/core": "^7.26.0",
"@babel/parser": "^7.26.0",
"@babel/plugin-syntax-typescript": "^7.25.9",
"@babel/types": "^7.26.0",
"cosmiconfig": "^9.0.0",
"prettier": "^3.3.3",
"vscode-languageserver": "^9.0.1",
"vscode-languageserver-textdocument": "^1.0.12"
}
}
@@ -0,0 +1,58 @@
/**
* 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 type * as BabelCore from '@babel/core';
import {parseAsync, transformFromAstAsync} from '@babel/core';
import BabelPluginReactCompiler, {
type PluginOptions,
} from 'babel-plugin-react-compiler/src';
import * as babelParser from 'prettier/plugins/babel.js';
import estreeParser from 'prettier/plugins/estree';
import * as typescriptParser from 'prettier/plugins/typescript';
import * as prettier from 'prettier/standalone';
type CompileOptions = {
text: string;
file: string;
options: PluginOptions | null;
};
export async function compile({
text,
file,
options,
}: CompileOptions): Promise<BabelCore.BabelFileResult> {
const ast = await parseAsync(text, {
sourceFileName: file,
parserOpts: {
plugins: ['typescript', 'jsx'],
},
sourceType: 'module',
});
const plugins =
options != null
? [[BabelPluginReactCompiler, options]]
: [[BabelPluginReactCompiler]];
const result = await transformFromAstAsync(ast, text, {
filename: file,
highlightCode: false,
retainLines: true,
plugins,
sourceType: 'module',
sourceFileName: file,
});
if (result?.code == null) {
throw new Error(
`Expected BabelPluginReactCompiler to compile successfully, got ${result}`,
);
}
result.code = await prettier.format(result.code, {
semi: false,
parser: 'babel-ts',
plugins: [babelParser, estreeParser, typescriptParser],
});
return result;
}
@@ -0,0 +1,25 @@
/**
* 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 {
parsePluginOptions,
type PluginOptions,
} from 'babel-plugin-react-compiler/src';
import {cosmiconfigSync} from 'cosmiconfig';
export function resolveReactConfig(projectPath: string): PluginOptions | null {
const explorerSync = cosmiconfigSync('react', {
searchStrategy: 'project',
cache: true,
});
const result = explorerSync.search(projectPath);
if (result != null) {
return parsePluginOptions(result.config);
} else {
return null;
}
}
@@ -0,0 +1,93 @@
/**
* 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 {TextDocument} from 'vscode-languageserver-textdocument';
import {
createConnection,
type InitializeParams,
type InitializeResult,
ProposedFeatures,
TextDocuments,
TextDocumentSyncKind,
} from 'vscode-languageserver/node';
import {compile} from './compiler';
import {type PluginOptions} from 'babel-plugin-react-compiler/src';
import {resolveReactConfig} from './compiler/options';
const SUPPORTED_LANGUAGE_IDS = new Set([
'javascript',
'javascriptreact',
'typescript',
'typescriptreact',
]);
const connection = createConnection(ProposedFeatures.all);
connection.console.info(`React Analyzer running in node ${process.version}`);
const compiledCache = new WeakMap<TextDocument, string>();
const documents = new TextDocuments(TextDocument);
documents.listen(connection);
let compilerOptions: PluginOptions | null = null;
connection.onInitialize((_params: InitializeParams) => {
// TODO(@poteto) get config fr
compilerOptions = resolveReactConfig('.');
const result: InitializeResult = {
capabilities: {
textDocumentSync: TextDocumentSyncKind.Full,
codeLensProvider: {resolveProvider: true},
},
};
return result;
});
connection.onInitialized(() => {
connection.console.log('initialized');
});
documents.onDidOpen(async event => {
if (SUPPORTED_LANGUAGE_IDS.has(event.document.languageId)) {
const result = await compile({
text: event.document.getText(),
file: event.document.uri,
options: compilerOptions,
});
if (result.code != null) {
compiledCache.set(event.document, result.code);
connection.console.log(result.code);
}
}
});
documents.onDidChangeContent(async event => {
if (SUPPORTED_LANGUAGE_IDS.has(event.document.languageId)) {
const result = await compile({
text: event.document.getText(),
file: event.document.uri,
options: compilerOptions,
});
if (result.code != null) {
compiledCache.set(event.document, result.code);
connection.console.log(result.code);
}
}
});
connection.onDidChangeWatchedFiles(change => {
connection.console.log(
change.changes.map(c => `File changed: ${c.uri}`).join('\n'),
);
});
connection.onCodeLens(params => {
connection.console.log(JSON.stringify(params, null, 2));
return [];
});
connection.listen();
@@ -0,0 +1,17 @@
{
"extends": "@tsconfig/strictest/tsconfig.json",
"compilerOptions": {
"module": "ES2015",
"moduleResolution": "Bundler",
"rootDir": "../../..",
"noEmit": true,
"jsx": "react-jsxdev",
"target": "ES2015",
"sourceMap": false,
"removeComments": true,
"strictNullChecks": false
},
"exclude": ["node_modules", ".vscode-test"],
"include": ["src/**/*.ts"]
}
@@ -0,0 +1,410 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@ampproject/remapping@^2.2.0":
version "2.3.0"
resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.3.0.tgz#ed441b6fa600072520ce18b43d2c8cc8caecc7f4"
integrity sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==
dependencies:
"@jridgewell/gen-mapping" "^0.3.5"
"@jridgewell/trace-mapping" "^0.3.24"
"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.25.9", "@babel/code-frame@^7.26.0", "@babel/code-frame@^7.26.2":
version "7.26.2"
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.26.2.tgz#4b5fab97d33338eff916235055f0ebc21e573a85"
integrity sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==
dependencies:
"@babel/helper-validator-identifier" "^7.25.9"
js-tokens "^4.0.0"
picocolors "^1.0.0"
"@babel/compat-data@^7.25.9":
version "7.26.3"
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.26.3.tgz#99488264a56b2aded63983abd6a417f03b92ed02"
integrity sha512-nHIxvKPniQXpmQLb0vhY3VaFb3S0YrTAwpOWJZh1wn3oJPjJk9Asva204PsBdmAE8vpzfHudT8DB0scYvy9q0g==
"@babel/core@^7.26.0":
version "7.26.0"
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.26.0.tgz#d78b6023cc8f3114ccf049eb219613f74a747b40"
integrity sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==
dependencies:
"@ampproject/remapping" "^2.2.0"
"@babel/code-frame" "^7.26.0"
"@babel/generator" "^7.26.0"
"@babel/helper-compilation-targets" "^7.25.9"
"@babel/helper-module-transforms" "^7.26.0"
"@babel/helpers" "^7.26.0"
"@babel/parser" "^7.26.0"
"@babel/template" "^7.25.9"
"@babel/traverse" "^7.25.9"
"@babel/types" "^7.26.0"
convert-source-map "^2.0.0"
debug "^4.1.0"
gensync "^1.0.0-beta.2"
json5 "^2.2.3"
semver "^6.3.1"
"@babel/generator@^7.26.0", "@babel/generator@^7.26.3":
version "7.26.3"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.26.3.tgz#ab8d4360544a425c90c248df7059881f4b2ce019"
integrity sha512-6FF/urZvD0sTeO7k6/B15pMLC4CHUv1426lzr3N01aHJTl046uCAh9LXW/fzeXXjPNCJ6iABW5XaWOsIZB93aQ==
dependencies:
"@babel/parser" "^7.26.3"
"@babel/types" "^7.26.3"
"@jridgewell/gen-mapping" "^0.3.5"
"@jridgewell/trace-mapping" "^0.3.25"
jsesc "^3.0.2"
"@babel/helper-compilation-targets@^7.25.9":
version "7.25.9"
resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.9.tgz#55af025ce365be3cdc0c1c1e56c6af617ce88875"
integrity sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ==
dependencies:
"@babel/compat-data" "^7.25.9"
"@babel/helper-validator-option" "^7.25.9"
browserslist "^4.24.0"
lru-cache "^5.1.1"
semver "^6.3.1"
"@babel/helper-module-imports@^7.25.9":
version "7.25.9"
resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz#e7f8d20602ebdbf9ebbea0a0751fb0f2a4141715"
integrity sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==
dependencies:
"@babel/traverse" "^7.25.9"
"@babel/types" "^7.25.9"
"@babel/helper-module-transforms@^7.26.0":
version "7.26.0"
resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz#8ce54ec9d592695e58d84cd884b7b5c6a2fdeeae"
integrity sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==
dependencies:
"@babel/helper-module-imports" "^7.25.9"
"@babel/helper-validator-identifier" "^7.25.9"
"@babel/traverse" "^7.25.9"
"@babel/helper-plugin-utils@^7.25.9":
version "7.25.9"
resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.9.tgz#9cbdd63a9443a2c92a725cca7ebca12cc8dd9f46"
integrity sha512-kSMlyUVdWe25rEsRGviIgOWnoT/nfABVWlqt9N19/dIPWViAOW2s9wznP5tURbs/IDuNk4gPy3YdYRgH3uxhBw==
"@babel/helper-string-parser@^7.25.9":
version "7.25.9"
resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz#1aabb72ee72ed35789b4bbcad3ca2862ce614e8c"
integrity sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==
"@babel/helper-validator-identifier@^7.25.9":
version "7.25.9"
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz#24b64e2c3ec7cd3b3c547729b8d16871f22cbdc7"
integrity sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==
"@babel/helper-validator-option@^7.25.9":
version "7.25.9"
resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz#86e45bd8a49ab7e03f276577f96179653d41da72"
integrity sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==
"@babel/helpers@^7.26.0":
version "7.26.0"
resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.26.0.tgz#30e621f1eba5aa45fe6f4868d2e9154d884119a4"
integrity sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==
dependencies:
"@babel/template" "^7.25.9"
"@babel/types" "^7.26.0"
"@babel/parser@^7.25.9", "@babel/parser@^7.26.0", "@babel/parser@^7.26.3":
version "7.26.3"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.26.3.tgz#8c51c5db6ddf08134af1ddbacf16aaab48bac234"
integrity sha512-WJ/CvmY8Mea8iDXo6a7RK2wbmJITT5fN3BEkRuFlxVyNx8jOKIIhmC4fSkTcPcf8JyavbBwIe6OpiCOBXt/IcA==
dependencies:
"@babel/types" "^7.26.3"
"@babel/plugin-syntax-typescript@^7.25.9":
version "7.25.9"
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.9.tgz#67dda2b74da43727cf21d46cf9afef23f4365399"
integrity sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ==
dependencies:
"@babel/helper-plugin-utils" "^7.25.9"
"@babel/template@^7.25.9":
version "7.25.9"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.25.9.tgz#ecb62d81a8a6f5dc5fe8abfc3901fc52ddf15016"
integrity sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==
dependencies:
"@babel/code-frame" "^7.25.9"
"@babel/parser" "^7.25.9"
"@babel/types" "^7.25.9"
"@babel/traverse@^7.25.9":
version "7.26.4"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.26.4.tgz#ac3a2a84b908dde6d463c3bfa2c5fdc1653574bd"
integrity sha512-fH+b7Y4p3yqvApJALCPJcwb0/XaOSgtK4pzV6WVjPR5GLFQBRI7pfoX2V2iM48NXvX07NUxxm1Vw98YjqTcU5w==
dependencies:
"@babel/code-frame" "^7.26.2"
"@babel/generator" "^7.26.3"
"@babel/parser" "^7.26.3"
"@babel/template" "^7.25.9"
"@babel/types" "^7.26.3"
debug "^4.3.1"
globals "^11.1.0"
"@babel/types@^7.25.9", "@babel/types@^7.26.0", "@babel/types@^7.26.3":
version "7.26.3"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.26.3.tgz#37e79830f04c2b5687acc77db97fbc75fb81f3c0"
integrity sha512-vN5p+1kl59GVKMvTHt55NzzmYVxprfJD+ql7U9NFIfKCBkYE55LYtS+WtPlaYOyzydrKI8Nezd+aZextrd+FMA==
dependencies:
"@babel/helper-string-parser" "^7.25.9"
"@babel/helper-validator-identifier" "^7.25.9"
"@jridgewell/gen-mapping@^0.3.5":
version "0.3.8"
resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz#4f0e06362e01362f823d348f1872b08f666d8142"
integrity sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==
dependencies:
"@jridgewell/set-array" "^1.2.1"
"@jridgewell/sourcemap-codec" "^1.4.10"
"@jridgewell/trace-mapping" "^0.3.24"
"@jridgewell/resolve-uri@^3.1.0":
version "3.1.2"
resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6"
integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==
"@jridgewell/set-array@^1.2.1":
version "1.2.1"
resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280"
integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==
"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14":
version "1.5.0"
resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a"
integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==
"@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25":
version "0.3.25"
resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0"
integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==
dependencies:
"@jridgewell/resolve-uri" "^3.1.0"
"@jridgewell/sourcemap-codec" "^1.4.14"
argparse@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38"
integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==
browserslist@^4.24.0:
version "4.24.3"
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.24.3.tgz#5fc2725ca8fb3c1432e13dac278c7cc103e026d2"
integrity sha512-1CPmv8iobE2fyRMV97dAcMVegvvWKxmq94hkLiAkUGwKVTyDLw33K+ZxiFrREKmmps4rIw6grcCFCnTMSZ/YiA==
dependencies:
caniuse-lite "^1.0.30001688"
electron-to-chromium "^1.5.73"
node-releases "^2.0.19"
update-browserslist-db "^1.1.1"
callsites@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==
caniuse-lite@^1.0.30001688:
version "1.0.30001690"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001690.tgz#f2d15e3aaf8e18f76b2b8c1481abde063b8104c8"
integrity sha512-5ExiE3qQN6oF8Clf8ifIDcMRCRE/dMGcETG/XGMD8/XiXm6HXQgQTh1yZYLXXpSOsEUlJm1Xr7kGULZTuGtP/w==
convert-source-map@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a"
integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==
cosmiconfig@^9.0.0:
version "9.0.0"
resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-9.0.0.tgz#34c3fc58287b915f3ae905ab6dc3de258b55ad9d"
integrity sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==
dependencies:
env-paths "^2.2.1"
import-fresh "^3.3.0"
js-yaml "^4.1.0"
parse-json "^5.2.0"
debug@^4.1.0, debug@^4.3.1:
version "4.4.0"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.0.tgz#2b3f2aea2ffeb776477460267377dc8710faba8a"
integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==
dependencies:
ms "^2.1.3"
electron-to-chromium@^1.5.73:
version "1.5.74"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.74.tgz#cb886b504a6467e4c00bea3317edb38393c53413"
integrity sha512-ck3//9RC+6oss/1Bh9tiAVFy5vfSKbRHAFh7Z3/eTRkEqJeWgymloShB17Vg3Z4nmDNp35vAd1BZ6CMW4Wt6Iw==
env-paths@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2"
integrity sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==
error-ex@^1.3.1:
version "1.3.2"
resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==
dependencies:
is-arrayish "^0.2.1"
escalade@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5"
integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==
gensync@^1.0.0-beta.2:
version "1.0.0-beta.2"
resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0"
integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==
globals@^11.1.0:
version "11.12.0"
resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e"
integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==
import-fresh@^3.3.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b"
integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==
dependencies:
parent-module "^1.0.0"
resolve-from "^4.0.0"
is-arrayish@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==
js-tokens@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
js-yaml@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602"
integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==
dependencies:
argparse "^2.0.1"
jsesc@^3.0.2:
version "3.1.0"
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.1.0.tgz#74d335a234f67ed19907fdadfac7ccf9d409825d"
integrity sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==
json-parse-even-better-errors@^2.3.0:
version "2.3.1"
resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d"
integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==
json5@^2.2.3:
version "2.2.3"
resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283"
integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==
lines-and-columns@^1.1.6:
version "1.2.4"
resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632"
integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==
lru-cache@^5.1.1:
version "5.1.1"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920"
integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==
dependencies:
yallist "^3.0.2"
ms@^2.1.3:
version "2.1.3"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
node-releases@^2.0.19:
version "2.0.19"
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.19.tgz#9e445a52950951ec4d177d843af370b411caf314"
integrity sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==
parent-module@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2"
integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==
dependencies:
callsites "^3.0.0"
parse-json@^5.2.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd"
integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==
dependencies:
"@babel/code-frame" "^7.0.0"
error-ex "^1.3.1"
json-parse-even-better-errors "^2.3.0"
lines-and-columns "^1.1.6"
picocolors@^1.0.0, picocolors@^1.1.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b"
integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==
prettier@^3.3.3:
version "3.4.2"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.4.2.tgz#a5ce1fb522a588bf2b78ca44c6e6fe5aa5a2b13f"
integrity sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==
resolve-from@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
semver@^6.3.1:
version "6.3.1"
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4"
integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==
update-browserslist-db@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz#80846fba1d79e82547fb661f8d141e0945755fe5"
integrity sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==
dependencies:
escalade "^3.2.0"
picocolors "^1.1.0"
vscode-jsonrpc@8.2.0:
version "8.2.0"
resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz#f43dfa35fb51e763d17cd94dcca0c9458f35abf9"
integrity sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==
vscode-languageserver-protocol@3.17.5:
version "3.17.5"
resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz#864a8b8f390835572f4e13bd9f8313d0e3ac4bea"
integrity sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==
dependencies:
vscode-jsonrpc "8.2.0"
vscode-languageserver-types "3.17.5"
vscode-languageserver-textdocument@^1.0.12:
version "1.0.12"
resolved "https://registry.yarnpkg.com/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.12.tgz#457ee04271ab38998a093c68c2342f53f6e4a631"
integrity sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==
vscode-languageserver-types@3.17.5:
version "3.17.5"
resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz#3273676f0cf2eab40b3f44d085acbb7f08a39d8a"
integrity sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==
vscode-languageserver@^9.0.1:
version "9.0.1"
resolved "https://registry.yarnpkg.com/vscode-languageserver/-/vscode-languageserver-9.0.1.tgz#500aef82097eb94df90d008678b0b6b5f474015b"
integrity sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==
dependencies:
vscode-languageserver-protocol "3.17.5"
yallist@^3.0.2:
version "3.1.1"
resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd"
integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==
+501 -46
View File
@@ -1700,6 +1700,126 @@
dependencies:
"@jridgewell/trace-mapping" "0.3.9"
"@esbuild/aix-ppc64@0.24.0":
version "0.24.0"
resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.24.0.tgz#b57697945b50e99007b4c2521507dc613d4a648c"
integrity sha512-WtKdFM7ls47zkKHFVzMz8opM7LkcsIp9amDUBIAWirg70RM71WRSjdILPsY5Uv1D42ZpUfaPILDlfactHgsRkw==
"@esbuild/android-arm64@0.24.0":
version "0.24.0"
resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.24.0.tgz#1add7e0af67acefd556e407f8497e81fddad79c0"
integrity sha512-Vsm497xFM7tTIPYK9bNTYJyF/lsP590Qc1WxJdlB6ljCbdZKU9SY8i7+Iin4kyhV/KV5J2rOKsBQbB77Ab7L/w==
"@esbuild/android-arm@0.24.0":
version "0.24.0"
resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.24.0.tgz#ab7263045fa8e090833a8e3c393b60d59a789810"
integrity sha512-arAtTPo76fJ/ICkXWetLCc9EwEHKaeya4vMrReVlEIUCAUncH7M4bhMQ+M9Vf+FFOZJdTNMXNBrWwW+OXWpSew==
"@esbuild/android-x64@0.24.0":
version "0.24.0"
resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.24.0.tgz#e8f8b196cfdfdd5aeaebbdb0110983460440e705"
integrity sha512-t8GrvnFkiIY7pa7mMgJd7p8p8qqYIz1NYiAoKc75Zyv73L3DZW++oYMSHPRarcotTKuSs6m3hTOa5CKHaS02TQ==
"@esbuild/darwin-arm64@0.24.0":
version "0.24.0"
resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.24.0.tgz#2d0d9414f2acbffd2d86e98253914fca603a53dd"
integrity sha512-CKyDpRbK1hXwv79soeTJNHb5EiG6ct3efd/FTPdzOWdbZZfGhpbcqIpiD0+vwmpu0wTIL97ZRPZu8vUt46nBSw==
"@esbuild/darwin-x64@0.24.0":
version "0.24.0"
resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.24.0.tgz#33087aab31a1eb64c89daf3d2cf8ce1775656107"
integrity sha512-rgtz6flkVkh58od4PwTRqxbKH9cOjaXCMZgWD905JOzjFKW+7EiUObfd/Kav+A6Gyud6WZk9w+xu6QLytdi2OA==
"@esbuild/freebsd-arm64@0.24.0":
version "0.24.0"
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.24.0.tgz#bb76e5ea9e97fa3c753472f19421075d3a33e8a7"
integrity sha512-6Mtdq5nHggwfDNLAHkPlyLBpE5L6hwsuXZX8XNmHno9JuL2+bg2BX5tRkwjyfn6sKbxZTq68suOjgWqCicvPXA==
"@esbuild/freebsd-x64@0.24.0":
version "0.24.0"
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.24.0.tgz#e0e2ce9249fdf6ee29e5dc3d420c7007fa579b93"
integrity sha512-D3H+xh3/zphoX8ck4S2RxKR6gHlHDXXzOf6f/9dbFt/NRBDIE33+cVa49Kil4WUjxMGW0ZIYBYtaGCa2+OsQwQ==
"@esbuild/linux-arm64@0.24.0":
version "0.24.0"
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.24.0.tgz#d1b2aa58085f73ecf45533c07c82d81235388e75"
integrity sha512-TDijPXTOeE3eaMkRYpcy3LarIg13dS9wWHRdwYRnzlwlA370rNdZqbcp0WTyyV/k2zSxfko52+C7jU5F9Tfj1g==
"@esbuild/linux-arm@0.24.0":
version "0.24.0"
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.24.0.tgz#8e4915df8ea3e12b690a057e77a47b1d5935ef6d"
integrity sha512-gJKIi2IjRo5G6Glxb8d3DzYXlxdEj2NlkixPsqePSZMhLudqPhtZ4BUrpIuTjJYXxvF9njql+vRjB2oaC9XpBw==
"@esbuild/linux-ia32@0.24.0":
version "0.24.0"
resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.24.0.tgz#8200b1110666c39ab316572324b7af63d82013fb"
integrity sha512-K40ip1LAcA0byL05TbCQ4yJ4swvnbzHscRmUilrmP9Am7//0UjPreh4lpYzvThT2Quw66MhjG//20mrufm40mA==
"@esbuild/linux-loong64@0.24.0":
version "0.24.0"
resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.24.0.tgz#6ff0c99cf647504df321d0640f0d32e557da745c"
integrity sha512-0mswrYP/9ai+CU0BzBfPMZ8RVm3RGAN/lmOMgW4aFUSOQBjA31UP8Mr6DDhWSuMwj7jaWOT0p0WoZ6jeHhrD7g==
"@esbuild/linux-mips64el@0.24.0":
version "0.24.0"
resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.24.0.tgz#3f720ccd4d59bfeb4c2ce276a46b77ad380fa1f3"
integrity sha512-hIKvXm0/3w/5+RDtCJeXqMZGkI2s4oMUGj3/jM0QzhgIASWrGO5/RlzAzm5nNh/awHE0A19h/CvHQe6FaBNrRA==
"@esbuild/linux-ppc64@0.24.0":
version "0.24.0"
resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.24.0.tgz#9d6b188b15c25afd2e213474bf5f31e42e3aa09e"
integrity sha512-HcZh5BNq0aC52UoocJxaKORfFODWXZxtBaaZNuN3PUX3MoDsChsZqopzi5UupRhPHSEHotoiptqikjN/B77mYQ==
"@esbuild/linux-riscv64@0.24.0":
version "0.24.0"
resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.24.0.tgz#f989fdc9752dfda286c9cd87c46248e4dfecbc25"
integrity sha512-bEh7dMn/h3QxeR2KTy1DUszQjUrIHPZKyO6aN1X4BCnhfYhuQqedHaa5MxSQA/06j3GpiIlFGSsy1c7Gf9padw==
"@esbuild/linux-s390x@0.24.0":
version "0.24.0"
resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.24.0.tgz#29ebf87e4132ea659c1489fce63cd8509d1c7319"
integrity sha512-ZcQ6+qRkw1UcZGPyrCiHHkmBaj9SiCD8Oqd556HldP+QlpUIe2Wgn3ehQGVoPOvZvtHm8HPx+bH20c9pvbkX3g==
"@esbuild/linux-x64@0.24.0":
version "0.24.0"
resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.24.0.tgz#4af48c5c0479569b1f359ffbce22d15f261c0cef"
integrity sha512-vbutsFqQ+foy3wSSbmjBXXIJ6PL3scghJoM8zCL142cGaZKAdCZHyf+Bpu/MmX9zT9Q0zFBVKb36Ma5Fzfa8xA==
"@esbuild/netbsd-x64@0.24.0":
version "0.24.0"
resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.24.0.tgz#1ae73d23cc044a0ebd4f198334416fb26c31366c"
integrity sha512-hjQ0R/ulkO8fCYFsG0FZoH+pWgTTDreqpqY7UnQntnaKv95uP5iW3+dChxnx7C3trQQU40S+OgWhUVwCjVFLvg==
"@esbuild/openbsd-arm64@0.24.0":
version "0.24.0"
resolved "https://registry.yarnpkg.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.24.0.tgz#5d904a4f5158c89859fd902c427f96d6a9e632e2"
integrity sha512-MD9uzzkPQbYehwcN583yx3Tu5M8EIoTD+tUgKF982WYL9Pf5rKy9ltgD0eUgs8pvKnmizxjXZyLt0z6DC3rRXg==
"@esbuild/openbsd-x64@0.24.0":
version "0.24.0"
resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.24.0.tgz#4c8aa88c49187c601bae2971e71c6dc5e0ad1cdf"
integrity sha512-4ir0aY1NGUhIC1hdoCzr1+5b43mw99uNwVzhIq1OY3QcEwPDO3B7WNXBzaKY5Nsf1+N11i1eOfFcq+D/gOS15Q==
"@esbuild/sunos-x64@0.24.0":
version "0.24.0"
resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.24.0.tgz#8ddc35a0ea38575fa44eda30a5ee01ae2fa54dd4"
integrity sha512-jVzdzsbM5xrotH+W5f1s+JtUy1UWgjU0Cf4wMvffTB8m6wP5/kx0KiaLHlbJO+dMgtxKV8RQ/JvtlFcdZ1zCPA==
"@esbuild/win32-arm64@0.24.0":
version "0.24.0"
resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.24.0.tgz#6e79c8543f282c4539db684a207ae0e174a9007b"
integrity sha512-iKc8GAslzRpBytO2/aN3d2yb2z8XTVfNV0PjGlCxKo5SgWmNXx82I/Q3aG1tFfS+A2igVCY97TJ8tnYwpUWLCA==
"@esbuild/win32-ia32@0.24.0":
version "0.24.0"
resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.24.0.tgz#057af345da256b7192d18b676a02e95d0fa39103"
integrity sha512-vQW36KZolfIudCcTnaTpmLQ24Ha1RjygBo39/aLkM2kmjkWmZGEJ5Gn9l5/7tzXA42QGIoWbICfg6KLLkIw6yw==
"@esbuild/win32-x64@0.24.0":
version "0.24.0"
resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.24.0.tgz#168ab1c7e1c318b922637fad8f339d48b01e1244"
integrity sha512-7IAFPrjSQIJrGsK6flwg7NFmwBoSTyF3rl7If0hNUFQU4ilTsEPL6GuMuU9BfIWVVGuRnuIidkSMC+c0Otu8IA==
"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0":
version "4.4.0"
resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59"
@@ -1712,11 +1832,32 @@
resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.11.1.tgz#a547badfc719eb3e5f4b556325e542fbe9d7a18f"
integrity sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q==
"@eslint-community/regexpp@^4.12.1":
version "4.12.1"
resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.12.1.tgz#cfc6cffe39df390a3841cde2abccf92eaa7ae0e0"
integrity sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==
"@eslint-community/regexpp@^4.5.1", "@eslint-community/regexpp@^4.6.1":
version "4.10.0"
resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.10.0.tgz#548f6de556857c8bb73bbee70c35dc82a2e74d63"
integrity sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==
"@eslint/config-array@^0.19.0":
version "0.19.1"
resolved "https://registry.yarnpkg.com/@eslint/config-array/-/config-array-0.19.1.tgz#734aaea2c40be22bbb1f2a9dac687c57a6a4c984"
integrity sha512-fo6Mtm5mWyKjA/Chy1BYTdn5mGJoDNjC7C64ug20ADsRDGrA85bN3uK3MaKbeRkRuuIEAR5N33Jr1pbm411/PA==
dependencies:
"@eslint/object-schema" "^2.1.5"
debug "^4.3.1"
minimatch "^3.1.2"
"@eslint/core@^0.9.0":
version "0.9.1"
resolved "https://registry.yarnpkg.com/@eslint/core/-/core-0.9.1.tgz#31763847308ef6b7084a4505573ac9402c51f9d1"
integrity sha512-GuUdqkyyzQI5RMIWkHhvTWLCyLo1jNK3vzkSyaExH5kHPDHcuL2VOpHjmMY+y3+NC69qAKToBqldTBgYeLSr9Q==
dependencies:
"@types/json-schema" "^7.0.15"
"@eslint/eslintrc@^2.1.4":
version "2.1.4"
resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.4.tgz#388a269f0f25c1b6adc317b5a2c55714894c70ad"
@@ -1732,6 +1873,21 @@
minimatch "^3.1.2"
strip-json-comments "^3.1.1"
"@eslint/eslintrc@^3.2.0":
version "3.2.0"
resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-3.2.0.tgz#57470ac4e2e283a6bf76044d63281196e370542c"
integrity sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==
dependencies:
ajv "^6.12.4"
debug "^4.3.2"
espree "^10.0.1"
globals "^14.0.0"
ignore "^5.2.0"
import-fresh "^3.2.1"
js-yaml "^4.1.0"
minimatch "^3.1.2"
strip-json-comments "^3.1.1"
"@eslint/js@8.57.0":
version "8.57.0"
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.0.tgz#a5417ae8427873f1dd08b70b3574b453e67b5f7f"
@@ -1742,6 +1898,23 @@
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.1.tgz#de633db3ec2ef6a3c89e2f19038063e8a122e2c2"
integrity sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==
"@eslint/js@9.17.0", "@eslint/js@^9.13.0":
version "9.17.0"
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.17.0.tgz#1523e586791f80376a6f8398a3964455ecc651ec"
integrity sha512-Sxc4hqcs1kTu0iID3kcZDW3JHq2a77HO9P8CP6YEA/FpH3Ll8UXE2r/86Rz9YJLKme39S9vU5OWNjC6Xl0Cr3w==
"@eslint/object-schema@^2.1.5":
version "2.1.5"
resolved "https://registry.yarnpkg.com/@eslint/object-schema/-/object-schema-2.1.5.tgz#8670a8f6258a2be5b2c620ff314a1d984c23eb2e"
integrity sha512-o0bhxnL89h5Bae5T318nFoFzGy+YE5i/gGkoPAgkmTVdRKTiv3p8JHevPiPaMwoloKfEiiaHlawCqaZMqRm+XQ==
"@eslint/plugin-kit@^0.2.3":
version "0.2.4"
resolved "https://registry.yarnpkg.com/@eslint/plugin-kit/-/plugin-kit-0.2.4.tgz#2b78e7bb3755784bb13faa8932a1d994d6537792"
integrity sha512-zSkKow6H5Kdm0ZUQUB2kV5JIXqoG0+uH5YADhaEHswm664N9Db8dXSi0nMJpacpMf+MyyglF1vnZohpEg5yUtg==
dependencies:
levn "^0.4.1"
"@hapi/hoek@^9.0.0", "@hapi/hoek@^9.3.0":
version "9.3.0"
resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-9.3.0.tgz#8368869dcb735be2e7f5cb7647de78e167a251fb"
@@ -1754,6 +1927,19 @@
dependencies:
"@hapi/hoek" "^9.0.0"
"@humanfs/core@^0.19.1":
version "0.19.1"
resolved "https://registry.yarnpkg.com/@humanfs/core/-/core-0.19.1.tgz#17c55ca7d426733fe3c561906b8173c336b40a77"
integrity sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==
"@humanfs/node@^0.16.6":
version "0.16.6"
resolved "https://registry.yarnpkg.com/@humanfs/node/-/node-0.16.6.tgz#ee2a10eaabd1131987bf0488fd9b820174cd765e"
integrity sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==
dependencies:
"@humanfs/core" "^0.19.1"
"@humanwhocodes/retry" "^0.3.0"
"@humanwhocodes/config-array@^0.11.14":
version "0.11.14"
resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.14.tgz#d78e481a039f7566ecc9660b4ea7fe6b1fec442b"
@@ -1787,6 +1973,16 @@
resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3"
integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==
"@humanwhocodes/retry@^0.3.0":
version "0.3.1"
resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.3.1.tgz#c72a5c76a9fbaf3488e231b13dc52c0da7bab42a"
integrity sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==
"@humanwhocodes/retry@^0.4.1":
version "0.4.1"
resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.4.1.tgz#9a96ce501bc62df46c4031fbd970e3cc6b10f07b"
integrity sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==
"@isaacs/cliui@^8.0.2":
version "8.0.2"
resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550"
@@ -2512,17 +2708,18 @@
resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33"
integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==
"@rollup/plugin-commonjs@^25.0.7":
version "25.0.7"
resolved "https://registry.yarnpkg.com/@rollup/plugin-commonjs/-/plugin-commonjs-25.0.7.tgz#145cec7589ad952171aeb6a585bbeabd0fd3b4cf"
integrity sha512-nEvcR+LRjEjsaSsc4x3XZfCCvZIaSMenZu/OiwOKGN2UhQpAYI7ru7czFvyWbErlpoGjnSX3D5Ch5FcMA3kRWQ==
"@rollup/plugin-commonjs@^28.0.2":
version "28.0.2"
resolved "https://registry.yarnpkg.com/@rollup/plugin-commonjs/-/plugin-commonjs-28.0.2.tgz#193d7a86470f112b56927c1d821ee45951a819ea"
integrity sha512-BEFI2EDqzl+vA1rl97IDRZ61AIwGH093d9nz8+dThxJNH8oSoB7MjWvPCX3dkaK1/RCJ/1v/R1XB15FuSs0fQw==
dependencies:
"@rollup/pluginutils" "^5.0.1"
commondir "^1.0.1"
estree-walker "^2.0.2"
glob "^8.0.3"
fdir "^6.2.0"
is-reference "1.2.1"
magic-string "^0.30.3"
picomatch "^4.0.2"
"@rollup/plugin-json@^6.1.0":
version "6.1.0"
@@ -2531,15 +2728,14 @@
dependencies:
"@rollup/pluginutils" "^5.1.0"
"@rollup/plugin-node-resolve@^15.2.3":
version "15.2.3"
resolved "https://registry.yarnpkg.com/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.2.3.tgz#e5e0b059bd85ca57489492f295ce88c2d4b0daf9"
integrity sha512-j/lym8nf5E21LwBT4Df1VD6hRO2L2iwUeUmP7litikRsVp1H6NWx20NEp0Y7su+7XGc476GnXXc4kFeZNGmaSQ==
"@rollup/plugin-node-resolve@^16.0.0":
version "16.0.0"
resolved "https://registry.yarnpkg.com/@rollup/plugin-node-resolve/-/plugin-node-resolve-16.0.0.tgz#b1a0594661f40d7b061d82136e847354ff85f211"
integrity sha512-0FPvAeVUT/zdWoO0jnb/V5BlBsUSNfkIOtFHzMO4H9MOklrmQFY6FduVHKucNb/aTFxvnGhj4MNj/T1oNdDfNg==
dependencies:
"@rollup/pluginutils" "^5.0.1"
"@types/resolve" "1.20.2"
deepmerge "^4.2.2"
is-builtin-module "^3.2.1"
is-module "^1.0.0"
resolve "^1.22.1"
@@ -2552,10 +2748,10 @@
smob "^1.0.0"
terser "^5.17.4"
"@rollup/plugin-typescript@^11.1.6":
version "11.1.6"
resolved "https://registry.yarnpkg.com/@rollup/plugin-typescript/-/plugin-typescript-11.1.6.tgz#724237d5ec12609ec01429f619d2a3e7d4d1b22b"
integrity sha512-R92yOmIACgYdJ7dJ97p4K69I8gg6IEHt8M7dUBxN3W6nrO8uUxX5ixl0yU/N3aZTi8WhPuICvOHXQvF6FaykAA==
"@rollup/plugin-typescript@^12.1.2":
version "12.1.2"
resolved "https://registry.yarnpkg.com/@rollup/plugin-typescript/-/plugin-typescript-12.1.2.tgz#ebaeec2e7376faa889030ccd7cb485a649e63118"
integrity sha512-cdtSp154H5sv637uMr1a8OTWB0L1SWDSm1rDGiyfcGcvQ6cuTs4MDk2BVEBGysUWago4OJN4EQZqOTl/QY3Jgg==
dependencies:
"@rollup/pluginutils" "^5.1.0"
resolve "^1.22.1"
@@ -2827,6 +3023,11 @@
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4"
integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==
"@types/estree@^1.0.6":
version "1.0.6"
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.6.tgz#628effeeae2064a1b4e79f78e81d87b7e5fc7b50"
integrity sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==
"@types/fbt@^1.0.4":
version "1.0.4"
resolved "https://registry.yarnpkg.com/@types/fbt/-/fbt-1.0.4.tgz#0d9e427f91fcff46bdcf2ca42a63343096565451"
@@ -2906,7 +3107,7 @@
"@types/tough-cookie" "*"
parse5 "^7.0.0"
"@types/json-schema@*", "@types/json-schema@^7.0.12":
"@types/json-schema@*", "@types/json-schema@^7.0.12", "@types/json-schema@^7.0.15":
version "7.0.15"
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841"
integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==
@@ -2921,6 +3122,13 @@
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.7.19.tgz#ad83aa9b7af470fab7e0f562be87e97dc8ffe08e"
integrity sha512-Sq1itGUKUX1ap7GgZlrzdBydjbsJL/NSQt/4wkAxUJ7/OS5c2WkoN6WSpWc2Yc5wtKMZOUA0VCs/j2XJadN3HA==
"@types/node@^20":
version "20.17.10"
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.17.10.tgz#3f7166190aece19a0d1d364d75c8b0b5778c1e18"
integrity sha512-/jrvh5h6NXhEauFFexRin69nA0uHJ5gwk4iDivp/DeoEua3uwCUto6PC86IpRITBOs4+6i2I56K5x5b6WYGXHA==
dependencies:
undici-types "~6.19.2"
"@types/node@^20.2.5":
version "20.2.5"
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.2.5.tgz#26d295f3570323b2837d322180dfbf1ba156fefb"
@@ -3003,6 +3211,21 @@
dependencies:
"@types/yargs-parser" "*"
"@typescript-eslint/eslint-plugin@8.18.1":
version "8.18.1"
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.18.1.tgz#992e5ac1553ce20d0d46aa6eccd79dc36dedc805"
integrity sha512-Ncvsq5CT3Gvh+uJG0Lwlho6suwDfUXH0HztslDf5I+F2wAFAZMRwYLEorumpKLzmO2suAXZ/td1tBg4NZIi9CQ==
dependencies:
"@eslint-community/regexpp" "^4.10.0"
"@typescript-eslint/scope-manager" "8.18.1"
"@typescript-eslint/type-utils" "8.18.1"
"@typescript-eslint/utils" "8.18.1"
"@typescript-eslint/visitor-keys" "8.18.1"
graphemer "^1.4.0"
ignore "^5.3.1"
natural-compare "^1.4.0"
ts-api-utils "^1.3.0"
"@typescript-eslint/eslint-plugin@^7.4.0":
version "7.4.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.4.0.tgz#de61c3083842fc6ac889d2fc83c9a96b55ab8328"
@@ -3035,6 +3258,17 @@
natural-compare "^1.4.0"
ts-api-utils "^1.3.0"
"@typescript-eslint/parser@8.18.1":
version "8.18.1"
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.18.1.tgz#c258bae062778b7696793bc492249027a39dfb95"
integrity sha512-rBnTWHCdbYM2lh7hjyXqxk70wvon3p2FyaniZuey5TrcGBpfhVp0OxOa6gxr9Q9YhZFKyfbEnxc24ZnVbbUkCA==
dependencies:
"@typescript-eslint/scope-manager" "8.18.1"
"@typescript-eslint/types" "8.18.1"
"@typescript-eslint/typescript-estree" "8.18.1"
"@typescript-eslint/visitor-keys" "8.18.1"
debug "^4.3.4"
"@typescript-eslint/parser@^7.4.0":
version "7.4.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-7.4.0.tgz#540f4321de1e52b886c0fa68628af1459954c1f1"
@@ -3065,6 +3299,14 @@
"@typescript-eslint/types" "7.4.0"
"@typescript-eslint/visitor-keys" "7.4.0"
"@typescript-eslint/scope-manager@8.18.1":
version "8.18.1"
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.18.1.tgz#52cedc3a8178d7464a70beffed3203678648e55b"
integrity sha512-HxfHo2b090M5s2+/9Z3gkBhI6xBH8OJCFjH9MhQ+nnoZqxU3wNxkLT+VWXWSFWc3UF3Z+CfPAyqdCTdoXtDPCQ==
dependencies:
"@typescript-eslint/types" "8.18.1"
"@typescript-eslint/visitor-keys" "8.18.1"
"@typescript-eslint/scope-manager@8.7.0":
version "8.7.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.7.0.tgz#90ee7bf9bc982b9260b93347c01a8bc2b595e0b8"
@@ -3083,6 +3325,16 @@
debug "^4.3.4"
ts-api-utils "^1.0.1"
"@typescript-eslint/type-utils@8.18.1":
version "8.18.1"
resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.18.1.tgz#10f41285475c0bdee452b79ff7223f0e43a7781e"
integrity sha512-jAhTdK/Qx2NJPNOTxXpMwlOiSymtR2j283TtPqXkKBdH8OAMmhiUfP0kJjc/qSE51Xrq02Gj9NY7MwK+UxVwHQ==
dependencies:
"@typescript-eslint/typescript-estree" "8.18.1"
"@typescript-eslint/utils" "8.18.1"
debug "^4.3.4"
ts-api-utils "^1.3.0"
"@typescript-eslint/type-utils@8.7.0":
version "8.7.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.7.0.tgz#d56b104183bdcffcc434a23d1ce26cde5e42df93"
@@ -3098,6 +3350,11 @@
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-7.4.0.tgz#ee9dafa75c99eaee49de6dcc9348b45d354419b6"
integrity sha512-mjQopsbffzJskos5B4HmbsadSJQWaRK0UxqQ7GuNA9Ga4bEKeiO6b2DnB6cM6bpc8lemaPseh0H9B/wyg+J7rw==
"@typescript-eslint/types@8.18.1":
version "8.18.1"
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.18.1.tgz#d7f4f94d0bba9ebd088de840266fcd45408a8fff"
integrity sha512-7uoAUsCj66qdNQNpH2G8MyTFlgerum8ubf21s3TSM3XmKXuIn+H2Sifh/ES2nPOPiYSRJWAk0fDkW0APBWcpfw==
"@typescript-eslint/types@8.7.0":
version "8.7.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.7.0.tgz#21d987201c07b69ce7ddc03451d7196e5445ad19"
@@ -3117,6 +3374,20 @@
semver "^7.5.4"
ts-api-utils "^1.0.1"
"@typescript-eslint/typescript-estree@8.18.1":
version "8.18.1"
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.18.1.tgz#2a86cd64b211a742f78dfa7e6f4860413475367e"
integrity sha512-z8U21WI5txzl2XYOW7i9hJhxoKKNG1kcU4RzyNvKrdZDmbjkmLBo8bgeiOJmA06kizLI76/CCBAAGlTlEeUfyg==
dependencies:
"@typescript-eslint/types" "8.18.1"
"@typescript-eslint/visitor-keys" "8.18.1"
debug "^4.3.4"
fast-glob "^3.3.2"
is-glob "^4.0.3"
minimatch "^9.0.4"
semver "^7.6.0"
ts-api-utils "^1.3.0"
"@typescript-eslint/typescript-estree@8.7.0":
version "8.7.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.7.0.tgz#6c7db6baa4380b937fa81466c546d052f362d0e8"
@@ -3144,6 +3415,16 @@
"@typescript-eslint/typescript-estree" "7.4.0"
semver "^7.5.4"
"@typescript-eslint/utils@8.18.1":
version "8.18.1"
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.18.1.tgz#c4199ea23fc823c736e2c96fd07b1f7235fa92d5"
integrity sha512-8vikiIj2ebrC4WRdcAdDcmnu9Q/MXXwg+STf40BVfT8exDqBCUPdypvzcUPxEqRGKg9ALagZ0UWcYCtn+4W2iQ==
dependencies:
"@eslint-community/eslint-utils" "^4.4.0"
"@typescript-eslint/scope-manager" "8.18.1"
"@typescript-eslint/types" "8.18.1"
"@typescript-eslint/typescript-estree" "8.18.1"
"@typescript-eslint/utils@8.7.0":
version "8.7.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.7.0.tgz#cef3f70708b5b5fd7ed8672fc14714472bd8a011"
@@ -3162,6 +3443,14 @@
"@typescript-eslint/types" "7.4.0"
eslint-visitor-keys "^3.4.1"
"@typescript-eslint/visitor-keys@8.18.1":
version "8.18.1"
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.18.1.tgz#344b4f6bc83f104f514676facf3129260df7610a"
integrity sha512-Vj0WLm5/ZsD013YeUKn+K0y8p1M0jPpxOkKdbD1wB0ns53a5piVY02zjf072TblEweAbcYiFiPoSMF3kp+VhhQ==
dependencies:
"@typescript-eslint/types" "8.18.1"
eslint-visitor-keys "^4.2.0"
"@typescript-eslint/visitor-keys@8.7.0":
version "8.7.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.7.0.tgz#5e46f1777f9d69360a883c1a56ac3c511c9659a8"
@@ -3208,6 +3497,11 @@ acorn@^7.1.1:
resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa"
integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==
acorn@^8.14.0:
version "8.14.0"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.14.0.tgz#063e2c70cac5fb4f6467f0b11152e04c682795b0"
integrity sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==
acorn@^8.4.1, acorn@^8.7.1:
version "8.8.0"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.0.tgz#88c0187620435c7f6015803f5539dae05a9dbea8"
@@ -3621,11 +3915,6 @@ buffer@^5.5.0:
base64-js "^1.3.1"
ieee754 "^1.1.13"
builtin-modules@^3.3.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.3.0.tgz#cae62812b89801e9656336e46223e030386be7b6"
integrity sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==
call-bind@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c"
@@ -3841,6 +4130,16 @@ core-js-compat@^3.30.1, core-js-compat@^3.30.2:
dependencies:
browserslist "^4.21.5"
cosmiconfig@^9.0.0:
version "9.0.0"
resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-9.0.0.tgz#34c3fc58287b915f3ae905ab6dc3de258b55ad9d"
integrity sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==
dependencies:
env-paths "^2.2.1"
import-fresh "^3.3.0"
js-yaml "^4.1.0"
parse-json "^5.2.0"
create-require@^1.1.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333"
@@ -3855,6 +4154,15 @@ cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3:
shebang-command "^2.0.0"
which "^2.0.1"
cross-spawn@^7.0.6:
version "7.0.6"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f"
integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==
dependencies:
path-key "^3.1.0"
shebang-command "^2.0.0"
which "^2.0.1"
cssom@^0.5.0:
version "0.5.0"
resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.5.0.tgz#d254fa92cd8b6fbd83811b9fbaed34663cc17c36"
@@ -4076,6 +4384,11 @@ entities@^4.4.0:
resolved "https://registry.yarnpkg.com/entities/-/entities-4.4.0.tgz#97bdaba170339446495e653cfd2db78962900174"
integrity sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==
env-paths@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2"
integrity sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==
error-ex@^1.3.1:
version "1.3.2"
resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
@@ -4088,6 +4401,36 @@ es5-ext@0.8.x:
resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.8.2.tgz#aba8d9e1943a895ac96837a62a39b3f55ecd94ab"
integrity sha512-H19ompyhnKiBdjHR1DPHvf5RHgHPmJaY9JNzFGbMbPgdsUkvnUCN1Ke8J4Y0IMyTwFM2M9l4h2GoHwzwpSmXbA==
esbuild@^0.24.0:
version "0.24.0"
resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.24.0.tgz#f2d470596885fcb2e91c21eb3da3b3c89c0b55e7"
integrity sha512-FuLPevChGDshgSicjisSooU0cemp/sGXR841D5LHMB7mTVOmsEHcAxaH3irL53+8YDIeVNQEySh4DaYU/iuPqQ==
optionalDependencies:
"@esbuild/aix-ppc64" "0.24.0"
"@esbuild/android-arm" "0.24.0"
"@esbuild/android-arm64" "0.24.0"
"@esbuild/android-x64" "0.24.0"
"@esbuild/darwin-arm64" "0.24.0"
"@esbuild/darwin-x64" "0.24.0"
"@esbuild/freebsd-arm64" "0.24.0"
"@esbuild/freebsd-x64" "0.24.0"
"@esbuild/linux-arm" "0.24.0"
"@esbuild/linux-arm64" "0.24.0"
"@esbuild/linux-ia32" "0.24.0"
"@esbuild/linux-loong64" "0.24.0"
"@esbuild/linux-mips64el" "0.24.0"
"@esbuild/linux-ppc64" "0.24.0"
"@esbuild/linux-riscv64" "0.24.0"
"@esbuild/linux-s390x" "0.24.0"
"@esbuild/linux-x64" "0.24.0"
"@esbuild/netbsd-x64" "0.24.0"
"@esbuild/openbsd-arm64" "0.24.0"
"@esbuild/openbsd-x64" "0.24.0"
"@esbuild/sunos-x64" "0.24.0"
"@esbuild/win32-arm64" "0.24.0"
"@esbuild/win32-ia32" "0.24.0"
"@esbuild/win32-x64" "0.24.0"
escalade@^3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
@@ -4133,6 +4476,14 @@ eslint-scope@^7.2.2:
esrecurse "^4.3.0"
estraverse "^5.2.0"
eslint-scope@^8.2.0:
version "8.2.0"
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-8.2.0.tgz#377aa6f1cb5dc7592cfd0b7f892fd0cf352ce442"
integrity sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==
dependencies:
esrecurse "^4.3.0"
estraverse "^5.2.0"
eslint-visitor-keys@^3.3.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826"
@@ -4148,6 +4499,11 @@ eslint-visitor-keys@^3.4.3:
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800"
integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==
eslint-visitor-keys@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz#687bacb2af884fcdda8a6e7d65c606f46a14cd45"
integrity sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==
eslint@8.57.0:
version "8.57.0"
resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.57.0.tgz#c786a6fd0e0b68941aaf624596fb987089195668"
@@ -4236,6 +4592,55 @@ eslint@^8.57.1:
strip-ansi "^6.0.1"
text-table "^0.2.0"
eslint@^9.13.0:
version "9.17.0"
resolved "https://registry.yarnpkg.com/eslint/-/eslint-9.17.0.tgz#faa1facb5dd042172fdc520106984b5c2421bb0c"
integrity sha512-evtlNcpJg+cZLcnVKwsai8fExnqjGPicK7gnUtlNuzu+Fv9bI0aLpND5T44VLQtoMEnI57LoXO9XAkIXwohKrA==
dependencies:
"@eslint-community/eslint-utils" "^4.2.0"
"@eslint-community/regexpp" "^4.12.1"
"@eslint/config-array" "^0.19.0"
"@eslint/core" "^0.9.0"
"@eslint/eslintrc" "^3.2.0"
"@eslint/js" "9.17.0"
"@eslint/plugin-kit" "^0.2.3"
"@humanfs/node" "^0.16.6"
"@humanwhocodes/module-importer" "^1.0.1"
"@humanwhocodes/retry" "^0.4.1"
"@types/estree" "^1.0.6"
"@types/json-schema" "^7.0.15"
ajv "^6.12.4"
chalk "^4.0.0"
cross-spawn "^7.0.6"
debug "^4.3.2"
escape-string-regexp "^4.0.0"
eslint-scope "^8.2.0"
eslint-visitor-keys "^4.2.0"
espree "^10.3.0"
esquery "^1.5.0"
esutils "^2.0.2"
fast-deep-equal "^3.1.3"
file-entry-cache "^8.0.0"
find-up "^5.0.0"
glob-parent "^6.0.2"
ignore "^5.2.0"
imurmurhash "^0.1.4"
is-glob "^4.0.0"
json-stable-stringify-without-jsonify "^1.0.1"
lodash.merge "^4.6.2"
minimatch "^3.1.2"
natural-compare "^1.4.0"
optionator "^0.9.3"
espree@^10.0.1, espree@^10.3.0:
version "10.3.0"
resolved "https://registry.yarnpkg.com/espree/-/espree-10.3.0.tgz#29267cf5b0cb98735b65e64ba07e0ed49d1eed8a"
integrity sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==
dependencies:
acorn "^8.14.0"
acorn-jsx "^5.3.2"
eslint-visitor-keys "^4.2.0"
espree@^9.6.0, espree@^9.6.1:
version "9.6.1"
resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f"
@@ -4257,6 +4662,13 @@ esquery@^1.4.2:
dependencies:
estraverse "^5.1.0"
esquery@^1.5.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.6.0.tgz#91419234f804d852a82dceec3e16cdc22cf9dae7"
integrity sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==
dependencies:
estraverse "^5.1.0"
esrecurse@^4.3.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921"
@@ -4408,6 +4820,11 @@ fbt@^1.0.2:
dependencies:
invariant "^2.2.4"
fdir@^6.2.0:
version "6.4.2"
resolved "https://registry.yarnpkg.com/fdir/-/fdir-6.4.2.tgz#ddaa7ce1831b161bc3657bb99cb36e1622702689"
integrity sha512-KnhMXsKSPZlAhp7+IjUkRZKPb4fUyccpDrdFXbi4QL1qkmFh9kVY09Yox+n4MaOb3lHZ1Tv829C3oaaXoMYPDQ==
file-entry-cache@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027"
@@ -4415,6 +4832,13 @@ file-entry-cache@^6.0.1:
dependencies:
flat-cache "^3.0.4"
file-entry-cache@^8.0.0:
version "8.0.0"
resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-8.0.0.tgz#7787bddcf1131bffb92636c69457bbc0edd6d81f"
integrity sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==
dependencies:
flat-cache "^4.0.0"
fill-range@^7.1.1:
version "7.1.1"
resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292"
@@ -4462,11 +4886,24 @@ flat-cache@^3.0.4:
flatted "^3.1.0"
rimraf "^3.0.2"
flat-cache@^4.0.0:
version "4.0.1"
resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-4.0.1.tgz#0ece39fcb14ee012f4b0410bd33dd9c1f011127c"
integrity sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==
dependencies:
flatted "^3.2.9"
keyv "^4.5.4"
flatted@^3.1.0:
version "3.2.7"
resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.7.tgz#609f39207cb614b89d0765b477cb2d437fbf9787"
integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==
flatted@^3.2.9:
version "3.3.2"
resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.2.tgz#adba1448a9841bec72b42c532ea23dbbedef1a27"
integrity sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==
flow-enums-runtime@^0.0.4:
version "0.0.4"
resolved "https://registry.yarnpkg.com/flow-enums-runtime/-/flow-enums-runtime-0.0.4.tgz#038635c679030d08d4c197db29a2fad62722072f"
@@ -4592,17 +5029,6 @@ glob@^7.1.3, glob@^7.1.4, glob@^7.1.6:
once "^1.3.0"
path-is-absolute "^1.0.0"
glob@^8.0.3:
version "8.1.0"
resolved "https://registry.yarnpkg.com/glob/-/glob-8.1.0.tgz#d388f656593ef708ee3e34640fdfb99a9fd1c33e"
integrity sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==
dependencies:
fs.realpath "^1.0.0"
inflight "^1.0.4"
inherits "2"
minimatch "^5.0.1"
once "^1.3.0"
globals@^11.1.0:
version "11.12.0"
resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e"
@@ -4615,6 +5041,11 @@ globals@^13.19.0:
dependencies:
type-fest "^0.20.2"
globals@^14.0.0:
version "14.0.0"
resolved "https://registry.yarnpkg.com/globals/-/globals-14.0.0.tgz#898d7413c29babcf6bafe56fcadded858ada724e"
integrity sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==
globby@^11.1.0:
version "11.1.0"
resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b"
@@ -4758,7 +5189,7 @@ ignore@^5.3.1:
resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5"
integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==
import-fresh@^3.2.1:
import-fresh@^3.2.1, import-fresh@^3.3.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b"
integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==
@@ -4804,13 +5235,6 @@ is-arrayish@^0.2.1:
resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==
is-builtin-module@^3.2.1:
version "3.2.1"
resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-3.2.1.tgz#f03271717d8654cfcaf07ab0463faa3571581169"
integrity sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==
dependencies:
builtin-modules "^3.3.0"
is-core-module@^2.11.0:
version "2.12.1"
resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.12.1.tgz#0c0b6885b6f80011c71541ce15c8d66cf5a4f9fd"
@@ -6154,6 +6578,11 @@ jsesc@~0.5.0:
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d"
integrity sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==
json-buffer@3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13"
integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==
json-diff@^0.5.4:
version "0.5.5"
resolved "https://registry.yarnpkg.com/json-diff/-/json-diff-0.5.5.tgz#24658ad200dbdd64ae8a56baf4d87b2b33d7196e"
@@ -6195,6 +6624,13 @@ keypress@~0.2.1:
resolved "https://registry.yarnpkg.com/keypress/-/keypress-0.2.1.tgz#1e80454250018dbad4c3fe94497d6e67b6269c77"
integrity sha512-HjorDJFNhnM4SicvaUXac0X77NiskggxJdesG72+O5zBKpSqKFCrqmndKVqpu3pFqkla0St6uGk8Ju0sCurrmg==
keyv@^4.5.4:
version "4.5.4"
resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93"
integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==
dependencies:
json-buffer "3.0.1"
kind-of@^6.0.2:
version "6.0.3"
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd"
@@ -6429,13 +6865,6 @@ minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2:
dependencies:
brace-expansion "^1.1.7"
minimatch@^5.0.1, minimatch@~5.1.2:
version "5.1.6"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96"
integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==
dependencies:
brace-expansion "^2.0.1"
minimatch@^9.0.4:
version "9.0.5"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5"
@@ -6443,6 +6872,13 @@ minimatch@^9.0.4:
dependencies:
brace-expansion "^2.0.1"
minimatch@~5.1.2:
version "5.1.6"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96"
integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==
dependencies:
brace-expansion "^2.0.1"
minimist@^1.2.8:
version "1.2.8"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c"
@@ -6724,6 +7160,11 @@ picomatch@^2.0.4, picomatch@^2.2.3, picomatch@^2.3.1:
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
picomatch@^4.0.2:
version "4.0.2"
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.2.tgz#77c742931e8f3b8820946c76cd0c1f13730d1dab"
integrity sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==
pify@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231"
@@ -7576,11 +8017,25 @@ type-fest@^0.21.3:
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37"
integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==
typescript-eslint@^8.16.0:
version "8.18.1"
resolved "https://registry.yarnpkg.com/typescript-eslint/-/typescript-eslint-8.18.1.tgz#197b284b6769678ed77d9868df180eeaf61108eb"
integrity sha512-Mlaw6yxuaDEPQvb/2Qwu3/TfgeBHy9iTJ3mTwe7OvpPmF6KPQjVOfGyEJpPv6Ez2C34OODChhXrzYw/9phI0MQ==
dependencies:
"@typescript-eslint/eslint-plugin" "8.18.1"
"@typescript-eslint/parser" "8.18.1"
"@typescript-eslint/utils" "8.18.1"
typescript@^5.4.3:
version "5.4.3"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.4.3.tgz#5c6fedd4c87bee01cd7a528a30145521f8e0feff"
integrity sha512-KrPd3PKaCLr78MalgiwJnA25Nm8HAmdwN3mYUYZgG/wizIo9EainNVQI9/yDavtVFRN2h3k8uf3GLHuhDMgEHg==
undici-types@~6.19.2:
version "6.19.8"
resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.19.8.tgz#35111c9d1437ab83a7cdc0abae2f26d88eda0a02"
integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==
unicode-canonical-property-names-ecmascript@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz#301acdc525631670d39f6146e0e77ff6bbdebddc"
@@ -14,8 +14,6 @@ let TestAct;
global.__DEV__ = process.env.NODE_ENV !== 'production';
expect.extend(require('../toWarnDev'));
describe('unmocked scheduler', () => {
beforeEach(() => {
jest.resetModules();
-284
View File
@@ -1,284 +0,0 @@
// copied from scripts/jest/matchers/toWarnDev.js
'use strict';
const {diff: jestDiff} = require('jest-diff');
const util = require('util');
function shouldIgnoreConsoleError(format, args) {
if (__DEV__) {
if (typeof format === 'string') {
if (format.indexOf('The above error occurred') === 0) {
// This looks like an error addendum from ReactFiberErrorLogger.
// Ignore it too.
return true;
}
}
} else {
if (
format != null &&
typeof format.message === 'string' &&
typeof format.stack === 'string' &&
args.length === 0
) {
// In production, ReactFiberErrorLogger logs error objects directly.
// They are noisy too so we'll try to ignore them.
return true;
}
}
// Looks legit
return false;
}
function normalizeCodeLocInfo(str) {
return str && str.replace(/at .+?:\d+/g, 'at **');
}
const createMatcherFor = consoleMethod =>
function matcher(callback, expectedMessages, options = {}) {
if (__DEV__) {
// Warn about incorrect usage of matcher.
if (typeof expectedMessages === 'string') {
expectedMessages = [expectedMessages];
} else if (!Array.isArray(expectedMessages)) {
throw Error(
`toWarnDev() requires a parameter of type string or an array of strings ` +
`but was given ${typeof expectedMessages}.`
);
}
if (
options != null &&
(typeof options !== 'object' || Array.isArray(options))
) {
throw new Error(
'toWarnDev() second argument, when present, should be an object. ' +
'Did you forget to wrap the messages into an array?'
);
}
if (arguments.length > 3) {
// `matcher` comes from Jest, so it's more than 2 in practice
throw new Error(
'toWarnDev() received more than two arguments. ' +
'Did you forget to wrap the messages into an array?'
);
}
const withoutStack = options.withoutStack;
const warningsWithoutComponentStack = [];
const warningsWithComponentStack = [];
const unexpectedWarnings = [];
let lastWarningWithMismatchingFormat = null;
let lastWarningWithExtraComponentStack = null;
// Catch errors thrown by the callback,
// But only rethrow them if all test expectations have been satisfied.
// Otherwise an Error in the callback can mask a failed expectation,
// and result in a test that passes when it shouldn't.
let caughtError;
const isLikelyAComponentStack = message =>
typeof message === 'string' && message.includes('\n in ');
const consoleSpy = (format, ...args) => {
// Ignore uncaught errors reported by jsdom
// and React addendums because they're too noisy.
if (
consoleMethod === 'error' &&
shouldIgnoreConsoleError(format, args)
) {
return;
}
const message = util.format(format, ...args);
const normalizedMessage = normalizeCodeLocInfo(message);
// Remember if the number of %s interpolations
// doesn't match the number of arguments.
// We'll fail the test if it happens.
let argIndex = 0;
format.replace(/%s/g, () => argIndex++);
if (argIndex !== args.length) {
lastWarningWithMismatchingFormat = {
format,
args,
expectedArgCount: argIndex,
};
}
// Protect against accidentally passing a component stack
// to warning() which already injects the component stack.
if (
args.length >= 2 &&
isLikelyAComponentStack(args[args.length - 1]) &&
isLikelyAComponentStack(args[args.length - 2])
) {
lastWarningWithExtraComponentStack = {
format,
};
}
for (let index = 0; index < expectedMessages.length; index++) {
const expectedMessage = expectedMessages[index];
if (
normalizedMessage === expectedMessage ||
normalizedMessage.includes(expectedMessage)
) {
if (isLikelyAComponentStack(normalizedMessage)) {
warningsWithComponentStack.push(normalizedMessage);
} else {
warningsWithoutComponentStack.push(normalizedMessage);
}
expectedMessages.splice(index, 1);
return;
}
}
let errorMessage;
if (expectedMessages.length === 0) {
errorMessage =
'Unexpected warning recorded: ' +
this.utils.printReceived(normalizedMessage);
} else if (expectedMessages.length === 1) {
errorMessage =
'Unexpected warning recorded: ' +
jestDiff(expectedMessages[0], normalizedMessage);
} else {
errorMessage =
'Unexpected warning recorded: ' +
jestDiff(expectedMessages, [normalizedMessage]);
}
// Record the call stack for unexpected warnings.
// We don't throw an Error here though,
// Because it might be suppressed by ReactFiberScheduler.
unexpectedWarnings.push(new Error(errorMessage));
};
// TODO Decide whether we need to support nested toWarn* expectations.
// If we don't need it, add a check here to see if this is already our spy,
// And throw an error.
const originalMethod = console[consoleMethod];
// Avoid using Jest's built-in spy since it can't be removed.
console[consoleMethod] = consoleSpy;
try {
callback();
} catch (error) {
caughtError = error;
} finally {
// Restore the unspied method so that unexpected errors fail tests.
console[consoleMethod] = originalMethod;
// Any unexpected Errors thrown by the callback should fail the test.
// This should take precedence since unexpected errors could block warnings.
if (caughtError) {
throw caughtError;
}
// Any unexpected warnings should be treated as a failure.
if (unexpectedWarnings.length > 0) {
return {
message: () => unexpectedWarnings[0].stack,
pass: false,
};
}
// Any remaining messages indicate a failed expectations.
if (expectedMessages.length > 0) {
return {
message: () =>
`Expected warning was not recorded:\n ${this.utils.printReceived(
expectedMessages[0]
)}`,
pass: false,
};
}
if (typeof withoutStack === 'number') {
// We're expecting a particular number of warnings without stacks.
if (withoutStack !== warningsWithoutComponentStack.length) {
return {
message: () =>
`Expected ${withoutStack} warnings without a component stack but received ${warningsWithoutComponentStack.length}:\n` +
warningsWithoutComponentStack.map(warning =>
this.utils.printReceived(warning)
),
pass: false,
};
}
} else if (withoutStack === true) {
// We're expecting that all warnings won't have the stack.
// If some warnings have it, it's an error.
if (warningsWithComponentStack.length > 0) {
return {
message: () =>
`Received warning unexpectedly includes a component stack:\n ${this.utils.printReceived(
warningsWithComponentStack[0]
)}\nIf this warning intentionally includes the component stack, remove ` +
`{withoutStack: true} from the toWarnDev() call. If you have a mix of ` +
`warnings with and without stack in one toWarnDev() call, pass ` +
`{withoutStack: N} where N is the number of warnings without stacks.`,
pass: false,
};
}
} else if (withoutStack === false || withoutStack === undefined) {
// We're expecting that all warnings *do* have the stack (default).
// If some warnings don't have it, it's an error.
if (warningsWithoutComponentStack.length > 0) {
return {
message: () =>
`Received warning unexpectedly does not include a component stack:\n ${this.utils.printReceived(
warningsWithoutComponentStack[0]
)}\nIf this warning intentionally omits the component stack, add ` +
`{withoutStack: true} to the toWarnDev() call.`,
pass: false,
};
}
} else {
throw Error(
`The second argument for toWarnDev(), when specified, must be an object. It may have a ` +
`property called "withoutStack" whose value may be undefined, boolean, or a number. ` +
`Instead received ${typeof withoutStack}.`
);
}
if (lastWarningWithMismatchingFormat !== null) {
return {
message: () =>
`Received ${
lastWarningWithMismatchingFormat.args.length
} arguments for a message with ${
lastWarningWithMismatchingFormat.expectedArgCount
} placeholders:\n ${this.utils.printReceived(
lastWarningWithMismatchingFormat.format
)}`,
pass: false,
};
}
if (lastWarningWithExtraComponentStack !== null) {
return {
message: () =>
`Received more than one component stack for a warning:\n ${this.utils.printReceived(
lastWarningWithExtraComponentStack.format
)}\nDid you accidentally pass a stack to warning() as the last argument? ` +
`Don't forget warning() already injects the component stack automatically.`,
pass: false,
};
}
return {pass: true};
}
} else {
// Any uncaught errors or warnings should fail tests in production mode.
callback();
return {pass: true};
}
};
module.exports = {
toLowPriorityWarnDev: createMatcherFor('warn'),
toWarnDev: createMatcherFor('error'),
};
@@ -22,6 +22,7 @@ let waitForPaint;
let assertLog;
let waitForThrow;
let act;
let assertConsoleErrorDev;
describe('ReactCache', () => {
beforeEach(() => {
@@ -39,6 +40,7 @@ describe('ReactCache', () => {
assertLog = InternalTestUtils.assertLog;
waitForThrow = InternalTestUtils.waitForThrow;
waitForPaint = InternalTestUtils.waitForPaint;
assertConsoleErrorDev = InternalTestUtils.assertConsoleErrorDev;
act = InternalTestUtils.act;
TextResource = createResource(
@@ -190,20 +192,31 @@ describe('ReactCache', () => {
);
if (__DEV__) {
await expect(async () => {
await waitForAll([
'App',
'Loading...',
await waitForAll([
'App',
'Loading...',
...(gate('enableSiblingPrerendering') ? ['App'] : []),
]);
}).toErrorDev([
...(gate('enableSiblingPrerendering') ? ['App'] : []),
]);
assertConsoleErrorDev([
'Invalid key type. Expected a string, number, symbol, or ' +
"boolean, but instead received: [ 'Hi', 100 ]\n\n" +
'To use non-primitive values as keys, you must pass a hash ' +
'function as the second argument to createResource().',
'function as the second argument to createResource().\n' +
' in App (at **)' +
(gate(flags => flags.enableOwnerStacks)
? ''
: '\n in Suspense (at **)'),
...(gate('enableSiblingPrerendering') ? ['Invalid key type'] : []),
...(gate('enableSiblingPrerendering')
? [
'Invalid key type. Expected a string, number, symbol, or ' +
"boolean, but instead received: [ 'Hi', 100 ]\n\n" +
'To use non-primitive values as keys, you must pass a hash ' +
'function as the second argument to createResource().\n' +
' in App (at **)',
]
: []),
]);
} else {
await waitForAll([
+474 -166
View File
@@ -1467,13 +1467,12 @@ describe('ReactFlight', () => {
const transport = ReactNoopFlightServer.render(<App />);
await expect(async () => {
await act(() => {
startTransition(() => {
ReactNoop.render(ReactNoopFlightClient.read(transport));
});
await act(() => {
startTransition(() => {
ReactNoop.render(ReactNoopFlightClient.read(transport));
});
}).toErrorDev(
});
assertConsoleErrorDev([
'Each child in a list should have a unique "key" prop.\n' +
'\n' +
'Check the render method of `Component`. See https://react.dev/link/warning-keys for more information.\n' +
@@ -1483,7 +1482,7 @@ describe('ReactFlight', () => {
? ''
: ' in Indirection (at **)\n') +
' in App (at **)',
);
]);
});
it('should trigger the inner most error boundary inside a Client Component', async () => {
@@ -1541,17 +1540,47 @@ describe('ReactFlight', () => {
return 123;
},
};
expect(() => {
const transport = ReactNoopFlightServer.render(<input value={obj} />);
ReactNoopFlightClient.read(transport);
}).toErrorDev(
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with toJSON methods are not supported. ' +
'Convert it manually to a simple value before passing it to props.\n' +
' <input value={{toJSON: ...}}>\n' +
' ^^^^^^^^^^^^^^^',
{withoutStack: true},
);
const transport = ReactNoopFlightServer.render(<input value={obj} />);
if (gate(flags => flags.enableOwnerStacks)) {
assertConsoleErrorDev(
[
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with toJSON methods are not supported. ' +
'Convert it manually to a simple value before passing it to props.\n' +
' <input value={{toJSON: ...}}>\n' +
' ^^^^^^^^^^^^^^^',
],
{withoutStack: true},
);
}
ReactNoopFlightClient.read(transport);
if (gate(flags => flags.enableOwnerStacks)) {
assertConsoleErrorDev([
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with toJSON methods are not supported. ' +
'Convert it manually to a simple value before passing it to props.\n' +
' <input value={{toJSON: ...}}>\n' +
' ^^^^^^^^^^^^^^^\n' +
' at (<anonymous>)',
]);
} else {
assertConsoleErrorDev(
[
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with toJSON methods are not supported. ' +
'Convert it manually to a simple value before passing it to props.\n' +
' <input value={{toJSON: ...}}>\n' +
' ^^^^^^^^^^^^^^^',
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with toJSON methods are not supported. ' +
'Convert it manually to a simple value before passing it to props.\n' +
' <input value={{toJSON: ...}}>\n' +
' ^^^^^^^^^^^^^^^',
],
{withoutStack: true},
);
}
});
it('should warn in DEV if a toJSON instance is passed to a host component child', () => {
@@ -1560,43 +1589,123 @@ describe('ReactFlight', () => {
return 123;
}
}
expect(() => {
const transport = ReactNoopFlightServer.render(
<div>Womp womp: {new MyError('spaghetti')}</div>,
);
ReactNoopFlightClient.read(transport);
}).toErrorDev(
'Error objects cannot be rendered as text children. Try formatting it using toString().\n' +
' <div>Womp womp: {Error}</div>\n' +
' ^^^^^^^',
{withoutStack: true},
const transport = ReactNoopFlightServer.render(
<div>Womp womp: {new MyError('spaghetti')}</div>,
);
if (gate(flags => flags.enableOwnerStacks)) {
assertConsoleErrorDev(
[
'Error objects cannot be rendered as text children. Try formatting it using toString().\n' +
' <div>Womp womp: {Error}</div>\n' +
' ^^^^^^^',
],
{withoutStack: true},
);
}
ReactNoopFlightClient.read(transport);
if (gate(flags => flags.enableOwnerStacks)) {
assertConsoleErrorDev([
'Error objects cannot be rendered as text children. Try formatting it using toString().\n' +
' <div>Womp womp: {Error}</div>\n' +
' ^^^^^^^\n' +
' at (<anonymous>)',
]);
} else {
assertConsoleErrorDev(
[
'Error objects cannot be rendered as text children. Try formatting it using toString().\n' +
' <div>Womp womp: {Error}</div>\n' +
' ^^^^^^^',
'Error objects cannot be rendered as text children. Try formatting it using toString().\n' +
' <div>Womp womp: {Error}</div>\n' +
' ^^^^^^^',
],
{withoutStack: true},
);
}
});
it('should warn in DEV if a special object is passed to a host component', () => {
expect(() => {
const transport = ReactNoopFlightServer.render(<input value={Math} />);
ReactNoopFlightClient.read(transport);
}).toErrorDev(
'Only plain objects can be passed to Client Components from Server Components. ' +
'Math objects are not supported.\n' +
' <input value={Math}>\n' +
' ^^^^^^',
{withoutStack: true},
);
const transport = ReactNoopFlightServer.render(<input value={Math} />);
if (gate(flags => flags.enableOwnerStacks)) {
assertConsoleErrorDev(
[
'Only plain objects can be passed to Client Components from Server Components. ' +
'Math objects are not supported.\n' +
' <input value={Math}>\n' +
' ^^^^^^',
],
{withoutStack: true},
);
}
ReactNoopFlightClient.read(transport);
if (gate(flags => flags.enableOwnerStacks)) {
assertConsoleErrorDev([
'Only plain objects can be passed to Client Components from Server Components. ' +
'Math objects are not supported.\n' +
' <input value={Math}>\n' +
' ^^^^^^\n' +
' at (<anonymous>)',
]);
} else {
assertConsoleErrorDev(
[
'Only plain objects can be passed to Client Components from Server Components. ' +
'Math objects are not supported.\n' +
' <input value={Math}>\n' +
' ^^^^^^',
'Only plain objects can be passed to Client Components from Server Components. ' +
'Math objects are not supported.\n' +
' <input value={Math}>\n' +
' ^^^^^^',
],
{withoutStack: true},
);
}
});
it('should warn in DEV if an object with symbols is passed to a host component', () => {
expect(() => {
const transport = ReactNoopFlightServer.render(
<input value={{[Symbol.iterator]: {}}} />,
);
ReactNoopFlightClient.read(transport);
}).toErrorDev(
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with symbol properties like Symbol.iterator are not supported.',
{withoutStack: true},
const transport = ReactNoopFlightServer.render(
<input value={{[Symbol.iterator]: {}}} />,
);
if (gate(flags => flags.enableOwnerStacks)) {
assertConsoleErrorDev(
[
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with symbol properties like Symbol.iterator are not supported.\n' +
' <input value={{}}>\n' +
' ^^^^',
],
{withoutStack: true},
);
}
ReactNoopFlightClient.read(transport);
if (gate(flags => flags.enableOwnerStacks)) {
assertConsoleErrorDev([
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with symbol properties like Symbol.iterator are not supported.\n' +
' <input value={{}}>\n' +
' ^^^^\n' +
' at (<anonymous>)',
]);
} else {
assertConsoleErrorDev(
[
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with symbol properties like Symbol.iterator are not supported.\n' +
' <input value={{}}>\n' +
' ^^^^',
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with symbol properties like Symbol.iterator are not supported.\n' +
' <input value={{}}>\n' +
' ^^^^',
],
{withoutStack: true},
);
}
});
it('should warn in DEV if a toJSON instance is passed to a Client Component', () => {
@@ -1609,14 +1718,47 @@ describe('ReactFlight', () => {
return <div>{value}</div>;
}
const Client = clientReference(ClientImpl);
expect(() => {
const transport = ReactNoopFlightServer.render(<Client value={obj} />);
ReactNoopFlightClient.read(transport);
}).toErrorDev(
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with toJSON methods are not supported.',
{withoutStack: true},
);
const transport = ReactNoopFlightServer.render(<Client value={obj} />);
if (gate(flags => flags.enableOwnerStacks)) {
assertConsoleErrorDev(
[
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with toJSON methods are not supported. ' +
'Convert it manually to a simple value before passing it to props.\n' +
' <... value={{toJSON: ...}}>\n' +
' ^^^^^^^^^^^^^^^',
],
{withoutStack: true},
);
}
ReactNoopFlightClient.read(transport);
if (gate(flags => flags.enableOwnerStacks)) {
assertConsoleErrorDev([
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with toJSON methods are not supported. ' +
'Convert it manually to a simple value before passing it to props.\n' +
' <... value={{toJSON: ...}}>\n' +
' ^^^^^^^^^^^^^^^\n' +
' at (<anonymous>)',
]);
} else {
assertConsoleErrorDev(
[
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with toJSON methods are not supported. ' +
'Convert it manually to a simple value before passing it to props.\n' +
' <... value={{toJSON: ...}}>\n' +
' ^^^^^^^^^^^^^^^',
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with toJSON methods are not supported. ' +
'Convert it manually to a simple value before passing it to props.\n' +
' <... value={{toJSON: ...}}>\n' +
' ^^^^^^^^^^^^^^^',
],
{withoutStack: true},
);
}
});
it('should warn in DEV if a toJSON instance is passed to a Client Component child', () => {
@@ -1629,19 +1771,49 @@ describe('ReactFlight', () => {
return <div>{children}</div>;
}
const Client = clientReference(ClientImpl);
expect(() => {
const transport = ReactNoopFlightServer.render(
<Client>Current date: {obj}</Client>,
);
ReactNoopFlightClient.read(transport);
}).toErrorDev(
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with toJSON methods are not supported. ' +
'Convert it manually to a simple value before passing it to props.\n' +
' <>Current date: {{toJSON: ...}}</>\n' +
' ^^^^^^^^^^^^^^^',
{withoutStack: true},
const transport = ReactNoopFlightServer.render(
<Client>Current date: {obj}</Client>,
);
if (gate(flags => flags.enableOwnerStacks)) {
assertConsoleErrorDev(
[
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with toJSON methods are not supported. ' +
'Convert it manually to a simple value before passing it to props.\n' +
' <>Current date: {{toJSON: ...}}</>\n' +
' ^^^^^^^^^^^^^^^',
],
{withoutStack: true},
);
}
ReactNoopFlightClient.read(transport);
if (gate(flags => flags.enableOwnerStacks)) {
assertConsoleErrorDev([
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with toJSON methods are not supported. ' +
'Convert it manually to a simple value before passing it to props.\n' +
' <>Current date: {{toJSON: ...}}</>\n' +
' ^^^^^^^^^^^^^^^\n' +
' at (<anonymous>)',
]);
} else {
assertConsoleErrorDev(
[
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with toJSON methods are not supported. ' +
'Convert it manually to a simple value before passing it to props.\n' +
' <>Current date: {{toJSON: ...}}</>\n' +
' ^^^^^^^^^^^^^^^',
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with toJSON methods are not supported. ' +
'Convert it manually to a simple value before passing it to props.\n' +
' <>Current date: {{toJSON: ...}}</>\n' +
' ^^^^^^^^^^^^^^^',
],
{withoutStack: true},
);
}
});
it('should warn in DEV if a special object is passed to a Client Component', () => {
@@ -1649,16 +1821,44 @@ describe('ReactFlight', () => {
return <div>{value}</div>;
}
const Client = clientReference(ClientImpl);
expect(() => {
const transport = ReactNoopFlightServer.render(<Client value={Math} />);
ReactNoopFlightClient.read(transport);
}).toErrorDev(
'Only plain objects can be passed to Client Components from Server Components. ' +
'Math objects are not supported.\n' +
' <... value={Math}>\n' +
' ^^^^^^',
{withoutStack: true},
);
const transport = ReactNoopFlightServer.render(<Client value={Math} />);
if (gate(flags => flags.enableOwnerStacks)) {
assertConsoleErrorDev(
[
'Only plain objects can be passed to Client Components from Server Components. ' +
'Math objects are not supported.\n' +
' <... value={Math}>\n' +
' ^^^^^^',
],
{withoutStack: true},
);
}
ReactNoopFlightClient.read(transport);
if (gate(flags => flags.enableOwnerStacks)) {
assertConsoleErrorDev([
'Only plain objects can be passed to Client Components from Server Components. ' +
'Math objects are not supported.\n' +
' <... value={Math}>\n' +
' ^^^^^^\n' +
' at (<anonymous>)',
]);
} else {
assertConsoleErrorDev(
[
'Only plain objects can be passed to Client Components from Server Components. ' +
'Math objects are not supported.\n' +
' <... value={Math}>\n' +
' ^^^^^^',
'Only plain objects can be passed to Client Components from Server Components. ' +
'Math objects are not supported.\n' +
' <... value={Math}>\n' +
' ^^^^^^',
],
{withoutStack: true},
);
}
});
it('should warn in DEV if an object with symbols is passed to a Client Component', () => {
@@ -1666,16 +1866,46 @@ describe('ReactFlight', () => {
return <div>{value}</div>;
}
const Client = clientReference(ClientImpl);
expect(() => {
const transport = ReactNoopFlightServer.render(
<Client value={{[Symbol.iterator]: {}}} />,
);
ReactNoopFlightClient.read(transport);
}).toErrorDev(
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with symbol properties like Symbol.iterator are not supported.',
{withoutStack: true},
assertConsoleErrorDev([]);
const transport = ReactNoopFlightServer.render(
<Client value={{[Symbol.iterator]: {}}} />,
);
if (gate(flags => flags.enableOwnerStacks)) {
assertConsoleErrorDev(
[
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with symbol properties like Symbol.iterator are not supported.\n' +
' <... value={{}}>\n' +
' ^^^^',
],
{withoutStack: true},
);
}
ReactNoopFlightClient.read(transport);
if (gate(flags => flags.enableOwnerStacks)) {
assertConsoleErrorDev([
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with symbol properties like Symbol.iterator are not supported.\n' +
' <... value={{}}>\n' +
' ^^^^\n',
]);
} else {
assertConsoleErrorDev(
[
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with symbol properties like Symbol.iterator are not supported.\n' +
' <... value={{}}>\n' +
' ^^^^',
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with symbol properties like Symbol.iterator are not supported.\n' +
' <... value={{}}>\n' +
' ^^^^',
],
{withoutStack: true},
);
}
});
it('should warn in DEV if a special object is passed to a nested object in Client Component', () => {
@@ -1683,18 +1913,41 @@ describe('ReactFlight', () => {
return <div>{value}</div>;
}
const Client = clientReference(ClientImpl);
expect(() => {
const transport = ReactNoopFlightServer.render(
<Client value={{hello: Math, title: <h1>hi</h1>}} />,
);
ReactNoopFlightClient.read(transport);
}).toErrorDev(
'Only plain objects can be passed to Client Components from Server Components. ' +
'Math objects are not supported.\n' +
' {hello: Math, title: <h1/>}\n' +
' ^^^^',
{withoutStack: true},
const transport = ReactNoopFlightServer.render(
<Client value={{[Symbol.iterator]: {}}} />,
);
ReactNoopFlightClient.read(transport);
if (gate(flags => flags.enableOwnerStacks)) {
assertConsoleErrorDev([
[
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with symbol properties like Symbol.iterator are not supported.\n' +
' <... value={{}}>\n' +
' ^^^^',
{withoutStack: true},
],
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with symbol properties like Symbol.iterator are not supported.\n' +
' <... value={{}}>\n' +
' ^^^^\n' +
' at (<anonymous>)',
]);
} else {
assertConsoleErrorDev(
[
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with symbol properties like Symbol.iterator are not supported.\n' +
' <... value={{}}>\n' +
' ^^^^',
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with symbol properties like Symbol.iterator are not supported.\n' +
' <... value={{}}>\n' +
' ^^^^',
],
{withoutStack: true},
);
}
});
it('should warn in DEV if a special object is passed to a nested array in Client Component', () => {
@@ -1702,20 +1955,40 @@ describe('ReactFlight', () => {
return <div>{value}</div>;
}
const Client = clientReference(ClientImpl);
expect(() => {
const transport = ReactNoopFlightServer.render(
<Client
value={['looooong string takes up noise', Math, <h1>hi</h1>]}
/>,
);
ReactNoopFlightClient.read(transport);
}).toErrorDev(
'Only plain objects can be passed to Client Components from Server Components. ' +
'Math objects are not supported.\n' +
' [..., Math, <h1/>]\n' +
' ^^^^',
{withoutStack: true},
const transport = ReactNoopFlightServer.render(
<Client value={['looooong string takes up noise', Math, <h1>hi</h1>]} />,
);
ReactNoopFlightClient.read(transport);
if (gate(flags => flags.enableOwnerStacks)) {
assertConsoleErrorDev([
[
'Only plain objects can be passed to Client Components from Server Components. ' +
'Math objects are not supported.\n' +
' [..., Math, <h1/>]\n' +
' ^^^^',
{withoutStack: true},
],
'Only plain objects can be passed to Client Components from Server Components. ' +
'Math objects are not supported.\n' +
' [..., Math, <h1/>]\n' +
' ^^^^\n' +
' at (<anonymous>)',
]);
} else {
assertConsoleErrorDev(
[
'Only plain objects can be passed to Client Components from Server Components. ' +
'Math objects are not supported.\n' +
' [..., Math, <h1/>]\n' +
' ^^^^',
'Only plain objects can be passed to Client Components from Server Components. ' +
'Math objects are not supported.\n' +
' [..., Math, <h1/>]\n' +
' ^^^^',
],
{withoutStack: true},
);
}
});
it('should NOT warn in DEV for key getters', () => {
@@ -1729,63 +2002,100 @@ describe('ReactFlight', () => {
key: "this has a key but parent doesn't",
});
}
expect(() => {
// While we're on the server we need to have the Server version active to track component stacks.
jest.resetModules();
jest.mock('react', () => ReactServer);
const transport = ReactNoopFlightServer.render(
ReactServer.createElement(
'div',
null,
Array(6).fill(ReactServer.createElement(NoKey)),
),
);
jest.resetModules();
jest.mock('react', () => React);
ReactNoopFlightClient.read(transport);
}).toErrorDev('Each child in a list should have a unique "key" prop.');
// While we're on the server we need to have the Server version active to track component stacks.
jest.resetModules();
jest.mock('react', () => ReactServer);
const transport = ReactNoopFlightServer.render(
ReactServer.createElement(
'div',
null,
Array(6).fill(ReactServer.createElement(NoKey)),
),
);
jest.resetModules();
jest.mock('react', () => React);
ReactNoopFlightClient.read(transport);
if (gate(flags => flags.enableOwnerStacks)) {
assertConsoleErrorDev([
'Each child in a list should have a unique "key" prop. ' +
'See https://react.dev/link/warning-keys for more information.\n' +
' in NoKey (at **)',
'Each child in a list should have a unique "key" prop. ' +
'See https://react.dev/link/warning-keys for more information.\n' +
' in NoKey (at **)',
]);
} else {
assertConsoleErrorDev([
'Each child in a list should have a unique "key" prop.\n\n' +
'Check the top-level render call using <div>. ' +
'See https://react.dev/link/warning-keys for more information.\n' +
' in NoKey (at **)',
]);
}
});
// @gate !__DEV__ || enableOwnerStacks
it('should warn in DEV a child is missing keys on a fragment', () => {
expect(() => {
// While we're on the server we need to have the Server version active to track component stacks.
jest.resetModules();
jest.mock('react', () => ReactServer);
const transport = ReactNoopFlightServer.render(
ReactServer.createElement(
'div',
null,
Array(6).fill(ReactServer.createElement(ReactServer.Fragment)),
),
);
jest.resetModules();
jest.mock('react', () => React);
ReactNoopFlightClient.read(transport);
}).toErrorDev('Each child in a list should have a unique "key" prop.');
// While we're on the server we need to have the Server version active to track component stacks.
jest.resetModules();
jest.mock('react', () => ReactServer);
const transport = ReactNoopFlightServer.render(
ReactServer.createElement(
'div',
null,
Array(6).fill(ReactServer.createElement(ReactServer.Fragment)),
),
);
jest.resetModules();
jest.mock('react', () => React);
ReactNoopFlightClient.read(transport);
if (gate(flags => flags.enableOwnerStacks)) {
assertConsoleErrorDev([
'Each child in a list should have a unique "key" prop. ' +
'See https://react.dev/link/warning-keys for more information.\n' +
' in Fragment (at **)',
'Each child in a list should have a unique "key" prop. ' +
'See https://react.dev/link/warning-keys for more information.\n' +
' in Fragment (at **)',
]);
} else {
assertConsoleErrorDev([
'Each child in a list should have a unique "key" prop.\n\n' +
'Check the top-level render call using <div>. ' +
'See https://react.dev/link/warning-keys for more information.\n' +
' in Fragment (at **)',
]);
}
});
it('should warn in DEV a child is missing keys in client component', async () => {
function ParentClient({children}) {
return children;
}
const Parent = clientReference(ParentClient);
await expect(async () => {
await act(async () => {
const Parent = clientReference(ParentClient);
const transport = ReactNoopFlightServer.render(
<Parent>{Array(6).fill(<div>no key</div>)}</Parent>,
);
ReactNoopFlightClient.read(transport);
await act(async () => {
ReactNoop.render(await ReactNoopFlightClient.read(transport));
});
}).toErrorDev(
gate(flags => flags.enableOwnerStacks)
? 'Each child in a list should have a unique "key" prop.' +
'\n\nCheck the top-level render call using <ParentClient>. ' +
'See https://react.dev/link/warning-keys for more information.'
: 'Each child in a list should have a unique "key" prop. ' +
'See https://react.dev/link/warning-keys for more information.',
);
ReactNoop.render(await ReactNoopFlightClient.read(transport));
});
if (gate(flags => flags.enableOwnerStacks)) {
assertConsoleErrorDev([
'Each child in a list should have a unique "key" prop.\n\n' +
'Check the top-level render call using <ParentClient>. ' +
'See https://react.dev/link/warning-keys for more information.\n' +
' in div (at **)',
]);
} else {
assertConsoleErrorDev([
'Each child in a list should have a unique "key" prop. ' +
'See https://react.dev/link/warning-keys for more information.\n' +
' in div (at **)',
]);
}
});
it('should error if a class instance is passed to a host component', () => {
@@ -3135,19 +3445,17 @@ describe('ReactFlight', () => {
},
);
let transport;
expect(() => {
// Reset the modules so that we get a new overridden console on top of the
// one installed by expect. This ensures that we still emit console.error
// calls.
jest.resetModules();
jest.mock('react', () => require('react/react.react-server'));
ReactServer = require('react');
ReactNoopFlightServer = require('react-noop-renderer/flight-server');
transport = ReactNoopFlightServer.render({
root: ReactServer.createElement(App),
});
}).toErrorDev('err');
// Reset the modules so that we get a new overridden console on top of the
// one installed by expect. This ensures that we still emit console.error
// calls.
jest.resetModules();
jest.mock('react', () => require('react/react.react-server'));
ReactServer = require('react');
ReactNoopFlightServer = require('react-noop-renderer/flight-server');
const transport = ReactNoopFlightServer.render({
root: ReactServer.createElement(App),
});
assertConsoleErrorDev(['Error: err']);
expect(mockConsoleLog).toHaveBeenCalledTimes(1);
expect(mockConsoleLog.mock.calls[0][0]).toBe('hi');
@@ -14,6 +14,7 @@ let React;
let ReactTestRenderer;
let ReactDebugTools;
let act;
let assertConsoleErrorDev;
let useMemoCache;
function normalizeSourceLoc(tree) {
@@ -33,7 +34,7 @@ describe('ReactHooksInspectionIntegration', () => {
jest.resetModules();
React = require('react');
ReactTestRenderer = require('react-test-renderer');
act = require('internal-test-utils').act;
({act, assertConsoleErrorDev} = require('internal-test-utils'));
ReactDebugTools = require('react-debug-tools');
useMemoCache = require('react/compiler-runtime').c;
});
@@ -2344,10 +2345,12 @@ describe('ReactHooksInspectionIntegration', () => {
</Suspense>,
);
await expect(async () => {
await act(async () => await LazyFoo);
}).toErrorDev([
'Foo: Support for defaultProps will be removed from function components in a future major release. Use JavaScript default parameters instead.',
await act(async () => await LazyFoo);
assertConsoleErrorDev([
'Foo: Support for defaultProps will be removed from function components in a future major release. Use JavaScript default parameters instead.' +
(gate(flags => flags.enableOwnerStacks)
? ''
: '\n in Foo (at **)\n' + ' in Suspense (at **)'),
]);
const childFiber = renderer.root._currentFiber();
@@ -14,6 +14,7 @@ describe('when Trusted Types are available in global object', () => {
let ReactDOMClient;
let ReactFeatureFlags;
let act;
let assertConsoleErrorDev;
let container;
let ttObject1;
let ttObject2;
@@ -36,7 +37,7 @@ describe('when Trusted Types are available in global object', () => {
ReactFeatureFlags.enableTrustedTypesIntegration = true;
React = require('react');
ReactDOMClient = require('react-dom/client');
act = require('internal-test-utils').act;
({act, assertConsoleErrorDev} = require('internal-test-utils'));
ttObject1 = {
toString() {
return '<b>Hi</b>';
@@ -208,17 +209,16 @@ describe('when Trusted Types are available in global object', () => {
it('should warn once when rendering script tag in jsx on client', async () => {
const root = ReactDOMClient.createRoot(container);
await expect(async () => {
await act(() => {
root.render(<script>alert("I am not executed")</script>);
});
}).toErrorDev(
await act(() => {
root.render(<script>alert("I am not executed")</script>);
});
assertConsoleErrorDev([
'Encountered a script tag while rendering React component. ' +
'Scripts inside React components are never executed when rendering ' +
'on the client. Consider using template tag instead ' +
'(https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template).\n' +
' in script (at **)',
);
]);
// check that the warning is printed only once
await act(() => {
@@ -16,6 +16,7 @@ let ReactNativePrivateInterface;
let createReactNativeComponentClass;
let StrictMode;
let act;
let assertConsoleErrorDev;
const DISPATCH_COMMAND_REQUIRES_HOST_COMPONENT =
"dispatchCommand was called with a ref that isn't a " +
@@ -38,7 +39,7 @@ describe('ReactFabric', () => {
createReactNativeComponentClass =
require('react-native/Libraries/ReactPrivate/ReactNativePrivateInterface')
.ReactNativeViewConfigRegistry.register;
act = require('internal-test-utils').act;
({act, assertConsoleErrorDev} = require('internal-test-utils'));
});
it('should be able to create and render a native component', async () => {
@@ -459,9 +460,8 @@ describe('ReactFabric', () => {
});
expect(nativeFabricUIManager.dispatchCommand).not.toBeCalled();
expect(() => {
ReactFabric.dispatchCommand(viewRef, 'updateCommand', [10, 20]);
}).toErrorDev([DISPATCH_COMMAND_REQUIRES_HOST_COMPONENT], {
ReactFabric.dispatchCommand(viewRef, 'updateCommand', [10, 20]);
assertConsoleErrorDev([DISPATCH_COMMAND_REQUIRES_HOST_COMPONENT], {
withoutStack: true,
});
@@ -525,9 +525,8 @@ describe('ReactFabric', () => {
});
expect(nativeFabricUIManager.sendAccessibilityEvent).not.toBeCalled();
expect(() => {
ReactFabric.sendAccessibilityEvent(viewRef, 'eventTypeName');
}).toErrorDev([SEND_ACCESSIBILITY_EVENT_REQUIRES_HOST_COMPONENT], {
ReactFabric.sendAccessibilityEvent(viewRef, 'eventTypeName');
assertConsoleErrorDev([SEND_ACCESSIBILITY_EVENT_REQUIRES_HOST_COMPONENT], {
withoutStack: true,
});
@@ -856,24 +855,31 @@ describe('ReactFabric', () => {
uiViewClassName: 'RCTView',
}));
await expect(async () => {
await act(() => {
ReactFabric.render(<View>this should warn</View>, 11, null, true);
});
}).toErrorDev(['Text strings must be rendered within a <Text> component.']);
await act(() => {
ReactFabric.render(<View>this should warn</View>, 11, null, true);
});
assertConsoleErrorDev([
'Text strings must be rendered within a <Text> component.\n' +
' in RCTView (at **)',
]);
await expect(async () => {
await act(() => {
ReactFabric.render(
<Text>
<ScrollView>hi hello hi</ScrollView>
</Text>,
11,
null,
true,
);
});
}).toErrorDev(['Text strings must be rendered within a <Text> component.']);
await act(() => {
ReactFabric.render(
<Text>
<ScrollView>hi hello hi</ScrollView>
</Text>,
11,
null,
true,
);
});
assertConsoleErrorDev([
'Text strings must be rendered within a <Text> component.\n' +
' in RCTScrollView (at **)' +
(gate(flags => !flags.enableOwnerStacks)
? '\n in RCTText (at **)'
: ''),
]);
});
it('should not throw for text inside of an indirect <Text> ancestor', async () => {
@@ -1166,10 +1172,8 @@ describe('ReactFabric', () => {
);
});
let match;
expect(
() => (match = ReactFabric.findHostInstance_DEPRECATED(parent)),
).toErrorDev([
const match = ReactFabric.findHostInstance_DEPRECATED(parent);
assertConsoleErrorDev([
'findHostInstance_DEPRECATED is deprecated in StrictMode. ' +
'findHostInstance_DEPRECATED was passed an instance of ContainsStrictModeChild which renders StrictMode children. ' +
'Instead, add a ref directly to the element you want to reference. ' +
@@ -1207,10 +1211,8 @@ describe('ReactFabric', () => {
);
});
let match;
expect(
() => (match = ReactFabric.findHostInstance_DEPRECATED(parent)),
).toErrorDev([
const match = ReactFabric.findHostInstance_DEPRECATED(parent);
assertConsoleErrorDev([
'findHostInstance_DEPRECATED is deprecated in StrictMode. ' +
'findHostInstance_DEPRECATED was passed an instance of IsInStrictMode which is inside StrictMode. ' +
'Instead, add a ref directly to the element you want to reference. ' +
@@ -1250,8 +1252,8 @@ describe('ReactFabric', () => {
);
});
let match;
expect(() => (match = ReactFabric.findNodeHandle(parent))).toErrorDev([
const match = ReactFabric.findNodeHandle(parent);
assertConsoleErrorDev([
'findNodeHandle is deprecated in StrictMode. ' +
'findNodeHandle was passed an instance of ContainsStrictModeChild which renders StrictMode children. ' +
'Instead, add a ref directly to the element you want to reference. ' +
@@ -1291,8 +1293,8 @@ describe('ReactFabric', () => {
);
});
let match;
expect(() => (match = ReactFabric.findNodeHandle(parent))).toErrorDev([
const match = ReactFabric.findNodeHandle(parent);
assertConsoleErrorDev([
'findNodeHandle is deprecated in StrictMode. ' +
'findNodeHandle was passed an instance of IsInStrictMode which is inside StrictMode. ' +
'Instead, add a ref directly to the element you want to reference. ' +
@@ -1313,16 +1315,16 @@ describe('ReactFabric', () => {
return null;
}
}
await expect(async () => {
await act(() => {
ReactFabric.render(<TestComponent />, 11, null, true);
});
}).toErrorDev([
await act(() => {
ReactFabric.render(<TestComponent />, 11, null, true);
});
assertConsoleErrorDev([
'TestComponent is accessing findNodeHandle inside its render(). ' +
'render() should be a pure function of props and state. It should ' +
'never access something that requires stale data from the previous ' +
'render, such as refs. Move this logic to componentDidMount and ' +
'componentDidUpdate instead.',
'componentDidUpdate instead.\n' +
' in TestComponent (at **)',
]);
});
@@ -18,6 +18,7 @@ let ReactNative;
let ResponderEventPlugin;
let UIManager;
let createReactNativeComponentClass;
let assertConsoleErrorDev;
// Parallels requireNativeComponent() in that it lazily constructs a view config,
// And registers view manager event types with ReactNativeViewConfigRegistry.
@@ -69,6 +70,7 @@ beforeEach(() => {
require('react-native/Libraries/ReactPrivate/ReactNativePrivateInterface').RCTEventEmitter;
React = require('react');
act = require('internal-test-utils').act;
assertConsoleErrorDev = require('internal-test-utils').assertConsoleErrorDev;
ReactNative = require('react-native-renderer');
ResponderEventPlugin =
require('react-native-renderer/src/legacy-events/ResponderEventPlugin').default;
@@ -227,30 +229,32 @@ test('handles events on text nodes', () => {
}
const log = [];
expect(() => {
ReactNative.render(
<ContextHack>
<Text>
<Text
onTouchEnd={() => log.push('string touchend')}
onTouchEndCapture={() => log.push('string touchend capture')}
onTouchStart={() => log.push('string touchstart')}
onTouchStartCapture={() => log.push('string touchstart capture')}>
Text Content
</Text>
<Text
onTouchEnd={() => log.push('number touchend')}
onTouchEndCapture={() => log.push('number touchend capture')}
onTouchStart={() => log.push('number touchstart')}
onTouchStartCapture={() => log.push('number touchstart capture')}>
{123}
</Text>
ReactNative.render(
<ContextHack>
<Text>
<Text
onTouchEnd={() => log.push('string touchend')}
onTouchEndCapture={() => log.push('string touchend capture')}
onTouchStart={() => log.push('string touchstart')}
onTouchStartCapture={() => log.push('string touchstart capture')}>
Text Content
</Text>
</ContextHack>,
1,
);
}).toErrorDev([
'ContextHack uses the legacy childContextTypes API which will soon be removed. Use React.createContext() instead.',
<Text
onTouchEnd={() => log.push('number touchend')}
onTouchEndCapture={() => log.push('number touchend capture')}
onTouchStart={() => log.push('number touchstart')}
onTouchStartCapture={() => log.push('number touchstart capture')}>
{123}
</Text>
</Text>
</ContextHack>,
1,
);
assertConsoleErrorDev([
'ContextHack uses the legacy childContextTypes API which will soon be removed. ' +
'Use React.createContext() instead. ' +
'(https://react.dev/link/legacy-context)' +
'\n in ContextHack (at **)',
]);
expect(UIManager.createView).toHaveBeenCalledTimes(5);
@@ -18,6 +18,7 @@ let UIManager;
let TextInputState;
let ReactNativePrivateInterface;
let act;
let assertConsoleErrorDev;
const DISPATCH_COMMAND_REQUIRES_HOST_COMPONENT =
"dispatchCommand was called with a ref that isn't a " +
@@ -32,7 +33,7 @@ describe('ReactNative', () => {
jest.resetModules();
React = require('react');
act = require('internal-test-utils').act;
({act, assertConsoleErrorDev} = require('internal-test-utils'));
StrictMode = React.StrictMode;
ReactNative = require('react-native-renderer');
ReactNativePrivateInterface = require('react-native/Libraries/ReactPrivate/ReactNativePrivateInterface');
@@ -158,9 +159,8 @@ describe('ReactNative', () => {
);
expect(UIManager.dispatchViewManagerCommand).not.toBeCalled();
expect(() => {
ReactNative.dispatchCommand(viewRef, 'updateCommand', [10, 20]);
}).toErrorDev([DISPATCH_COMMAND_REQUIRES_HOST_COMPONENT], {
ReactNative.dispatchCommand(viewRef, 'updateCommand', [10, 20]);
assertConsoleErrorDev([DISPATCH_COMMAND_REQUIRES_HOST_COMPONENT], {
withoutStack: true,
});
@@ -219,9 +219,8 @@ describe('ReactNative', () => {
);
expect(UIManager.sendAccessibilityEvent).not.toBeCalled();
expect(() => {
ReactNative.sendAccessibilityEvent(viewRef, 'updateCommand', [10, 20]);
}).toErrorDev([SEND_ACCESSIBILITY_EVENT_REQUIRES_HOST_COMPONENT], {
ReactNative.sendAccessibilityEvent(viewRef, 'updateCommand', [10, 20]);
assertConsoleErrorDev([SEND_ACCESSIBILITY_EVENT_REQUIRES_HOST_COMPONENT], {
withoutStack: true,
});
@@ -614,10 +613,8 @@ describe('ReactNative', () => {
ReactNative.render(<ContainsStrictModeChild ref={n => (parent = n)} />, 11);
let match;
expect(
() => (match = ReactNative.findHostInstance_DEPRECATED(parent)),
).toErrorDev([
const match = ReactNative.findHostInstance_DEPRECATED(parent);
assertConsoleErrorDev([
'findHostInstance_DEPRECATED is deprecated in StrictMode. ' +
'findHostInstance_DEPRECATED was passed an instance of ContainsStrictModeChild which renders StrictMode children. ' +
'Instead, add a ref directly to the element you want to reference. ' +
@@ -652,10 +649,8 @@ describe('ReactNative', () => {
11,
);
let match;
expect(
() => (match = ReactNative.findHostInstance_DEPRECATED(parent)),
).toErrorDev([
const match = ReactNative.findHostInstance_DEPRECATED(parent);
assertConsoleErrorDev([
'findHostInstance_DEPRECATED is deprecated in StrictMode. ' +
'findHostInstance_DEPRECATED was passed an instance of IsInStrictMode which is inside StrictMode. ' +
'Instead, add a ref directly to the element you want to reference. ' +
@@ -689,8 +684,8 @@ describe('ReactNative', () => {
ReactNative.render(<ContainsStrictModeChild ref={n => (parent = n)} />, 11);
let match;
expect(() => (match = ReactNative.findNodeHandle(parent))).toErrorDev([
const match = ReactNative.findNodeHandle(parent);
assertConsoleErrorDev([
'findNodeHandle is deprecated in StrictMode. ' +
'findNodeHandle was passed an instance of ContainsStrictModeChild which renders StrictMode children. ' +
'Instead, add a ref directly to the element you want to reference. ' +
@@ -725,8 +720,8 @@ describe('ReactNative', () => {
11,
);
let match;
expect(() => (match = ReactNative.findNodeHandle(parent))).toErrorDev([
const match = ReactNative.findNodeHandle(parent);
assertConsoleErrorDev([
'findNodeHandle is deprecated in StrictMode. ' +
'findNodeHandle was passed an instance of IsInStrictMode which is inside StrictMode. ' +
'Instead, add a ref directly to the element you want to reference. ' +
@@ -233,8 +233,28 @@ describe('ReactLazy', () => {
expect(error.message).toMatch('Element type is invalid');
assertLog(['Loading...']);
assertConsoleErrorDev([
'Expected the result of a dynamic import() call',
'Expected the result of a dynamic import() call',
'lazy: Expected the result of a dynamic import() call. ' +
'Instead received: function Text(props) {\n' +
' Scheduler.log(props.text);\n' +
' return props.text;\n' +
' }\n\n' +
'Your code should look like: \n ' +
"const MyComponent = lazy(() => import('./MyComponent'))\n" +
(gate('enableOwnerStacks')
? ''
: ' in Lazy (at **)\n' + ' in Suspense (at **)\n') +
' in App (at **)',
'lazy: Expected the result of a dynamic import() call. ' +
'Instead received: function Text(props) {\n' +
' Scheduler.log(props.text);\n' +
' return props.text;\n' +
' }\n\n' +
'Your code should look like: \n ' +
"const MyComponent = lazy(() => import('./MyComponent'))\n" +
(gate('enableOwnerStacks')
? ''
: ' in Lazy (at **)\n' + ' in Suspense (at **)\n') +
' in App (at **)',
]);
expect(root).not.toMatchRenderedOutput('Hi');
});
@@ -852,19 +872,21 @@ describe('ReactLazy', () => {
expect(root).not.toMatchRenderedOutput('22');
// Mount
await expect(async () => {
await act(() => resolveFakeImport(Add));
}).toErrorDev(
shouldWarnAboutFunctionDefaultProps
? [
'Add: Support for defaultProps will be removed from function components in a future major release. Use JavaScript default parameters instead.',
]
: shouldWarnAboutMemoDefaultProps
? [
'Add: Support for defaultProps will be removed from memo components in a future major release. Use JavaScript default parameters instead.',
]
: [],
);
await act(() => resolveFakeImport(Add));
if (shouldWarnAboutFunctionDefaultProps) {
assertConsoleErrorDev([
'Add: Support for defaultProps will be removed from function components in a future major release. Use JavaScript default parameters instead.\n' +
' in Add (at **)\n' +
' in Suspense (at **)',
]);
} else if (shouldWarnAboutMemoDefaultProps) {
assertConsoleErrorDev([
'Add: Support for defaultProps will be removed from memo components in a future major release. Use JavaScript default parameters instead.\n' +
' in Suspense (at **)',
]);
}
expect(root).toMatchRenderedOutput('22');
// Update
@@ -491,4 +491,46 @@ describe('ReactSuspenseyCommitPhase', () => {
</>,
);
});
// FIXME: Should pass with `enableYieldingBeforePassive`
// @gate !enableYieldingBeforePassive
it('runs passive effects after suspended commit resolves', async () => {
function Effect() {
React.useEffect(() => {
Scheduler.log('flush effect');
});
return <Text text="render effect" />;
}
const root = ReactNoop.createRoot();
await act(() => {
root.render(
<Suspense fallback={<Text text="Loading..." />}>
<Effect />
<SuspenseyImage src="A" />
</Suspense>,
);
});
assertLog([
'render effect',
'Image requested [A]',
'Loading...',
'render effect',
]);
expect(root).toMatchRenderedOutput('Loading...');
await act(() => {
resolveSuspenseyThing('A');
});
assertLog(['flush effect']);
expect(root).toMatchRenderedOutput(
<>
{'render effect'}
<suspensey-thing src="A" />
</>,
);
});
});
@@ -9,6 +9,7 @@ if (process.env.NODE_ENV === 'production') {
exports.renderToReadableStream = s.renderToReadableStream;
exports.decodeReply = s.decodeReply;
exports.decodeReplyFromAsyncIterable = s.decodeReplyFromAsyncIterable;
exports.decodeAction = s.decodeAction;
exports.decodeFormState = s.decodeFormState;
exports.createClientReference = s.createClientReference;
@@ -10,6 +10,7 @@
export {
renderToReadableStream,
decodeReply,
decodeReplyFromAsyncIterable,
decodeAction,
decodeFormState,
createClientReference,
@@ -17,6 +17,8 @@ import {
type ServerReferenceId,
} from '../client/ReactFlightClientConfigBundlerParcel';
import {ASYNC_ITERATOR} from 'shared/ReactSymbols';
import {
createRequest,
createPrerenderRequest,
@@ -30,6 +32,9 @@ import {
createResponse,
close,
getRoot,
reportGlobalError,
resolveField,
resolveFile,
} from 'react-server/src/ReactFlightReplyServer';
import {
@@ -189,6 +194,50 @@ export function decodeReply<T>(
return root;
}
export function decodeReplyFromAsyncIterable<T>(
iterable: AsyncIterable<[string, string | File]>,
options?: {temporaryReferences?: TemporaryReferenceSet},
): Thenable<T> {
const iterator: AsyncIterator<[string, string | File]> =
iterable[ASYNC_ITERATOR]();
const response = createResponse(
serverManifest,
'',
options ? options.temporaryReferences : undefined,
);
function progress(
entry:
| {done: false, +value: [string, string | File], ...}
| {done: true, +value: void, ...},
) {
if (entry.done) {
close(response);
} else {
const [name, value] = entry.value;
if (typeof value === 'string') {
resolveField(response, name, value);
} else {
resolveFile(response, name, value);
}
iterator.next().then(progress, error);
}
}
function error(reason: Error) {
reportGlobalError(response, reason);
if (typeof (iterator: any).throw === 'function') {
// The iterator protocol doesn't necessarily include this but a generator do.
// $FlowFixMe should be able to pass mixed
iterator.throw(reason).then(error, error);
}
}
iterator.next().then(progress, error);
return getRoot(response);
}
export function decodeAction<T>(body: FormData): Promise<() => T> | null {
return decodeActionImpl(body, serverManifest);
}
@@ -11,6 +11,7 @@ export {
renderToReadableStream,
prerender as unstable_prerender,
decodeReply,
decodeReplyFromAsyncIterable,
decodeAction,
decodeFormState,
createClientReference,
@@ -9,6 +9,7 @@ if (process.env.NODE_ENV === 'production') {
exports.renderToReadableStream = s.renderToReadableStream;
exports.decodeReply = s.decodeReply;
exports.decodeReplyFromAsyncIterable = s.decodeReplyFromAsyncIterable;
exports.decodeAction = s.decodeAction;
exports.decodeFormState = s.decodeFormState;
exports.registerServerReference = s.registerServerReference;
@@ -10,6 +10,7 @@
export {
renderToReadableStream,
decodeReply,
decodeReplyFromAsyncIterable,
decodeAction,
decodeFormState,
registerServerReference,
@@ -12,6 +12,8 @@ import type {Thenable} from 'shared/ReactTypes';
import type {ClientManifest} from './ReactFlightServerConfigTurbopackBundler';
import type {ServerManifest} from 'react-client/src/ReactFlightClientConfig';
import {ASYNC_ITERATOR} from 'shared/ReactSymbols';
import {
createRequest,
createPrerenderRequest,
@@ -25,6 +27,9 @@ import {
createResponse,
close,
getRoot,
reportGlobalError,
resolveField,
resolveFile,
} from 'react-server/src/ReactFlightReplyServer';
import {
@@ -183,10 +188,56 @@ function decodeReply<T>(
return root;
}
function decodeReplyFromAsyncIterable<T>(
iterable: AsyncIterable<[string, string | File]>,
turbopackMap: ServerManifest,
options?: {temporaryReferences?: TemporaryReferenceSet},
): Thenable<T> {
const iterator: AsyncIterator<[string, string | File]> =
iterable[ASYNC_ITERATOR]();
const response = createResponse(
turbopackMap,
'',
options ? options.temporaryReferences : undefined,
);
function progress(
entry:
| {done: false, +value: [string, string | File], ...}
| {done: true, +value: void, ...},
) {
if (entry.done) {
close(response);
} else {
const [name, value] = entry.value;
if (typeof value === 'string') {
resolveField(response, name, value);
} else {
resolveFile(response, name, value);
}
iterator.next().then(progress, error);
}
}
function error(reason: Error) {
reportGlobalError(response, reason);
if (typeof (iterator: any).throw === 'function') {
// The iterator protocol doesn't necessarily include this but a generator do.
// $FlowFixMe should be able to pass mixed
iterator.throw(reason).then(error, error);
}
}
iterator.next().then(progress, error);
return getRoot(response);
}
export {
renderToReadableStream,
prerender,
decodeReply,
decodeReplyFromAsyncIterable,
decodeAction,
decodeFormState,
};
@@ -11,6 +11,7 @@ export {
renderToReadableStream,
prerender as unstable_prerender,
decodeReply,
decodeReplyFromAsyncIterable,
decodeAction,
decodeFormState,
registerServerReference,
@@ -9,6 +9,7 @@ if (process.env.NODE_ENV === 'production') {
exports.renderToReadableStream = s.renderToReadableStream;
exports.decodeReply = s.decodeReply;
exports.decodeReplyFromAsyncIterable = s.decodeReplyFromAsyncIterable;
exports.decodeAction = s.decodeAction;
exports.decodeFormState = s.decodeFormState;
exports.registerServerReference = s.registerServerReference;
@@ -10,6 +10,7 @@
export {
renderToReadableStream,
decodeReply,
decodeReplyFromAsyncIterable,
decodeAction,
decodeFormState,
registerServerReference,
@@ -38,6 +38,7 @@ let ReactServerDOM;
let Scheduler;
let ReactServerScheduler;
let reactServerAct;
let assertConsoleErrorDev;
describe('ReactFlightDOMBrowser', () => {
beforeEach(() => {
@@ -75,7 +76,7 @@ describe('ReactFlightDOMBrowser', () => {
Scheduler = require('scheduler');
patchMessageChannel(Scheduler);
act = require('internal-test-utils').act;
({act, assertConsoleErrorDev} = require('internal-test-utils'));
React = require('react');
ReactDOM = require('react-dom');
ReactDOMClient = require('react-dom/client');
@@ -1156,25 +1157,38 @@ describe('ReactFlightDOMBrowser', () => {
const container = document.createElement('div');
const root = ReactDOMClient.createRoot(container);
await expect(async () => {
const stream = await serverAct(() =>
ReactServerDOMServer.renderToReadableStream(
<>
<Parent>{Array(6).fill(<div>no key</div>)}</Parent>
<ParentModule.Parent>
{Array(6).fill(<div>no key</div>)}
</ParentModule.Parent>
</>,
webpackMap,
),
);
const result =
await ReactServerDOMClient.createFromReadableStream(stream);
const stream = await serverAct(() =>
ReactServerDOMServer.renderToReadableStream(
<>
<Parent>{Array(6).fill(<div>no key</div>)}</Parent>
<ParentModule.Parent>
{Array(6).fill(<div>no key</div>)}
</ParentModule.Parent>
</>,
webpackMap,
),
);
const result = await ReactServerDOMClient.createFromReadableStream(stream);
await act(() => {
root.render(result);
});
}).toErrorDev('Each child in a list should have a unique "key" prop.');
if (!gate(flags => flags.enableOwnerStacks)) {
assertConsoleErrorDev([
'Each child in a list should have a unique "key" prop. ' +
'See https://react.dev/link/warning-keys for more information.\n' +
' in div (at **)',
]);
}
await act(() => {
root.render(result);
});
if (gate(flags => flags.enableOwnerStacks)) {
assertConsoleErrorDev([
'Each child in a list should have a unique "key" prop.\n\n' +
'Check the top-level render call using <ParentClient>. ' +
'See https://react.dev/link/warning-keys for more information.\n' +
' in div (at **)',
]);
}
});
it('basic use(promise)', async () => {
@@ -37,6 +37,7 @@ let ReactServerDOMStaticServer;
let ReactServerDOMClient;
let use;
let reactServerAct;
let assertConsoleErrorDev;
function normalizeCodeLocInfo(str) {
return (
@@ -66,6 +67,8 @@ describe('ReactFlightDOMEdge', () => {
jest.resetModules();
reactServerAct = require('internal-test-utils').serverAct;
assertConsoleErrorDev =
require('internal-test-utils').assertConsoleErrorDev;
// Simulate the condition resolution
jest.mock('react', () => require('react/react.react-server'));
@@ -802,17 +805,19 @@ describe('ReactFlightDOMEdge', () => {
),
};
expect(() => {
ServerModule.greet.bind({}, 'hi');
}).toErrorDev(
'Cannot bind "this" of a Server Action. Pass null or undefined as the first argument to .bind().',
ServerModule.greet.bind({}, 'hi');
assertConsoleErrorDev(
[
'Cannot bind "this" of a Server Action. Pass null or undefined as the first argument to .bind().',
],
{withoutStack: true},
);
expect(() => {
ServerModuleImportedOnClient.greet.bind({}, 'hi');
}).toErrorDev(
'Cannot bind "this" of a Server Action. Pass null or undefined as the first argument to .bind().',
ServerModuleImportedOnClient.greet.bind({}, 'hi');
assertConsoleErrorDev(
[
'Cannot bind "this" of a Server Action. Pass null or undefined as the first argument to .bind().',
],
{withoutStack: true},
);
});
@@ -50,6 +50,7 @@ let ReactServerDOMClient;
let ReactDOMClient;
let useActionState;
let act;
let assertConsoleErrorDev;
describe('ReactFlightDOMForm', () => {
beforeEach(() => {
@@ -72,6 +73,8 @@ describe('ReactFlightDOMForm', () => {
ReactDOMServer = require('react-dom/server.edge');
ReactDOMClient = require('react-dom/client');
act = React.act;
assertConsoleErrorDev =
require('internal-test-utils').assertConsoleErrorDev;
// TODO: Test the old api but it warns so needs warnings to be asserted.
// if (__VARIANT__) {
@@ -959,12 +962,13 @@ describe('ReactFlightDOMForm', () => {
await readIntoContainer(postbackSsrStream);
}
await expect(submitTheForm).toErrorDev(
await submitTheForm();
assertConsoleErrorDev([
'Failed to serialize an action for progressive enhancement:\n' +
'Error: React Element cannot be passed to Server Functions from the Client without a temporary reference set. Pass a TemporaryReferenceSet to the options.\n' +
' [<div/>]\n' +
' ^^^^^^',
);
]);
// The error message was returned as JSX.
const form2 = container.getElementsByTagName('form')[0];
@@ -1035,10 +1039,11 @@ describe('ReactFlightDOMForm', () => {
await readIntoContainer(postbackSsrStream);
}
await expect(submitTheForm).toErrorDev(
await submitTheForm();
assertConsoleErrorDev([
'Failed to serialize an action for progressive enhancement:\n' +
'Error: File/Blob fields are not yet supported in progressive forms. Will fallback to client hydration.',
);
]);
expect(blob instanceof Blob).toBe(true);
expect(blob.size).toBe(2);
@@ -272,4 +272,40 @@ describe('ReactFlightDOMReplyEdge', () => {
expect(error).not.toBe(null);
expect(error.message).toBe('Connection closed.');
});
it('can stream the decoding using an async iterable', async () => {
let resolve;
const promise = new Promise(r => (resolve = r));
const buffer = new Uint8Array([
123, 4, 10, 5, 100, 255, 244, 45, 56, 67, 43, 124, 67, 89, 100, 20,
]);
const formData = await ReactServerDOMClient.encodeReply({
a: Promise.resolve('hello'),
b: Promise.resolve(buffer),
});
const iterable = {
async *[Symbol.asyncIterator]() {
// eslint-disable-next-line no-for-of-loops/no-for-of-loops
for (const entry of formData) {
yield entry;
await promise;
}
},
};
const decoded = await ReactServerDOMServer.decodeReplyFromAsyncIterable(
iterable,
webpackServerMap,
);
expect(Object.keys(decoded)).toEqual(['a', 'b']);
await resolve();
expect(await decoded.a).toBe('hello');
expect(Array.from(await decoded.b)).toEqual(Array.from(buffer));
});
});
@@ -12,6 +12,8 @@ import type {Thenable} from 'shared/ReactTypes';
import type {ClientManifest} from './ReactFlightServerConfigWebpackBundler';
import type {ServerManifest} from 'react-client/src/ReactFlightClientConfig';
import {ASYNC_ITERATOR} from 'shared/ReactSymbols';
import {
createRequest,
createPrerenderRequest,
@@ -25,6 +27,9 @@ import {
createResponse,
close,
getRoot,
reportGlobalError,
resolveField,
resolveFile,
} from 'react-server/src/ReactFlightReplyServer';
import {
@@ -183,10 +188,56 @@ function decodeReply<T>(
return root;
}
function decodeReplyFromAsyncIterable<T>(
iterable: AsyncIterable<[string, string | File]>,
webpackMap: ServerManifest,
options?: {temporaryReferences?: TemporaryReferenceSet},
): Thenable<T> {
const iterator: AsyncIterator<[string, string | File]> =
iterable[ASYNC_ITERATOR]();
const response = createResponse(
webpackMap,
'',
options ? options.temporaryReferences : undefined,
);
function progress(
entry:
| {done: false, +value: [string, string | File], ...}
| {done: true, +value: void, ...},
) {
if (entry.done) {
close(response);
} else {
const [name, value] = entry.value;
if (typeof value === 'string') {
resolveField(response, name, value);
} else {
resolveFile(response, name, value);
}
iterator.next().then(progress, error);
}
}
function error(reason: Error) {
reportGlobalError(response, reason);
if (typeof (iterator: any).throw === 'function') {
// The iterator protocol doesn't necessarily include this but a generator do.
// $FlowFixMe should be able to pass mixed
iterator.throw(reason).then(error, error);
}
}
iterator.next().then(progress, error);
return getRoot(response);
}
export {
renderToReadableStream,
prerender,
decodeReply,
decodeReplyFromAsyncIterable,
decodeAction,
decodeFormState,
};
@@ -11,6 +11,7 @@ export {
renderToReadableStream,
prerender as unstable_prerender,
decodeReply,
decodeReplyFromAsyncIterable,
decodeAction,
decodeFormState,
registerServerReference,
@@ -14,6 +14,7 @@ let React;
let ReactCache;
let ReactTestRenderer;
let act;
let assertConsoleErrorDev;
describe('ReactTestRenderer', () => {
beforeEach(() => {
@@ -27,19 +28,27 @@ describe('ReactTestRenderer', () => {
ReactTestRenderer = require('react-test-renderer');
const InternalTestUtils = require('internal-test-utils');
act = InternalTestUtils.act;
assertConsoleErrorDev = InternalTestUtils.assertConsoleErrorDev;
});
it('should warn if used to render a ReactDOM portal', async () => {
const container = document.createElement('div');
let error;
await expect(async () => {
await act(() => {
ReactTestRenderer.create(ReactDOM.createPortal('foo', container));
}).catch(e => (error = e));
}).toErrorDev('An invalid container has been provided.', {
withoutStack: true,
});
await act(() => {
ReactTestRenderer.create(ReactDOM.createPortal('foo', container));
}).catch(e => (error = e));
assertConsoleErrorDev(
[
'An invalid container has been provided. ' +
'This may indicate that another renderer is being used in addition to the test renderer. ' +
'(For example, ReactDOM.createPortal inside of a ReactTestRenderer tree.) ' +
'This is not supported.',
],
{
withoutStack: true,
},
);
// After the update throws, a subsequent render is scheduled to
// unmount the whole tree. This update also causes an error, so React
@@ -13,12 +13,13 @@ describe('ReactChildren', () => {
let React;
let ReactDOMClient;
let act;
let assertConsoleErrorDev;
beforeEach(() => {
jest.resetModules();
React = require('react');
ReactDOMClient = require('react-dom/client');
act = require('internal-test-utils').act;
({act, assertConsoleErrorDev} = require('internal-test-utils'));
});
it('should support identity for simple', () => {
@@ -331,14 +332,16 @@ describe('ReactChildren', () => {
callback.mockClear();
}
let instance;
expect(() => {
instance = <div>{threeDivIterable}</div>;
}).toErrorDev(
const instance = <div>{threeDivIterable}</div>;
assertConsoleErrorDev(
// With the flag on this doesn't warn eagerly but only when rendered
gate(flag => flag.enableOwnerStacks)
? []
: ['Each child in a list should have a unique "key" prop.'],
: [
'Each child in a list should have a unique "key" prop.\n\n' +
'Check the top-level render call using <div>. See https://react.dev/link/warning-keys for more information.\n' +
' in div (at **)',
],
);
React.Children.forEach(instance.props.children, callback, context);
@@ -359,11 +362,16 @@ describe('ReactChildren', () => {
const container = document.createElement('div');
const root = ReactDOMClient.createRoot(container);
await expect(async () => {
await act(() => {
root.render(instance);
});
}).toErrorDev('Each child in a list should have a unique "key" prop.');
await act(() => {
root.render(instance);
});
assertConsoleErrorDev([
'Each child in a list should have a unique "key" prop.\n\n' +
'Check the top-level render call using <div>. It was passed a child from div.' +
' See https://react.dev/link/warning-keys for more information.\n' +
' in div (at **)' +
(gate(flag => flag.enableOwnerStacks) ? '' : '\n in div (at **)'),
]);
});
it('should be called for each child in an iterable with keys', () => {
@@ -879,15 +887,29 @@ describe('ReactChildren', () => {
const container = document.createElement('div');
const root = ReactDOMClient.createRoot(container);
await expect(async () => {
await act(() => {
root.render(
<ComponentRenderingMappedChildren>
{[<div />]}
</ComponentRenderingMappedChildren>,
);
});
}).toErrorDev(['Each child in a list should have a unique "key" prop.']);
await act(() => {
root.render(
<ComponentRenderingMappedChildren>
{[<div />]}
</ComponentRenderingMappedChildren>,
);
});
assertConsoleErrorDev(
gate(flags => flags.enableOwnerStacks)
? [
'Each child in a list should have a unique "key" prop.\n\n' +
'Check the render method of `ComponentRenderingMappedChildren`.' +
' See https://react.dev/link/warning-keys for more information.\n' +
' in div (at **)\n' +
' in **/ReactChildren-test.js:**:** (at **)',
]
: [
'Each child in a list should have a unique "key" prop.\n\n' +
'Check the top-level render call using <ComponentRenderingMappedChildren>.' +
' See https://react.dev/link/warning-keys for more information.\n' +
' in div (at **)',
],
);
});
it('does not warn for mapped static children without keys', async () => {
@@ -903,16 +925,14 @@ describe('ReactChildren', () => {
const container = document.createElement('div');
const root = ReactDOMClient.createRoot(container);
await expect(async () => {
await act(() => {
root.render(
<ComponentRenderingMappedChildren>
<div />
<div />
</ComponentRenderingMappedChildren>,
);
});
}).toErrorDev([]);
await act(() => {
root.render(
<ComponentRenderingMappedChildren>
<div />
<div />
</ComponentRenderingMappedChildren>,
);
});
});
it('warns for cloned list children without keys', async () => {
@@ -926,15 +946,28 @@ describe('ReactChildren', () => {
const container = document.createElement('div');
const root = ReactDOMClient.createRoot(container);
await expect(async () => {
await act(() => {
root.render(
<ComponentRenderingClonedChildren>
{[<div />]}
</ComponentRenderingClonedChildren>,
);
});
}).toErrorDev(['Each child in a list should have a unique "key" prop.']);
await act(() => {
root.render(
<ComponentRenderingClonedChildren>
{[<div />]}
</ComponentRenderingClonedChildren>,
);
});
assertConsoleErrorDev(
gate(flags => flags.enableOwnerStacks)
? [
'Each child in a list should have a unique "key" prop.\n\n' +
'Check the render method of `ComponentRenderingClonedChildren`.' +
' See https://react.dev/link/warning-keys for more information.\n' +
' in div (at **)',
]
: [
'Each child in a list should have a unique "key" prop.\n\n' +
'Check the top-level render call using <ComponentRenderingClonedChildren>.' +
' See https://react.dev/link/warning-keys for more information.\n' +
' in div (at **)',
],
);
});
it('does not warn for cloned static children without keys', async () => {
@@ -948,16 +981,14 @@ describe('ReactChildren', () => {
const container = document.createElement('div');
const root = ReactDOMClient.createRoot(container);
await expect(async () => {
await act(() => {
root.render(
<ComponentRenderingClonedChildren>
<div />
<div />
</ComponentRenderingClonedChildren>,
);
});
}).toErrorDev([]);
await act(() => {
root.render(
<ComponentRenderingClonedChildren>
<div />
<div />
</ComponentRenderingClonedChildren>,
);
});
});
it('warns for flattened list children without keys', async () => {
@@ -967,15 +998,28 @@ describe('ReactChildren', () => {
const container = document.createElement('div');
const root = ReactDOMClient.createRoot(container);
await expect(async () => {
await act(() => {
root.render(
<ComponentRenderingFlattenedChildren>
{[<div />]}
</ComponentRenderingFlattenedChildren>,
);
});
}).toErrorDev(['Each child in a list should have a unique "key" prop.']);
await act(() => {
root.render(
<ComponentRenderingFlattenedChildren>
{[<div />]}
</ComponentRenderingFlattenedChildren>,
);
});
assertConsoleErrorDev(
gate(flags => flags.enableOwnerStacks)
? [
'Each child in a list should have a unique "key" prop.\n\n' +
'Check the render method of `ComponentRenderingFlattenedChildren`.' +
' See https://react.dev/link/warning-keys for more information.\n' +
' in div (at **)',
]
: [
'Each child in a list should have a unique "key" prop.\n\n' +
'Check the top-level render call using <ComponentRenderingFlattenedChildren>.' +
' See https://react.dev/link/warning-keys for more information.\n' +
' in div (at **)',
],
);
});
it('does not warn for flattened static children without keys', async () => {
@@ -985,16 +1029,14 @@ describe('ReactChildren', () => {
const container = document.createElement('div');
const root = ReactDOMClient.createRoot(container);
await expect(async () => {
await act(() => {
root.render(
<ComponentRenderingFlattenedChildren>
<div />
<div />
</ComponentRenderingFlattenedChildren>,
);
});
}).toErrorDev([]);
await act(() => {
root.render(
<ComponentRenderingFlattenedChildren>
<div />
<div />
</ComponentRenderingFlattenedChildren>,
);
});
});
it('should escape keys', () => {
@@ -1153,18 +1195,16 @@ describe('ReactChildren', () => {
const container = document.createElement('div');
const root = ReactDOMClient.createRoot(container);
await expect(async () => {
await act(() => {
root.render(<ComponentReturningArray />);
});
}).toErrorDev(
'' +
'Each child in a list should have a unique "key" prop.' +
await act(() => {
root.render(<ComponentReturningArray />);
});
assertConsoleErrorDev([
'Each child in a list should have a unique "key" prop.' +
'\n\nCheck the top-level render call using <ComponentReturningArray>. It was passed a child from ComponentReturningArray. ' +
'See https://react.dev/link/warning-keys for more information.' +
'\n in div (at **)' +
'\n in ComponentReturningArray (at **)',
);
]);
});
it('does not warn when there are keys on elements in a fragment', async () => {
@@ -1184,17 +1224,15 @@ describe('ReactChildren', () => {
it('warns for keys for arrays at the top level', async () => {
const container = document.createElement('div');
const root = ReactDOMClient.createRoot(container);
await expect(async () => {
await act(() => {
root.render([<div />, <div />]);
});
}).toErrorDev(
'' +
'Each child in a list should have a unique "key" prop.' +
await act(() => {
root.render([<div />, <div />]);
});
assertConsoleErrorDev([
'Each child in a list should have a unique "key" prop.' +
'\n\nCheck the top-level render call using <Root>. ' +
'See https://react.dev/link/warning-keys for more information.' +
'\n in div (at **)',
);
]);
});
});
});
@@ -9,6 +9,8 @@ PropTypes = null
React = null
ReactDOM = null
ReactDOMClient = null
assertConsoleErrorDev = null
assertConsoleWarnDev = null
featureFlags = require 'shared/ReactFeatureFlags'
@@ -28,6 +30,9 @@ describe 'ReactCoffeeScriptClass', ->
root = ReactDOMClient.createRoot container
attachedListener = null
renderedName = null
TestUtils = require 'internal-test-utils'
assertConsoleErrorDev = TestUtils.assertConsoleErrorDev
assertConsoleWarnDev = TestUtils.assertConsoleWarnDev
InnerComponent = class extends React.Component
getName: -> this.props.name
render: ->
@@ -53,14 +58,15 @@ describe 'ReactCoffeeScriptClass', ->
event.preventDefault()
caughtErrors.push(event.error)
window.addEventListener 'error', errorHandler;
expect(->
ReactDOM.flushSync ->
root.render React.createElement(Foo)
).toErrorDev([
# A failed component renders twice in DEV in concurrent mode
'No `render` method found on the Foo instance',
'No `render` method found on the Foo instance',
])
ReactDOM.flushSync ->
root.render React.createElement(Foo)
assertConsoleErrorDev [
# A failed component renders twice in DEV in concurrent mode
'No `render` method found on the Foo instance: you may have forgotten to define `render`.\n' +
' in Foo (at **)',
'No `render` method found on the Foo instance: you may have forgotten to define `render`.\n' +
' in Foo (at **)',
]
window.removeEventListener 'error', errorHandler;
expect(caughtErrors).toEqual([
expect.objectContaining(
@@ -136,11 +142,11 @@ describe 'ReactCoffeeScriptClass', ->
React.createElement('div')
getDerivedStateFromProps: ->
{}
expect(->
ReactDOM.flushSync ->
root.render React.createElement(Foo, foo: 'foo')
return
).toErrorDev 'Foo: getDerivedStateFromProps() is defined as an instance method and will be ignored. Instead, declare it as a static method.'
ReactDOM.flushSync ->
root.render React.createElement(Foo, foo: 'foo')
assertConsoleErrorDev [
'Foo: getDerivedStateFromProps() is defined as an instance method and will be ignored. Instead, declare it as a static method.\n' +
' in Foo (at **)']
it 'warns if getDerivedStateFromError is not static', ->
class Foo extends React.Component
@@ -148,11 +154,13 @@ describe 'ReactCoffeeScriptClass', ->
React.createElement('div')
getDerivedStateFromError: ->
{}
expect(->
ReactDOM.flushSync ->
root.render React.createElement(Foo, foo: 'foo')
return
).toErrorDev 'Foo: getDerivedStateFromError() is defined as an instance method and will be ignored. Instead, declare it as a static method.'
ReactDOM.flushSync ->
root.render React.createElement(Foo, foo: 'foo')
assertConsoleErrorDev [
'Foo: getDerivedStateFromError() is defined as an instance method and will be ignored. Instead, declare it as a static method.\n' +
' in Foo (at **)'
]
it 'warns if getSnapshotBeforeUpdate is static', ->
class Foo extends React.Component
@@ -160,11 +168,13 @@ describe 'ReactCoffeeScriptClass', ->
React.createElement('div')
Foo.getSnapshotBeforeUpdate = () ->
{}
expect(->
ReactDOM.flushSync ->
root.render React.createElement(Foo, foo: 'foo')
return
).toErrorDev 'Foo: getSnapshotBeforeUpdate() is defined as a static method and will be ignored. Instead, declare it as an instance method.'
ReactDOM.flushSync ->
root.render React.createElement(Foo, foo: 'foo')
assertConsoleErrorDev [
'Foo: getSnapshotBeforeUpdate() is defined as a static method and will be ignored. Instead, declare it as an instance method.\n' +
' in Foo (at **)'
]
it 'warns if state not initialized before static getDerivedStateFromProps', ->
class Foo extends React.Component
@@ -177,16 +187,16 @@ describe 'ReactCoffeeScriptClass', ->
foo: nextProps.foo
bar: 'bar'
}
expect(->
ReactDOM.flushSync ->
root.render React.createElement(Foo, foo: 'foo')
return
).toErrorDev (
'`Foo` uses `getDerivedStateFromProps` but its initial state is ' +
'undefined. This is not recommended. Instead, define the initial state by ' +
'assigning an object to `this.state` in the constructor of `Foo`. ' +
'This ensures that `getDerivedStateFromProps` arguments have a consistent shape.'
)
ReactDOM.flushSync ->
root.render React.createElement(Foo, foo: 'foo')
assertConsoleErrorDev [
'`Foo` uses `getDerivedStateFromProps` but its initial state is
undefined. This is not recommended. Instead, define the initial state by
assigning an object to `this.state` in the constructor of `Foo`.
This ensures that `getDerivedStateFromProps` arguments have a consistent shape.\n' +
' in Foo (at **)'
]
it 'updates initial state with values returned by static getDerivedStateFromProps', ->
class Foo extends React.Component
@@ -254,12 +264,28 @@ describe 'ReactCoffeeScriptClass', ->
render: ->
React.createElement Foo
expect(->
test React.createElement(Outer), 'SPAN', 'foo'
).toErrorDev([
'Outer uses the legacy childContextTypes API which will soon be removed. Use React.createContext() instead.',
'Foo uses the legacy contextTypes API which will soon be removed. Use React.createContext() with static contextType instead.',
])
test React.createElement(Outer), 'SPAN', 'foo'
if featureFlags.enableOwnerStacks
assertConsoleErrorDev([
'Outer uses the legacy childContextTypes API which will soon be removed.
Use React.createContext() instead. (https://react.dev/link/legacy-context)\n' +
' in Outer (at **)',
'Foo uses the legacy contextTypes API which will soon be removed.
Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' +
' in Outer (at **)',
]);
else
assertConsoleErrorDev([
'Outer uses the legacy childContextTypes API which will soon be removed.
Use React.createContext() instead. (https://react.dev/link/legacy-context)\n' +
' in Outer (at **)',
'Foo uses the legacy contextTypes API which will soon be removed.
Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' +
' in Foo (at **)\n' +
' in Outer (at **)',
]);
it 'renders only once when setting state in componentWillMount', ->
renderCount = 0
@@ -286,9 +312,11 @@ describe 'ReactCoffeeScriptClass', ->
render: ->
React.createElement('span')
expect(->
test React.createElement(Foo), 'SPAN', ''
).toErrorDev('Foo.state: must be set to an object or null')
test React.createElement(Foo), 'SPAN', ''
assertConsoleErrorDev [
'Foo.state: must be set to an object or null\n' +
' in Foo (at **)'
]
it 'should render with null in the initial state property', ->
class Foo extends React.Component
@@ -430,14 +458,21 @@ describe 'ReactCoffeeScriptClass', ->
className: 'foo'
)
expect(->
test React.createElement(Foo), 'SPAN', 'foo'
).toErrorDev([
'getInitialState was defined on Foo, a plain JavaScript class.',
'getDefaultProps was defined on Foo, a plain JavaScript class.',
'contextTypes was defined as an instance property on Foo.',
'contextType was defined as an instance property on Foo.',
])
test React.createElement(Foo), 'SPAN', 'foo'
assertConsoleErrorDev [
'getInitialState was defined on Foo, a plain JavaScript class.
This is only supported for classes created using React.createClass.
Did you mean to define a state property instead?\n' +
' in Foo (at **)',
'getDefaultProps was defined on Foo, a plain JavaScript class.
This is only supported for classes created using React.createClass.
Use a static property to define defaultProps instead.\n' +
' in Foo (at **)',
'contextType was defined as an instance property on Foo. Use a static property to define contextType instead.\n' +
' in Foo (at **)',
'contextTypes was defined as an instance property on Foo. Use a static property to define contextTypes instead.\n' +
' in Foo (at **)',
]
expect(getInitialStateWasCalled).toBe false
expect(getDefaultPropsWasCalled).toBe false
@@ -468,13 +503,13 @@ describe 'ReactCoffeeScriptClass', ->
className: 'foo'
)
expect(->
test React.createElement(NamedComponent), 'SPAN', 'foo'
).toErrorDev(
test React.createElement(NamedComponent), 'SPAN', 'foo'
assertConsoleErrorDev [
'NamedComponent has a method called componentShouldUpdate().
Did you mean shouldComponentUpdate()? The name is phrased as a
question because the function is expected to return a value.'
)
question because the function is expected to return a value.\n' +
' in NamedComponent (at **)'
]
it 'should warn when misspelling componentWillReceiveProps', ->
class NamedComponent extends React.Component
@@ -486,12 +521,12 @@ describe 'ReactCoffeeScriptClass', ->
className: 'foo'
)
expect(->
test React.createElement(NamedComponent), 'SPAN', 'foo'
).toErrorDev(
test React.createElement(NamedComponent), 'SPAN', 'foo'
assertConsoleErrorDev [
'NamedComponent has a method called componentWillRecieveProps().
Did you mean componentWillReceiveProps()?'
)
Did you mean componentWillReceiveProps()?\n' +
' in NamedComponent (at **)'
]
it 'should warn when misspelling UNSAFE_componentWillReceiveProps', ->
class NamedComponent extends React.Component
@@ -503,28 +538,28 @@ describe 'ReactCoffeeScriptClass', ->
className: 'foo'
)
expect(->
test React.createElement(NamedComponent), 'SPAN', 'foo'
).toErrorDev(
test React.createElement(NamedComponent), 'SPAN', 'foo'
assertConsoleErrorDev [
'NamedComponent has a method called UNSAFE_componentWillRecieveProps().
Did you mean UNSAFE_componentWillReceiveProps()?'
)
Did you mean UNSAFE_componentWillReceiveProps()?\n' +
' in NamedComponent (at **)'
]
it 'should throw AND warn when trying to access classic APIs', ->
ref = React.createRef()
test React.createElement(InnerComponent, name: 'foo', ref: ref), 'DIV', 'foo'
expect(->
expect(-> ref.current.replaceState {}).toThrow()
).toWarnDev(
'replaceState(...) is deprecated in plain JavaScript React classes',
{withoutStack: true}
)
expect(->
expect(-> ref.current.isMounted()).toThrow()
).toWarnDev(
'isMounted(...) is deprecated in plain JavaScript React classes',
{withoutStack: true}
)
expect(-> ref.current.replaceState {}).toThrow()
assertConsoleWarnDev([
'replaceState(...) is deprecated in plain JavaScript React classes.
Refactor your code to use setState instead (see https://github.com/facebook/react/issues/3236).'
], {withoutStack: true})
expect(-> ref.current.isMounted()).toThrow()
assertConsoleWarnDev([
'isMounted(...) is deprecated in plain JavaScript React classes.
Instead, make sure to clean up subscriptions and pending requests in componentWillUnmount to prevent memory leaks.',
], {withoutStack: true})
if !featureFlags.disableLegacyContext
it 'supports this.context passed via getChildContext', ->
@@ -542,13 +577,25 @@ describe 'ReactCoffeeScriptClass', ->
render: ->
React.createElement Bar
expect(->
test React.createElement(Foo), 'DIV', 'bar-through-context'
).toErrorDev(
[
'Foo uses the legacy childContextTypes API which will soon be removed. Use React.createContext() instead.',
'Bar uses the legacy contextTypes API which will soon be removed. Use React.createContext() with static contextType instead.',
],
)
test React.createElement(Foo), 'DIV', 'bar-through-context'
if featureFlags.enableOwnerStacks
assertConsoleErrorDev [
'Foo uses the legacy childContextTypes API which will soon be removed. Use React.createContext() instead.
(https://react.dev/link/legacy-context)\n' +
' in Foo (at **)',
'Bar uses the legacy contextTypes API which will soon be removed. Use React.createContext() with static contextType instead.
(https://react.dev/link/legacy-context)\n' +
' in Foo (at **)'
]
else
assertConsoleErrorDev [
'Foo uses the legacy childContextTypes API which will soon be removed. Use React.createContext() instead.
(https://react.dev/link/legacy-context)\n' +
' in Foo (at **)',
'Bar uses the legacy contextTypes API which will soon be removed. Use React.createContext() with static contextType instead.
(https://react.dev/link/legacy-context)\n' +
' in Bar (at **)\n' +
' in Foo (at **)'
]
undefined

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