Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
28a86ffe47 |
@@ -6,51 +6,52 @@
|
||||
*/
|
||||
|
||||
import MonacoEditor, {loader, type Monaco} from '@monaco-editor/react';
|
||||
import {parseConfigPragmaAsString} from 'babel-plugin-react-compiler';
|
||||
import type {editor} from 'monaco-editor';
|
||||
import * as monaco from 'monaco-editor';
|
||||
import {useState} from 'react';
|
||||
import parserBabel from 'prettier/plugins/babel';
|
||||
import * as prettierPluginEstree from 'prettier/plugins/estree';
|
||||
import * as prettier from 'prettier/standalone';
|
||||
import {useState, useEffect} from 'react';
|
||||
import {Resizable} from 're-resizable';
|
||||
import {useStore, useStoreDispatch} from '../StoreContext';
|
||||
import {useStore} from '../StoreContext';
|
||||
import {monacoOptions} from './monacoOptions';
|
||||
import {
|
||||
generateOverridePragmaFromConfig,
|
||||
updateSourceWithOverridePragma,
|
||||
} from '../../lib/configUtils';
|
||||
|
||||
loader.config({monaco});
|
||||
|
||||
export default function ConfigEditor(): JSX.Element {
|
||||
const [, setMonaco] = useState<Monaco | null>(null);
|
||||
const store = useStore();
|
||||
const dispatchStore = useStoreDispatch();
|
||||
|
||||
const handleChange: (value: string | undefined) => void = async value => {
|
||||
if (value === undefined) return;
|
||||
// Parse string-based override config from pragma comment and format it
|
||||
const [configJavaScript, setConfigJavaScript] = useState('');
|
||||
|
||||
try {
|
||||
const newPragma = await generateOverridePragmaFromConfig(value);
|
||||
const updatedSource = updateSourceWithOverridePragma(
|
||||
store.source,
|
||||
newPragma,
|
||||
);
|
||||
useEffect(() => {
|
||||
const pragma = store.source.substring(0, store.source.indexOf('\n'));
|
||||
const configString = `(${parseConfigPragmaAsString(pragma)})`;
|
||||
|
||||
// Update the store with both the new config and updated source
|
||||
dispatchStore({
|
||||
type: 'updateFile',
|
||||
payload: {
|
||||
source: updatedSource,
|
||||
config: value,
|
||||
},
|
||||
prettier
|
||||
.format(configString, {
|
||||
semi: true,
|
||||
parser: 'babel-ts',
|
||||
plugins: [parserBabel, prettierPluginEstree],
|
||||
})
|
||||
.then(formatted => {
|
||||
setConfigJavaScript(formatted);
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error formatting config:', error);
|
||||
setConfigJavaScript('({})'); // Return empty object if not valid for now
|
||||
//TODO: Add validation and error handling for config
|
||||
});
|
||||
} catch (_) {
|
||||
dispatchStore({
|
||||
type: 'updateFile',
|
||||
payload: {
|
||||
source: store.source,
|
||||
config: value,
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log('Config:', configString);
|
||||
}, [store.source]);
|
||||
|
||||
const handleChange: (value: string | undefined) => void = value => {
|
||||
if (!value) return;
|
||||
|
||||
// TODO: Implement sync logic to update pragma comments in the source
|
||||
console.log('Config changed:', value);
|
||||
};
|
||||
|
||||
const handleMount: (
|
||||
@@ -80,11 +81,12 @@ export default function ConfigEditor(): JSX.Element {
|
||||
<MonacoEditor
|
||||
path={'config.js'}
|
||||
language={'javascript'}
|
||||
value={store.config}
|
||||
value={configJavaScript}
|
||||
onMount={handleMount}
|
||||
onChange={handleChange}
|
||||
options={{
|
||||
...monacoOptions,
|
||||
readOnly: true,
|
||||
lineNumbers: 'off',
|
||||
folding: false,
|
||||
renderLineHighlight: 'none',
|
||||
|
||||
@@ -48,7 +48,6 @@ import {
|
||||
import {transformFromAstSync} from '@babel/core';
|
||||
import {LoggerEvent} from 'babel-plugin-react-compiler/dist/Entrypoint';
|
||||
import {useSearchParams} from 'next/navigation';
|
||||
import {parseAndFormatConfig} from '../../lib/configUtils';
|
||||
|
||||
function parseInput(
|
||||
input: string,
|
||||
@@ -316,17 +315,9 @@ export default function Editor(): JSX.Element {
|
||||
});
|
||||
mountStore = defaultStore;
|
||||
}
|
||||
|
||||
parseAndFormatConfig(mountStore.source).then(config => {
|
||||
dispatchStore({
|
||||
type: 'setStore',
|
||||
payload: {
|
||||
store: {
|
||||
...mountStore,
|
||||
config,
|
||||
},
|
||||
},
|
||||
});
|
||||
dispatchStore({
|
||||
type: 'setStore',
|
||||
payload: {store: mountStore},
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@ import {useStore, useStoreDispatch} from '../StoreContext';
|
||||
import {monacoOptions} from './monacoOptions';
|
||||
// @ts-expect-error TODO: Make TS recognize .d.ts files, in addition to loading them with webpack.
|
||||
import React$Types from '../../node_modules/@types/react/index.d.ts';
|
||||
import {parseAndFormatConfig} from '../../lib/configUtils.ts';
|
||||
|
||||
loader.config({monaco});
|
||||
|
||||
@@ -80,17 +79,13 @@ export default function Input({errors, language}: Props): JSX.Element {
|
||||
});
|
||||
}, [monaco, language]);
|
||||
|
||||
const handleChange: (value: string | undefined) => void = async value => {
|
||||
const handleChange: (value: string | undefined) => void = value => {
|
||||
if (!value) return;
|
||||
|
||||
// Parse and format the config
|
||||
const config = await parseAndFormatConfig(value);
|
||||
|
||||
dispatchStore({
|
||||
type: 'updateFile',
|
||||
payload: {
|
||||
source: value,
|
||||
config,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
@@ -56,7 +56,6 @@ type ReducerAction =
|
||||
type: 'updateFile';
|
||||
payload: {
|
||||
source: string;
|
||||
config?: string;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -67,11 +66,10 @@ function storeReducer(store: Store, action: ReducerAction): Store {
|
||||
return newStore;
|
||||
}
|
||||
case 'updateFile': {
|
||||
const {source, config} = action.payload;
|
||||
const {source} = action.payload;
|
||||
const newStore = {
|
||||
...store,
|
||||
source,
|
||||
config,
|
||||
};
|
||||
return newStore;
|
||||
}
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import parserBabel from 'prettier/plugins/babel';
|
||||
import prettierPluginEstree from 'prettier/plugins/estree';
|
||||
import * as prettier from 'prettier/standalone';
|
||||
import {parseConfigPragmaAsString} from '../../../packages/babel-plugin-react-compiler/src/Utils/TestUtils';
|
||||
|
||||
/**
|
||||
* Parse config from pragma and format it with prettier
|
||||
*/
|
||||
export async function parseAndFormatConfig(source: string): Promise<string> {
|
||||
const pragma = source.substring(0, source.indexOf('\n'));
|
||||
let configString = parseConfigPragmaAsString(pragma);
|
||||
if (configString !== '') {
|
||||
configString = `(${configString})`;
|
||||
}
|
||||
|
||||
try {
|
||||
const formatted = await prettier.format(configString, {
|
||||
semi: true,
|
||||
parser: 'babel-ts',
|
||||
plugins: [parserBabel, prettierPluginEstree],
|
||||
});
|
||||
return formatted;
|
||||
} catch (error) {
|
||||
console.error('Error formatting config:', error);
|
||||
return ''; // Return empty string if not valid for now
|
||||
}
|
||||
}
|
||||
|
||||
function extractCurlyBracesContent(input: string): string {
|
||||
const startIndex = input.indexOf('{');
|
||||
const endIndex = input.lastIndexOf('}');
|
||||
if (startIndex === -1 || endIndex === -1 || endIndex <= startIndex) {
|
||||
throw new Error('No outer curly braces found in input');
|
||||
}
|
||||
return input.slice(startIndex, endIndex + 1);
|
||||
}
|
||||
|
||||
function cleanContent(content: string): string {
|
||||
return content
|
||||
.replace(/[\r\n]+/g, ' ')
|
||||
.replace(/\s+/g, ' ')
|
||||
.trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a the override pragma comment from a formatted config object string
|
||||
*/
|
||||
export async function generateOverridePragmaFromConfig(
|
||||
formattedConfigString: string,
|
||||
): Promise<string> {
|
||||
const content = extractCurlyBracesContent(formattedConfigString);
|
||||
const cleanConfig = cleanContent(content);
|
||||
|
||||
// Format the config to ensure it's valid
|
||||
await prettier.format(`(${cleanConfig})`, {
|
||||
semi: false,
|
||||
parser: 'babel-ts',
|
||||
plugins: [parserBabel, prettierPluginEstree],
|
||||
});
|
||||
|
||||
return `// @OVERRIDE:${cleanConfig}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the override pragma comment in source code.
|
||||
*/
|
||||
export function updateSourceWithOverridePragma(
|
||||
source: string,
|
||||
newPragma: string,
|
||||
): string {
|
||||
const firstLineEnd = source.indexOf('\n');
|
||||
const firstLine = source.substring(0, firstLineEnd);
|
||||
|
||||
const pragmaRegex = /^\/\/\s*@/;
|
||||
if (firstLineEnd !== -1 && pragmaRegex.test(firstLine.trim())) {
|
||||
return newPragma + source.substring(firstLineEnd);
|
||||
} else {
|
||||
return newPragma + '\n' + source;
|
||||
}
|
||||
}
|
||||
@@ -15,10 +15,8 @@ export default function MyApp() {
|
||||
|
||||
export const defaultStore: Store = {
|
||||
source: index,
|
||||
config: '',
|
||||
};
|
||||
|
||||
export const emptyStore: Store = {
|
||||
source: '',
|
||||
config: '',
|
||||
};
|
||||
|
||||
@@ -17,7 +17,6 @@ import {defaultStore} from '../defaultStore';
|
||||
*/
|
||||
export interface Store {
|
||||
source: string;
|
||||
config?: string;
|
||||
}
|
||||
export function encodeStore(store: Store): string {
|
||||
return compressToEncodedURIComponent(JSON.stringify(store));
|
||||
@@ -66,14 +65,5 @@ export function initStoreFromUrlOrLocalStorage(): Store {
|
||||
const raw = decodeStore(encodedSource);
|
||||
|
||||
invariant(isValidStore(raw), 'Invalid Store');
|
||||
|
||||
// Add config property if missing for backwards compatibility
|
||||
if (!('config' in raw)) {
|
||||
return {
|
||||
...raw,
|
||||
config: '',
|
||||
};
|
||||
}
|
||||
|
||||
return raw;
|
||||
}
|
||||
|
||||
1
compiler/apps/playground/next-env.d.ts
vendored
1
compiler/apps/playground/next-env.d.ts
vendored
@@ -1,6 +1,5 @@
|
||||
/// <reference types="next" />
|
||||
/// <reference types="next/image-types/global" />
|
||||
/// <reference path="./.next/types/routes.d.ts" />
|
||||
|
||||
// NOTE: This file should not be edited
|
||||
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
|
||||
|
||||
@@ -34,30 +34,26 @@
|
||||
"invariant": "^2.2.4",
|
||||
"lz-string": "^1.5.0",
|
||||
"monaco-editor": "^0.52.0",
|
||||
"next": "15.5.2",
|
||||
"next": "^15.2.0-canary.64",
|
||||
"notistack": "^3.0.0-alpha.7",
|
||||
"prettier": "^3.3.3",
|
||||
"pretty-format": "^29.3.1",
|
||||
"re-resizable": "^6.9.16",
|
||||
"react": "19.1.1",
|
||||
"react-dom": "19.1.1"
|
||||
"react": "^19.0.0",
|
||||
"react-dom": "^19.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "18.11.9",
|
||||
"@types/react": "19.1.12",
|
||||
"@types/react-dom": "19.1.9",
|
||||
"@types/react": "^19.0.0",
|
||||
"@types/react-dom": "^19.0.0",
|
||||
"autoprefixer": "^10.4.13",
|
||||
"clsx": "^1.2.1",
|
||||
"concurrently": "^7.4.0",
|
||||
"eslint": "^8.28.0",
|
||||
"eslint-config-next": "15.5.2",
|
||||
"eslint-config-next": "^15.0.1",
|
||||
"monaco-editor-webpack-plugin": "^7.1.0",
|
||||
"postcss": "^8.4.31",
|
||||
"tailwindcss": "^3.2.4",
|
||||
"wait-on": "^7.2.0"
|
||||
},
|
||||
"resolutions": {
|
||||
"@types/react": "19.1.12",
|
||||
"@types/react-dom": "19.1.9"
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2089,7 +2089,7 @@ function computeSignatureForInstruction(
|
||||
effects.push({
|
||||
kind: 'Freeze',
|
||||
value: operand,
|
||||
reason: ValueReason.HookCaptured,
|
||||
reason: ValueReason.Other,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,41 +175,6 @@ export function alignReactiveScopesToBlockScopesHIR(fn: HIRFunction): void {
|
||||
if (node != null) {
|
||||
valueBlockNodes.set(fallthrough, node);
|
||||
}
|
||||
} else if (terminal.kind === 'goto') {
|
||||
/**
|
||||
* If we encounter a goto that is not to the natural fallthrough of the current
|
||||
* block (not the topmost fallthrough on the stack), then this is a goto to a
|
||||
* label. Any scopes that extend beyond the goto must be extended to include
|
||||
* the labeled range, so that the break statement doesn't accidentally jump
|
||||
* out of the scope. We do this by extending the start and end of the scope's
|
||||
* range to the label and its fallthrough respectively.
|
||||
*/
|
||||
const start = activeBlockFallthroughRanges.find(
|
||||
range => range.fallthrough === terminal.block,
|
||||
);
|
||||
if (start != null && start !== activeBlockFallthroughRanges.at(-1)) {
|
||||
const fallthroughBlock = fn.body.blocks.get(start.fallthrough)!;
|
||||
const firstId =
|
||||
fallthroughBlock.instructions[0]?.id ?? fallthroughBlock.terminal.id;
|
||||
for (const scope of activeScopes) {
|
||||
/**
|
||||
* activeScopes is only filtered at block start points, so some of the
|
||||
* scopes may not actually be active anymore, ie we've past their end
|
||||
* instruction. Only extend ranges for scopes that are actually active.
|
||||
*
|
||||
* TODO: consider pruning activeScopes per instruction
|
||||
*/
|
||||
if (scope.range.end <= terminal.id) {
|
||||
continue;
|
||||
}
|
||||
scope.range.start = makeInstructionId(
|
||||
Math.min(start.range.start, scope.range.start),
|
||||
);
|
||||
scope.range.end = makeInstructionId(
|
||||
Math.max(firstId, scope.range.end),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -945,8 +945,7 @@ function codegenTerminal(
|
||||
if (terminal.targetKind === 'implicit') {
|
||||
return null;
|
||||
}
|
||||
return createBreakStatement(
|
||||
terminal.loc,
|
||||
return t.breakStatement(
|
||||
terminal.targetKind === 'labeled'
|
||||
? t.identifier(codegenLabel(terminal.target))
|
||||
: null,
|
||||
@@ -956,16 +955,14 @@ function codegenTerminal(
|
||||
if (terminal.targetKind === 'implicit') {
|
||||
return null;
|
||||
}
|
||||
return createContinueStatement(
|
||||
terminal.loc,
|
||||
return t.continueStatement(
|
||||
terminal.targetKind === 'labeled'
|
||||
? t.identifier(codegenLabel(terminal.target))
|
||||
: null,
|
||||
);
|
||||
}
|
||||
case 'for': {
|
||||
return createForStatement(
|
||||
terminal.loc,
|
||||
return t.forStatement(
|
||||
codegenForInit(cx, terminal.init),
|
||||
codegenInstructionValueToExpression(cx, terminal.test),
|
||||
terminal.update !== null
|
||||
@@ -1050,8 +1047,7 @@ function codegenTerminal(
|
||||
`Unhandled lvalue kind: ${iterableItem.value.lvalue.kind}`,
|
||||
);
|
||||
}
|
||||
return createForInStatement(
|
||||
terminal.loc,
|
||||
return t.forInStatement(
|
||||
/*
|
||||
* Special handling here since we only want the VariableDeclarators without any inits
|
||||
* This needs to be updated when we handle non-trivial ForOf inits
|
||||
@@ -1144,8 +1140,7 @@ function codegenTerminal(
|
||||
`Unhandled lvalue kind: ${iterableItem.value.lvalue.kind}`,
|
||||
);
|
||||
}
|
||||
return createForOfStatement(
|
||||
terminal.loc,
|
||||
return t.forOfStatement(
|
||||
/*
|
||||
* Special handling here since we only want the VariableDeclarators without any inits
|
||||
* This needs to be updated when we handle non-trivial ForOf inits
|
||||
@@ -1167,7 +1162,7 @@ function codegenTerminal(
|
||||
alternate = block;
|
||||
}
|
||||
}
|
||||
return createIfStatement(terminal.loc, test, consequent, alternate);
|
||||
return t.ifStatement(test, consequent, alternate);
|
||||
}
|
||||
case 'return': {
|
||||
const value = codegenPlaceToExpression(cx, terminal.value);
|
||||
@@ -1178,8 +1173,7 @@ function codegenTerminal(
|
||||
return t.returnStatement(value);
|
||||
}
|
||||
case 'switch': {
|
||||
return createSwitchStatement(
|
||||
terminal.loc,
|
||||
return t.switchStatement(
|
||||
codegenPlaceToExpression(cx, terminal.test),
|
||||
terminal.cases.map(case_ => {
|
||||
const test =
|
||||
@@ -1192,26 +1186,15 @@ function codegenTerminal(
|
||||
);
|
||||
}
|
||||
case 'throw': {
|
||||
return createThrowStatement(
|
||||
terminal.loc,
|
||||
codegenPlaceToExpression(cx, terminal.value),
|
||||
);
|
||||
return t.throwStatement(codegenPlaceToExpression(cx, terminal.value));
|
||||
}
|
||||
case 'do-while': {
|
||||
const test = codegenInstructionValueToExpression(cx, terminal.test);
|
||||
return createDoWhileStatement(
|
||||
terminal.loc,
|
||||
test,
|
||||
codegenBlock(cx, terminal.loop),
|
||||
);
|
||||
return t.doWhileStatement(test, codegenBlock(cx, terminal.loop));
|
||||
}
|
||||
case 'while': {
|
||||
const test = codegenInstructionValueToExpression(cx, terminal.test);
|
||||
return createWhileStatement(
|
||||
terminal.loc,
|
||||
test,
|
||||
codegenBlock(cx, terminal.loop),
|
||||
);
|
||||
return t.whileStatement(test, codegenBlock(cx, terminal.loop));
|
||||
}
|
||||
case 'label': {
|
||||
return codegenBlock(cx, terminal.block);
|
||||
@@ -1222,8 +1205,7 @@ function codegenTerminal(
|
||||
catchParam = convertIdentifier(terminal.handlerBinding.identifier);
|
||||
cx.temp.set(terminal.handlerBinding.identifier.declarationId, null);
|
||||
}
|
||||
return createTryStatement(
|
||||
terminal.loc,
|
||||
return t.tryStatement(
|
||||
codegenBlock(cx, terminal.block),
|
||||
t.catchClause(catchParam, codegenBlock(cx, terminal.handler)),
|
||||
);
|
||||
@@ -1561,13 +1543,7 @@ const createExpressionStatement = withLoc(t.expressionStatement);
|
||||
const _createLabelledStatement = withLoc(t.labeledStatement);
|
||||
const createVariableDeclaration = withLoc(t.variableDeclaration);
|
||||
const createFunctionDeclaration = withLoc(t.functionDeclaration);
|
||||
const createWhileStatement = withLoc(t.whileStatement);
|
||||
const createDoWhileStatement = withLoc(t.doWhileStatement);
|
||||
const createSwitchStatement = withLoc(t.switchStatement);
|
||||
const createIfStatement = withLoc(t.ifStatement);
|
||||
const createForStatement = withLoc(t.forStatement);
|
||||
const createForOfStatement = withLoc(t.forOfStatement);
|
||||
const createForInStatement = withLoc(t.forInStatement);
|
||||
const _createWhileStatement = withLoc(t.whileStatement);
|
||||
const createTaggedTemplateExpression = withLoc(t.taggedTemplateExpression);
|
||||
const createLogicalExpression = withLoc(t.logicalExpression);
|
||||
const createSequenceExpression = withLoc(t.sequenceExpression);
|
||||
@@ -1582,10 +1558,6 @@ const createJsxText = withLoc(t.jsxText);
|
||||
const createJsxClosingElement = withLoc(t.jsxClosingElement);
|
||||
const createJsxOpeningElement = withLoc(t.jsxOpeningElement);
|
||||
const createStringLiteral = withLoc(t.stringLiteral);
|
||||
const createThrowStatement = withLoc(t.throwStatement);
|
||||
const createTryStatement = withLoc(t.tryStatement);
|
||||
const createBreakStatement = withLoc(t.breakStatement);
|
||||
const createContinueStatement = withLoc(t.continueStatement);
|
||||
|
||||
function createHookGuard(
|
||||
guard: ExternalFunction,
|
||||
@@ -2342,9 +2314,6 @@ function codegenInstructionValue(
|
||||
);
|
||||
}
|
||||
}
|
||||
if (instrValue.loc != null && instrValue.loc != GeneratedSource) {
|
||||
value.loc = instrValue.loc;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
@@ -411,9 +411,7 @@ class CollectDependenciesVisitor extends ReactiveFunctionVisitor<
|
||||
this.state = state;
|
||||
this.options = {
|
||||
memoizeJsxElements: !this.env.config.enableForest,
|
||||
forceMemoizePrimitives:
|
||||
this.env.config.enableForest ||
|
||||
this.env.config.enablePreserveExistingMemoizationGuarantees,
|
||||
forceMemoizePrimitives: this.env.config.enableForest,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -536,23 +534,9 @@ class CollectDependenciesVisitor extends ReactiveFunctionVisitor<
|
||||
case 'JSXText':
|
||||
case 'BinaryExpression':
|
||||
case 'UnaryExpression': {
|
||||
if (options.forceMemoizePrimitives) {
|
||||
/**
|
||||
* Because these instructions produce primitives we usually don't consider
|
||||
* them as escape points: they are known to copy, not return references.
|
||||
* However if we're forcing memoization of primitives then we mark these
|
||||
* instructions as needing memoization and walk their rvalues to ensure
|
||||
* any scopes transitively reachable from the rvalues are considered for
|
||||
* memoization. Note: we may still prune primitive-producing scopes if
|
||||
* they don't ultimately escape at all.
|
||||
*/
|
||||
const level = MemoizationLevel.Conditional;
|
||||
return {
|
||||
lvalues: lvalue !== null ? [{place: lvalue, level}] : [],
|
||||
rvalues: [...eachReactiveValueOperand(value)],
|
||||
};
|
||||
}
|
||||
const level = MemoizationLevel.Never;
|
||||
const level = options.forceMemoizePrimitives
|
||||
? MemoizationLevel.Memoized
|
||||
: MemoizationLevel.Never;
|
||||
return {
|
||||
// All of these instructions return a primitive value and never need to be memoized
|
||||
lvalues: lvalue !== null ? [{place: lvalue, level}] : [],
|
||||
@@ -701,7 +685,9 @@ class CollectDependenciesVisitor extends ReactiveFunctionVisitor<
|
||||
}
|
||||
case 'ComputedLoad':
|
||||
case 'PropertyLoad': {
|
||||
const level = MemoizationLevel.Conditional;
|
||||
const level = options.forceMemoizePrimitives
|
||||
? MemoizationLevel.Memoized
|
||||
: MemoizationLevel.Conditional;
|
||||
return {
|
||||
// Indirection for the inner value, memoized if the value is
|
||||
lvalues: lvalue !== null ? [{place: lvalue, level}] : [],
|
||||
|
||||
@@ -255,16 +255,11 @@ function parseConfigStringAsJS(
|
||||
|
||||
console.log('OVERRIDE:', parsedConfig);
|
||||
|
||||
const environment = parseConfigPragmaEnvironmentForTest(
|
||||
'',
|
||||
defaults.environment ?? {},
|
||||
);
|
||||
|
||||
const options: Record<keyof PluginOptions, unknown> = {
|
||||
...defaultOptions,
|
||||
panicThreshold: 'all_errors',
|
||||
compilationMode: defaults.compilationMode,
|
||||
environment,
|
||||
environment: defaults.environment ?? defaultOptions.environment,
|
||||
};
|
||||
|
||||
// Apply parsed config, merging environment if it exists
|
||||
@@ -274,9 +269,22 @@ function parseConfigStringAsJS(
|
||||
...parsedConfig.environment,
|
||||
};
|
||||
|
||||
// Apply complex defaults for environment flags that are set to true
|
||||
const environmentConfig: Partial<Record<keyof EnvironmentConfig, unknown>> =
|
||||
{};
|
||||
for (const [key, value] of Object.entries(mergedEnvironment)) {
|
||||
if (hasOwnProperty(EnvironmentConfigSchema.shape, key)) {
|
||||
if (value === true && key in testComplexConfigDefaults) {
|
||||
environmentConfig[key] = testComplexConfigDefaults[key];
|
||||
} else {
|
||||
environmentConfig[key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Validate environment config
|
||||
const validatedEnvironment =
|
||||
EnvironmentConfigSchema.safeParse(mergedEnvironment);
|
||||
EnvironmentConfigSchema.safeParse(environmentConfig);
|
||||
if (!validatedEnvironment.success) {
|
||||
CompilerError.invariant(false, {
|
||||
reason: 'Invalid environment configuration in config pragma',
|
||||
@@ -286,6 +294,10 @@ function parseConfigStringAsJS(
|
||||
});
|
||||
}
|
||||
|
||||
if (validatedEnvironment.data.enableResetCacheOnSourceFileChanges == null) {
|
||||
validatedEnvironment.data.enableResetCacheOnSourceFileChanges = false;
|
||||
}
|
||||
|
||||
options.environment = validatedEnvironment.data;
|
||||
}
|
||||
|
||||
@@ -296,7 +308,9 @@ function parseConfigStringAsJS(
|
||||
}
|
||||
|
||||
if (hasOwnProperty(defaultOptions, key)) {
|
||||
if (key === 'target' && value === 'donotuse_meta_internal') {
|
||||
if (value === true && key in testComplexPluginOptionDefaults) {
|
||||
options[key] = testComplexPluginOptionDefaults[key];
|
||||
} else if (key === 'target' && value === 'donotuse_meta_internal') {
|
||||
options[key] = {
|
||||
kind: value,
|
||||
runtimeModule: 'react',
|
||||
|
||||
@@ -129,7 +129,6 @@ function useFoo(t0) {
|
||||
t1 = null;
|
||||
break bb0;
|
||||
}
|
||||
|
||||
if (cond2) {
|
||||
mutate(s);
|
||||
}
|
||||
|
||||
@@ -46,16 +46,14 @@ function useFoo(t0) {
|
||||
t1 = $[0];
|
||||
}
|
||||
let items = t1;
|
||||
if ($[1] !== cond) {
|
||||
bb0: {
|
||||
if (cond) {
|
||||
items = [];
|
||||
} else {
|
||||
break bb0;
|
||||
}
|
||||
|
||||
items.push(2);
|
||||
bb0: if ($[1] !== cond) {
|
||||
if (cond) {
|
||||
items = [];
|
||||
} else {
|
||||
break bb0;
|
||||
}
|
||||
|
||||
items.push(2);
|
||||
$[1] = cond;
|
||||
$[2] = items;
|
||||
} else {
|
||||
|
||||
@@ -43,7 +43,6 @@ function useFoo(t0) {
|
||||
if ($[0] !== cond || $[1] !== value) {
|
||||
bb0: {
|
||||
items = [];
|
||||
|
||||
if (cond) {
|
||||
break bb0;
|
||||
}
|
||||
|
||||
@@ -39,7 +39,6 @@ function Foo() {
|
||||
if (cond) {
|
||||
thing = makeObject_Primitives();
|
||||
}
|
||||
|
||||
if (CONST_TRUE) {
|
||||
mutate(thing);
|
||||
}
|
||||
|
||||
@@ -23,7 +23,6 @@ import { c as _c } from "react/compiler-runtime";
|
||||
function useBar(props) {
|
||||
const $ = _c(1);
|
||||
let z;
|
||||
|
||||
if (props.a) {
|
||||
if (props.b) {
|
||||
let t0;
|
||||
|
||||
@@ -67,7 +67,6 @@ function getNativeLogFunction(level) {
|
||||
) {
|
||||
logLevel = LOG_LEVELS.warn;
|
||||
}
|
||||
|
||||
if (global.__inspectorLog) {
|
||||
global.__inspectorLog(
|
||||
INSPECTOR_LEVELS[logLevel],
|
||||
@@ -76,7 +75,6 @@ function getNativeLogFunction(level) {
|
||||
INSPECTOR_FRAMES_TO_SKIP,
|
||||
);
|
||||
}
|
||||
|
||||
if (groupStack.length) {
|
||||
str = groupFormat("", str);
|
||||
}
|
||||
|
||||
@@ -47,7 +47,9 @@ function useKeyCommand() {
|
||||
};
|
||||
|
||||
const moveLeft = { handler: handleKey("left") };
|
||||
|
||||
const moveRight = { handler: handleKey("right") };
|
||||
|
||||
t0 = [moveLeft, moveRight];
|
||||
$[0] = t0;
|
||||
} else {
|
||||
|
||||
@@ -33,6 +33,7 @@ function Component() {
|
||||
let y;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
y = x = {};
|
||||
|
||||
const foo = () => {
|
||||
x = makeArray();
|
||||
};
|
||||
|
||||
@@ -44,7 +44,6 @@ function ComponentA(props) {
|
||||
if (b) {
|
||||
a.push(props.p0);
|
||||
}
|
||||
|
||||
if (props.p1) {
|
||||
b.push(props.p2);
|
||||
}
|
||||
@@ -69,7 +68,6 @@ function ComponentB(props) {
|
||||
if (mayMutate(b)) {
|
||||
a.push(props.p0);
|
||||
}
|
||||
|
||||
if (props.p1) {
|
||||
b.push(props.p2);
|
||||
}
|
||||
|
||||
@@ -34,7 +34,6 @@ function Component(props) {
|
||||
const foo = () => {
|
||||
setX(1);
|
||||
};
|
||||
|
||||
if (props.cond) {
|
||||
setX(2);
|
||||
foo();
|
||||
|
||||
@@ -36,6 +36,7 @@ function Foo() {
|
||||
return identity(1);
|
||||
},
|
||||
};
|
||||
|
||||
t0 = x.foo();
|
||||
$[0] = t0;
|
||||
} else {
|
||||
|
||||
@@ -79,6 +79,7 @@ function foo() {
|
||||
value={[
|
||||
true,
|
||||
true,
|
||||
|
||||
"a\nb",
|
||||
"\n",
|
||||
"a1b",
|
||||
|
||||
@@ -48,6 +48,7 @@ function foo() {
|
||||
true,
|
||||
-Infinity,
|
||||
-NaN,
|
||||
|
||||
-1 * NaN,
|
||||
-1 * Infinity,
|
||||
-1 * -Infinity,
|
||||
|
||||
@@ -28,7 +28,6 @@ function Component(props) {
|
||||
const a = [];
|
||||
const b = {};
|
||||
new Foo(a, b);
|
||||
|
||||
new Foo(b);
|
||||
t0 = <div a={a} b={b} />;
|
||||
$[0] = t0;
|
||||
|
||||
@@ -43,6 +43,7 @@ function Component(t0) {
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
invoke(obj.method, cond);
|
||||
$[0] = cond;
|
||||
$[1] = x;
|
||||
|
||||
@@ -27,7 +27,6 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
```javascript
|
||||
function Component(props) {
|
||||
debugger;
|
||||
|
||||
if (props.cond) {
|
||||
debugger;
|
||||
} else {
|
||||
|
||||
@@ -26,7 +26,6 @@ function Component(props) {
|
||||
let x;
|
||||
if ($[0] !== props.a || $[1] !== props.b) {
|
||||
x = { a: props.a, b: props.b };
|
||||
|
||||
delete x["b"];
|
||||
$[0] = props.a;
|
||||
$[1] = props.b;
|
||||
|
||||
@@ -46,7 +46,6 @@ function foo(a, b) {
|
||||
if (x.length) {
|
||||
y.push(x);
|
||||
}
|
||||
|
||||
if (b) {
|
||||
y.push(b);
|
||||
}
|
||||
|
||||
@@ -46,7 +46,6 @@ function foo(x, y, z) {
|
||||
} else {
|
||||
items2 = $[2];
|
||||
}
|
||||
|
||||
if (y) {
|
||||
items.push(x);
|
||||
}
|
||||
|
||||
@@ -1,77 +0,0 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @compilationMode:"infer" @enablePreserveExistingMemoizationGuarantees @validatePreserveExistingMemoizationGuarantees
|
||||
import {useMemo} from 'react';
|
||||
import {makeObject_Primitives, ValidateMemoization} from 'shared-runtime';
|
||||
|
||||
function Component(props) {
|
||||
const result = useMemo(
|
||||
() => makeObject(props.value).value + 1,
|
||||
[props.value]
|
||||
);
|
||||
console.log(result);
|
||||
return 'ok';
|
||||
}
|
||||
|
||||
function makeObject(value) {
|
||||
console.log(value);
|
||||
return {value};
|
||||
}
|
||||
|
||||
export const TODO_FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{value: 42}],
|
||||
sequentialRenders: [
|
||||
{value: 42},
|
||||
{value: 42},
|
||||
{value: 3.14},
|
||||
{value: 3.14},
|
||||
{value: 42},
|
||||
{value: 3.14},
|
||||
{value: 42},
|
||||
{value: 3.14},
|
||||
],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
// @compilationMode:"infer" @enablePreserveExistingMemoizationGuarantees @validatePreserveExistingMemoizationGuarantees
|
||||
import { useMemo } from "react";
|
||||
import { makeObject_Primitives, ValidateMemoization } from "shared-runtime";
|
||||
|
||||
function Component(props) {
|
||||
const result = makeObject(props.value).value + 1;
|
||||
|
||||
console.log(result);
|
||||
return "ok";
|
||||
}
|
||||
|
||||
function makeObject(value) {
|
||||
console.log(value);
|
||||
return { value };
|
||||
}
|
||||
|
||||
export const TODO_FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{ value: 42 }],
|
||||
sequentialRenders: [
|
||||
{ value: 42 },
|
||||
{ value: 42 },
|
||||
{ value: 3.14 },
|
||||
{ value: 3.14 },
|
||||
{ value: 42 },
|
||||
{ value: 3.14 },
|
||||
{ value: 42 },
|
||||
{ value: 3.14 },
|
||||
],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
### Eval output
|
||||
(kind: exception) Fixture not implemented
|
||||
@@ -1,32 +0,0 @@
|
||||
// @compilationMode:"infer" @enablePreserveExistingMemoizationGuarantees @validatePreserveExistingMemoizationGuarantees
|
||||
import {useMemo} from 'react';
|
||||
import {makeObject_Primitives, ValidateMemoization} from 'shared-runtime';
|
||||
|
||||
function Component(props) {
|
||||
const result = useMemo(
|
||||
() => makeObject(props.value).value + 1,
|
||||
[props.value]
|
||||
);
|
||||
console.log(result);
|
||||
return 'ok';
|
||||
}
|
||||
|
||||
function makeObject(value) {
|
||||
console.log(value);
|
||||
return {value};
|
||||
}
|
||||
|
||||
export const TODO_FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{value: 42}],
|
||||
sequentialRenders: [
|
||||
{value: 42},
|
||||
{value: 42},
|
||||
{value: 3.14},
|
||||
{value: 3.14},
|
||||
{value: 42},
|
||||
{value: 3.14},
|
||||
{value: 42},
|
||||
{value: 3.14},
|
||||
],
|
||||
};
|
||||
@@ -1,81 +0,0 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @compilationMode:"infer" @enablePreserveExistingMemoizationGuarantees @validatePreserveExistingMemoizationGuarantees
|
||||
import {useMemo} from 'react';
|
||||
import {makeObject_Primitives, ValidateMemoization} from 'shared-runtime';
|
||||
|
||||
function Component(props) {
|
||||
const result = makeObject(props.value).value + 1;
|
||||
console.log(result);
|
||||
return 'ok';
|
||||
}
|
||||
|
||||
function makeObject(value) {
|
||||
console.log(value);
|
||||
return {value};
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{value: 42}],
|
||||
sequentialRenders: [
|
||||
{value: 42},
|
||||
{value: 42},
|
||||
{value: 3.14},
|
||||
{value: 3.14},
|
||||
{value: 42},
|
||||
{value: 3.14},
|
||||
{value: 42},
|
||||
{value: 3.14},
|
||||
],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
// @compilationMode:"infer" @enablePreserveExistingMemoizationGuarantees @validatePreserveExistingMemoizationGuarantees
|
||||
import { useMemo } from "react";
|
||||
import { makeObject_Primitives, ValidateMemoization } from "shared-runtime";
|
||||
|
||||
function Component(props) {
|
||||
const result = makeObject(props.value).value + 1;
|
||||
console.log(result);
|
||||
return "ok";
|
||||
}
|
||||
|
||||
function makeObject(value) {
|
||||
console.log(value);
|
||||
return { value };
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{ value: 42 }],
|
||||
sequentialRenders: [
|
||||
{ value: 42 },
|
||||
{ value: 42 },
|
||||
{ value: 3.14 },
|
||||
{ value: 3.14 },
|
||||
{ value: 42 },
|
||||
{ value: 3.14 },
|
||||
{ value: 42 },
|
||||
{ value: 3.14 },
|
||||
],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
### Eval output
|
||||
(kind: ok) "ok"
|
||||
"ok"
|
||||
"ok"
|
||||
"ok"
|
||||
"ok"
|
||||
"ok"
|
||||
"ok"
|
||||
"ok"
|
||||
logs: [42,43,42,43,3.14,4.140000000000001,3.14,4.140000000000001,42,43,3.14,4.140000000000001,42,43,3.14,4.140000000000001]
|
||||
@@ -1,29 +0,0 @@
|
||||
// @compilationMode:"infer" @enablePreserveExistingMemoizationGuarantees @validatePreserveExistingMemoizationGuarantees
|
||||
import {useMemo} from 'react';
|
||||
import {makeObject_Primitives, ValidateMemoization} from 'shared-runtime';
|
||||
|
||||
function Component(props) {
|
||||
const result = makeObject(props.value).value + 1;
|
||||
console.log(result);
|
||||
return 'ok';
|
||||
}
|
||||
|
||||
function makeObject(value) {
|
||||
console.log(value);
|
||||
return {value};
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{value: 42}],
|
||||
sequentialRenders: [
|
||||
{value: 42},
|
||||
{value: 42},
|
||||
{value: 3.14},
|
||||
{value: 3.14},
|
||||
{value: 42},
|
||||
{value: 3.14},
|
||||
{value: 42},
|
||||
{value: 3.14},
|
||||
],
|
||||
};
|
||||
@@ -57,7 +57,6 @@ function Component(t0) {
|
||||
let y;
|
||||
if ($[0] !== a || $[1] !== b || $[2] !== c) {
|
||||
x = [];
|
||||
|
||||
if (a) {
|
||||
let t1;
|
||||
if ($[5] !== b) {
|
||||
|
||||
@@ -48,7 +48,6 @@ function foo(a, b, c) {
|
||||
} else {
|
||||
x = $[3];
|
||||
}
|
||||
|
||||
if (x.length) {
|
||||
return x;
|
||||
}
|
||||
|
||||
@@ -28,7 +28,6 @@ function Component(props) {
|
||||
let items;
|
||||
if ($[0] !== props.items) {
|
||||
items = [];
|
||||
|
||||
for (let i = 0, length = props.items.length; i < length; i++) {
|
||||
items.push(props.items[i]);
|
||||
}
|
||||
|
||||
@@ -39,7 +39,6 @@ function Component(props) {
|
||||
for (const x of items) {
|
||||
lastItem = x;
|
||||
}
|
||||
|
||||
if (lastItem != null) {
|
||||
lastItem.a = lastItem.a + 1;
|
||||
}
|
||||
|
||||
@@ -39,7 +39,6 @@ function Component(props) {
|
||||
for (const x of items) {
|
||||
lastItem = x;
|
||||
}
|
||||
|
||||
if (lastItem != null) {
|
||||
lastItem.a = lastItem.a + 1;
|
||||
}
|
||||
|
||||
@@ -41,7 +41,6 @@ function Component(props) {
|
||||
t1 = $[1];
|
||||
}
|
||||
const onChange = t1;
|
||||
|
||||
if (props.cond) {
|
||||
}
|
||||
let t2;
|
||||
|
||||
@@ -69,7 +69,6 @@ const Foo = isForgetEnabled_Fixtures()
|
||||
if (DEV && shouldInstrument)
|
||||
useRenderCounter("Foo", "/codegen-instrument-forget-gating-test.ts");
|
||||
const $ = _c(3);
|
||||
|
||||
if (props.bar < 0) {
|
||||
return props.children;
|
||||
}
|
||||
|
||||
@@ -63,7 +63,6 @@ const Foo = isForgetEnabled_Fixtures()
|
||||
? function Foo(props) {
|
||||
"use forget";
|
||||
const $ = _c(3);
|
||||
|
||||
if (props.bar < 0) {
|
||||
return props.children;
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ function hoisting() {
|
||||
return bar();
|
||||
},
|
||||
};
|
||||
|
||||
const bar = _temp;
|
||||
|
||||
t0 = x.foo();
|
||||
|
||||
@@ -30,7 +30,6 @@ function Component(props) {
|
||||
let items;
|
||||
if ($[0] !== props.a || $[1] !== props.cond) {
|
||||
let t0;
|
||||
|
||||
if (props.cond) {
|
||||
t0 = [];
|
||||
} else {
|
||||
|
||||
@@ -390,7 +390,6 @@ function ConditionalJsx(t0) {
|
||||
t1 = $[0];
|
||||
}
|
||||
let content = t1;
|
||||
|
||||
if (shouldWrap) {
|
||||
const t2 = content;
|
||||
let t3;
|
||||
|
||||
@@ -27,7 +27,6 @@ import * as SharedRuntime from "shared-runtime";
|
||||
function useFoo(t0) {
|
||||
const $ = _c(1);
|
||||
const { cond } = t0;
|
||||
|
||||
if (cond) {
|
||||
let t1;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
|
||||
@@ -1,107 +0,0 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @compilationMode:"infer" @enablePreserveExistingMemoizationGuarantees @validatePreserveExistingMemoizationGuarantees
|
||||
import {useMemo} from 'react';
|
||||
import {makeObject_Primitives, ValidateMemoization} from 'shared-runtime';
|
||||
|
||||
function Component(props) {
|
||||
const result = useMemo(() => {
|
||||
return makeObject(props.value).value + 1;
|
||||
}, [props.value]);
|
||||
return <ValidateMemoization inputs={[props.value]} output={result} />;
|
||||
}
|
||||
|
||||
function makeObject(value) {
|
||||
console.log(value);
|
||||
return {value};
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{value: 42}],
|
||||
sequentialRenders: [
|
||||
{value: 42},
|
||||
{value: 42},
|
||||
{value: 3.14},
|
||||
{value: 3.14},
|
||||
{value: 42},
|
||||
{value: 3.14},
|
||||
{value: 42},
|
||||
{value: 3.14},
|
||||
],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime"; // @compilationMode:"infer" @enablePreserveExistingMemoizationGuarantees @validatePreserveExistingMemoizationGuarantees
|
||||
import { useMemo } from "react";
|
||||
import { makeObject_Primitives, ValidateMemoization } from "shared-runtime";
|
||||
|
||||
function Component(props) {
|
||||
const $ = _c(7);
|
||||
let t0;
|
||||
if ($[0] !== props.value) {
|
||||
t0 = makeObject(props.value);
|
||||
$[0] = props.value;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t0 = $[1];
|
||||
}
|
||||
const result = t0.value + 1;
|
||||
let t1;
|
||||
if ($[2] !== props.value) {
|
||||
t1 = [props.value];
|
||||
$[2] = props.value;
|
||||
$[3] = t1;
|
||||
} else {
|
||||
t1 = $[3];
|
||||
}
|
||||
let t2;
|
||||
if ($[4] !== result || $[5] !== t1) {
|
||||
t2 = <ValidateMemoization inputs={t1} output={result} />;
|
||||
$[4] = result;
|
||||
$[5] = t1;
|
||||
$[6] = t2;
|
||||
} else {
|
||||
t2 = $[6];
|
||||
}
|
||||
return t2;
|
||||
}
|
||||
|
||||
function makeObject(value) {
|
||||
console.log(value);
|
||||
return { value };
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{ value: 42 }],
|
||||
sequentialRenders: [
|
||||
{ value: 42 },
|
||||
{ value: 42 },
|
||||
{ value: 3.14 },
|
||||
{ value: 3.14 },
|
||||
{ value: 42 },
|
||||
{ value: 3.14 },
|
||||
{ value: 42 },
|
||||
{ value: 3.14 },
|
||||
],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
### Eval output
|
||||
(kind: ok) <div>{"inputs":[42],"output":43}</div>
|
||||
<div>{"inputs":[42],"output":43}</div>
|
||||
<div>{"inputs":[3.14],"output":4.140000000000001}</div>
|
||||
<div>{"inputs":[3.14],"output":4.140000000000001}</div>
|
||||
<div>{"inputs":[42],"output":43}</div>
|
||||
<div>{"inputs":[3.14],"output":4.140000000000001}</div>
|
||||
<div>{"inputs":[42],"output":43}</div>
|
||||
<div>{"inputs":[3.14],"output":4.140000000000001}</div>
|
||||
logs: [42,3.14,42,3.14,42,3.14]
|
||||
@@ -1,30 +0,0 @@
|
||||
// @compilationMode:"infer" @enablePreserveExistingMemoizationGuarantees @validatePreserveExistingMemoizationGuarantees
|
||||
import {useMemo} from 'react';
|
||||
import {makeObject_Primitives, ValidateMemoization} from 'shared-runtime';
|
||||
|
||||
function Component(props) {
|
||||
const result = useMemo(() => {
|
||||
return makeObject(props.value).value + 1;
|
||||
}, [props.value]);
|
||||
return <ValidateMemoization inputs={[props.value]} output={result} />;
|
||||
}
|
||||
|
||||
function makeObject(value) {
|
||||
console.log(value);
|
||||
return {value};
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{value: 42}],
|
||||
sequentialRenders: [
|
||||
{value: 42},
|
||||
{value: 42},
|
||||
{value: 3.14},
|
||||
{value: 3.14},
|
||||
{value: 42},
|
||||
{value: 3.14},
|
||||
{value: 42},
|
||||
{value: 3.14},
|
||||
],
|
||||
};
|
||||
@@ -30,7 +30,6 @@ const { getNumber } = require("shared-runtime");
|
||||
function Component(props) {
|
||||
const $ = _c(1);
|
||||
let x;
|
||||
|
||||
if (props.cond) {
|
||||
let t0;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @compilationMode:"infer"
|
||||
import {makeArray} from 'shared-runtime';
|
||||
|
||||
function Component() {
|
||||
@@ -31,7 +30,7 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime"; // @compilationMode:"infer"
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
import { makeArray } from "shared-runtime";
|
||||
|
||||
function Component() {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// @compilationMode:"infer"
|
||||
import {makeArray} from 'shared-runtime';
|
||||
|
||||
function Component() {
|
||||
|
||||
@@ -75,6 +75,7 @@ function Component() {
|
||||
if ($[0] !== state) {
|
||||
t0 = [
|
||||
React,
|
||||
|
||||
state,
|
||||
CONST,
|
||||
NON_REASSIGNED_LET,
|
||||
|
||||
@@ -94,16 +94,12 @@ function testFunction(props) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (a) {
|
||||
}
|
||||
|
||||
if (b) {
|
||||
}
|
||||
|
||||
if (c) {
|
||||
}
|
||||
|
||||
if (d) {
|
||||
}
|
||||
|
||||
|
||||
@@ -78,19 +78,14 @@ function Component(props) {
|
||||
x = {};
|
||||
x.b = b;
|
||||
const y = mutate(x, d);
|
||||
|
||||
if (a) {
|
||||
}
|
||||
|
||||
if (b) {
|
||||
}
|
||||
|
||||
if (c) {
|
||||
}
|
||||
|
||||
if (d) {
|
||||
}
|
||||
|
||||
if (y) {
|
||||
}
|
||||
|
||||
|
||||
@@ -51,16 +51,12 @@ function Component(props) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (a) {
|
||||
}
|
||||
|
||||
if (b) {
|
||||
}
|
||||
|
||||
if (c) {
|
||||
}
|
||||
|
||||
if (d) {
|
||||
}
|
||||
|
||||
|
||||
@@ -49,12 +49,12 @@ import {
|
||||
} from "shared-runtime";
|
||||
|
||||
function useFoo(t0) {
|
||||
const $ = _c(4);
|
||||
const $ = _c(3);
|
||||
const { data } = t0;
|
||||
let obj;
|
||||
let myDiv = null;
|
||||
if ($[0] !== data.cond || $[1] !== data.cond1) {
|
||||
bb0: if (data.cond) {
|
||||
bb0: if (data.cond) {
|
||||
if ($[0] !== data.cond1) {
|
||||
obj = makeObject_Primitives();
|
||||
if (data.cond1) {
|
||||
myDiv = <Stringify value={mutateAndReturn(obj)} />;
|
||||
@@ -62,14 +62,13 @@ function useFoo(t0) {
|
||||
}
|
||||
|
||||
mutate(obj);
|
||||
$[0] = data.cond1;
|
||||
$[1] = obj;
|
||||
$[2] = myDiv;
|
||||
} else {
|
||||
obj = $[1];
|
||||
myDiv = $[2];
|
||||
}
|
||||
$[0] = data.cond;
|
||||
$[1] = data.cond1;
|
||||
$[2] = obj;
|
||||
$[3] = myDiv;
|
||||
} else {
|
||||
obj = $[2];
|
||||
myDiv = $[3];
|
||||
}
|
||||
return myDiv;
|
||||
}
|
||||
|
||||
@@ -53,10 +53,8 @@ function Component(t0) {
|
||||
let z;
|
||||
if ($[0] !== prop1 || $[1] !== prop2) {
|
||||
let x = [{ value: prop1 }];
|
||||
|
||||
while (x.length < 2) {
|
||||
arrayPush(x, { value: prop2 });
|
||||
|
||||
if (x[0].value === prop1) {
|
||||
x = [{ value: prop2 }];
|
||||
const y = x;
|
||||
|
||||
@@ -30,7 +30,6 @@ function Component(props) {
|
||||
let items;
|
||||
if ($[0] !== props.a || $[1] !== props.cond) {
|
||||
let t0;
|
||||
|
||||
if (props.cond) {
|
||||
t0 = [];
|
||||
} else {
|
||||
|
||||
@@ -33,6 +33,7 @@ function Component(props) {
|
||||
if ($[0] !== props.value) {
|
||||
const key = {};
|
||||
context = { [key]: identity([props.value]) };
|
||||
|
||||
mutate(key);
|
||||
$[0] = props.value;
|
||||
$[1] = context;
|
||||
|
||||
@@ -44,6 +44,7 @@ function Component(props) {
|
||||
t2 = $[3];
|
||||
}
|
||||
context = t2;
|
||||
|
||||
mutate(key);
|
||||
$[0] = props.value;
|
||||
$[1] = context;
|
||||
|
||||
@@ -32,7 +32,6 @@ import fbt from "fbt";
|
||||
function Component() {
|
||||
const $ = _c(1);
|
||||
const sections = Object.keys(items);
|
||||
|
||||
for (let i = 0; i < sections.length; i = i + 3, i) {
|
||||
chunks.push(sections.slice(i, i + 3).map(_temp));
|
||||
}
|
||||
|
||||
@@ -51,6 +51,7 @@ function useFoo(arr1, arr2) {
|
||||
if ($[2] !== arr2 || $[3] !== x) {
|
||||
let y;
|
||||
t1 = () => ({ y });
|
||||
|
||||
(y = x.concat(arr2)), y;
|
||||
$[2] = arr2;
|
||||
$[3] = x;
|
||||
|
||||
@@ -89,7 +89,6 @@ function useFoo(t0) {
|
||||
y = $[2];
|
||||
z = $[3];
|
||||
}
|
||||
|
||||
if (z[0] !== y) {
|
||||
throw new Error("oh no!");
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ function Component(props) {
|
||||
if ($[0] !== props.value) {
|
||||
const key = {};
|
||||
context = { [key]: identity([props.value]) };
|
||||
|
||||
mutate(key);
|
||||
$[0] = props.value;
|
||||
$[1] = context;
|
||||
|
||||
@@ -43,6 +43,7 @@ function Component(props) {
|
||||
t2 = $[3];
|
||||
}
|
||||
context = t2;
|
||||
|
||||
mutate(key);
|
||||
$[0] = props.value;
|
||||
$[1] = context;
|
||||
|
||||
@@ -38,11 +38,13 @@ function useHook(props) {
|
||||
return props;
|
||||
},
|
||||
};
|
||||
|
||||
const y = {
|
||||
getY() {
|
||||
return "y";
|
||||
},
|
||||
};
|
||||
|
||||
t0 = setProperty(x, y);
|
||||
$[0] = props;
|
||||
$[1] = t0;
|
||||
|
||||
@@ -39,6 +39,7 @@ function useHook(a) {
|
||||
return x;
|
||||
},
|
||||
};
|
||||
|
||||
t0 = obj.method();
|
||||
$[0] = a;
|
||||
$[1] = t0;
|
||||
|
||||
@@ -37,6 +37,7 @@ function useHook(t0) {
|
||||
return value;
|
||||
},
|
||||
};
|
||||
|
||||
mutate(x);
|
||||
$[0] = value;
|
||||
$[1] = obj;
|
||||
|
||||
@@ -37,6 +37,7 @@ function useHook(t0) {
|
||||
return x;
|
||||
},
|
||||
};
|
||||
|
||||
mutate(obj);
|
||||
$[0] = value;
|
||||
$[1] = obj;
|
||||
|
||||
@@ -31,6 +31,7 @@ function Component() {
|
||||
return 1;
|
||||
},
|
||||
};
|
||||
|
||||
t0 = obj.method();
|
||||
$[0] = t0;
|
||||
} else {
|
||||
|
||||
@@ -48,7 +48,9 @@ function useKeyCommand() {
|
||||
};
|
||||
|
||||
const moveLeft = { handler: handleKey("left") };
|
||||
|
||||
const moveRight = { handler: handleKey("right") };
|
||||
|
||||
t0 = [moveLeft, moveRight];
|
||||
$[0] = t0;
|
||||
} else {
|
||||
|
||||
@@ -27,7 +27,6 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
function foo(a, b, c) {
|
||||
const x = [];
|
||||
const y = [];
|
||||
|
||||
if (x) {
|
||||
}
|
||||
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @enablePreserveExistingMemoizationGuarantees
|
||||
import {fbt} from 'fbt';
|
||||
|
||||
function Component() {
|
||||
const buttonLabel = () => {
|
||||
if (!someCondition) {
|
||||
return <fbt desc="My label">{'Purchase as a gift'}</fbt>;
|
||||
} else if (
|
||||
!iconOnly &&
|
||||
showPrice &&
|
||||
item?.current_gift_offer?.price?.formatted != null
|
||||
) {
|
||||
return (
|
||||
<fbt desc="Gift button's label">
|
||||
{'Gift | '}
|
||||
<fbt:param name="price">
|
||||
{item?.current_gift_offer?.price?.formatted}
|
||||
</fbt:param>
|
||||
</fbt>
|
||||
);
|
||||
} else if (!iconOnly && !showPrice) {
|
||||
return <fbt desc="Gift button's label">{'Gift'}</fbt>;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<View>
|
||||
<Button text={buttonLabel()} />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime"; // @enablePreserveExistingMemoizationGuarantees
|
||||
import { fbt } from "fbt";
|
||||
|
||||
function Component() {
|
||||
const $ = _c(1);
|
||||
const buttonLabel = _temp;
|
||||
let t0;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t0 = (
|
||||
<View>
|
||||
<Button text={buttonLabel()} />
|
||||
</View>
|
||||
);
|
||||
$[0] = t0;
|
||||
} else {
|
||||
t0 = $[0];
|
||||
}
|
||||
return t0;
|
||||
}
|
||||
function _temp() {
|
||||
if (!someCondition) {
|
||||
return fbt._("Purchase as a gift", null, { hk: "1gHj4g" });
|
||||
} else {
|
||||
if (
|
||||
!iconOnly &&
|
||||
showPrice &&
|
||||
item?.current_gift_offer?.price?.formatted != null
|
||||
) {
|
||||
return fbt._(
|
||||
"Gift | {price}",
|
||||
[fbt._param("price", item?.current_gift_offer?.price?.formatted)],
|
||||
{ hk: "3GTnGE" },
|
||||
);
|
||||
} else {
|
||||
if (!iconOnly && !showPrice) {
|
||||
return fbt._("Gift", null, { hk: "3fqfrk" });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### Eval output
|
||||
(kind: exception) Fixture not implemented
|
||||
@@ -1,31 +0,0 @@
|
||||
// @enablePreserveExistingMemoizationGuarantees
|
||||
import {fbt} from 'fbt';
|
||||
|
||||
function Component() {
|
||||
const buttonLabel = () => {
|
||||
if (!someCondition) {
|
||||
return <fbt desc="My label">{'Purchase as a gift'}</fbt>;
|
||||
} else if (
|
||||
!iconOnly &&
|
||||
showPrice &&
|
||||
item?.current_gift_offer?.price?.formatted != null
|
||||
) {
|
||||
return (
|
||||
<fbt desc="Gift button's label">
|
||||
{'Gift | '}
|
||||
<fbt:param name="price">
|
||||
{item?.current_gift_offer?.price?.formatted}
|
||||
</fbt:param>
|
||||
</fbt>
|
||||
);
|
||||
} else if (!iconOnly && !showPrice) {
|
||||
return <fbt desc="Gift button's label">{'Gift'}</fbt>;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<View>
|
||||
<Button text={buttonLabel()} />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
@@ -36,7 +36,6 @@ import { useMemo } from "react";
|
||||
// (i.e. inferred non-mutable or non-escaping values don't get memoized)
|
||||
function useFoo(t0) {
|
||||
const { minWidth, styles, setStyles } = t0;
|
||||
|
||||
if (styles.width > minWidth) {
|
||||
setStyles(styles);
|
||||
}
|
||||
|
||||
@@ -34,7 +34,6 @@ import { identity } from "shared-runtime";
|
||||
|
||||
function useFoo(cond) {
|
||||
let t0;
|
||||
|
||||
if (cond) {
|
||||
t0 = 2;
|
||||
} else {
|
||||
|
||||
@@ -34,7 +34,6 @@ import { identity } from "shared-runtime";
|
||||
|
||||
function useFoo(cond) {
|
||||
let t0;
|
||||
|
||||
if (cond) {
|
||||
t0 = identity(10);
|
||||
} else {
|
||||
|
||||
@@ -41,7 +41,6 @@ function Component(t0) {
|
||||
const { entity, children } = t0;
|
||||
|
||||
const showMessage = () => entity != null;
|
||||
|
||||
if (!showMessage()) {
|
||||
return children;
|
||||
}
|
||||
|
||||
@@ -50,6 +50,7 @@ function useFoo(arr1, arr2) {
|
||||
if ($[2] !== arr2 || $[3] !== x) {
|
||||
let y;
|
||||
t1 = () => ({ y });
|
||||
|
||||
(y = x.concat(arr2)), y;
|
||||
$[2] = arr2;
|
||||
$[3] = x;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @enablePreserveExistingMemoizationGuarantees
|
||||
// @enableForest
|
||||
function Component({base, start, increment, test}) {
|
||||
let value = base;
|
||||
for (let i = start; i < test; i += increment) {
|
||||
@@ -27,23 +27,25 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime"; // @enablePreserveExistingMemoizationGuarantees
|
||||
import { c as _c } from "react/compiler-runtime"; // @enableForest
|
||||
function Component(t0) {
|
||||
const $ = _c(2);
|
||||
const $ = _c(5);
|
||||
const { base, start, increment, test } = t0;
|
||||
let value = base;
|
||||
for (let i = start; i < test; i = i + increment, i) {
|
||||
value = value + i;
|
||||
}
|
||||
let t1;
|
||||
if ($[0] !== value) {
|
||||
t1 = <div>{value}</div>;
|
||||
$[0] = value;
|
||||
$[1] = t1;
|
||||
let value;
|
||||
if ($[0] !== base || $[1] !== increment || $[2] !== start || $[3] !== test) {
|
||||
value = base;
|
||||
for (let i = start; i < test; i = i + increment, i) {
|
||||
value = value + i;
|
||||
}
|
||||
$[0] = base;
|
||||
$[1] = increment;
|
||||
$[2] = start;
|
||||
$[3] = test;
|
||||
$[4] = value;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
value = $[4];
|
||||
}
|
||||
return t1;
|
||||
return <div>{value}</div>;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @enablePreserveExistingMemoizationGuarantees
|
||||
// @enableForest
|
||||
function Component({base, start, increment, test}) {
|
||||
let value = base;
|
||||
for (let i = start; i < test; i += increment) {
|
||||
|
||||
@@ -45,7 +45,6 @@ function ComponentA(props) {
|
||||
if (b) {
|
||||
a.push(props.p0);
|
||||
}
|
||||
|
||||
if (props.p1) {
|
||||
b.push(props.p2);
|
||||
}
|
||||
@@ -70,7 +69,6 @@ function ComponentB(props) {
|
||||
if (mayMutate(b)) {
|
||||
a.push(props.p0);
|
||||
}
|
||||
|
||||
if (props.p1) {
|
||||
b.push(props.p2);
|
||||
}
|
||||
|
||||
@@ -31,7 +31,6 @@ function Component(props) {
|
||||
let items;
|
||||
if ($[0] !== props.a || $[1] !== props.cond) {
|
||||
let t0;
|
||||
|
||||
if (props.cond) {
|
||||
t0 = [];
|
||||
} else {
|
||||
|
||||
@@ -40,6 +40,7 @@ function useFoo(t0) {
|
||||
return identity(a.b.c);
|
||||
},
|
||||
};
|
||||
|
||||
t1 = <Stringify x={x} shouldInvokeFns={true} />;
|
||||
$[0] = a;
|
||||
$[1] = t1;
|
||||
|
||||
@@ -61,6 +61,7 @@ function Component(props) {
|
||||
y = x;
|
||||
}
|
||||
}
|
||||
|
||||
t0 = <Component data={x} />;
|
||||
$[0] = props.p0;
|
||||
$[1] = props.p2;
|
||||
|
||||
@@ -34,7 +34,6 @@ function Component(props) {
|
||||
let y;
|
||||
if ($[0] !== props.p0 || $[1] !== props.p2 || $[2] !== props.p3) {
|
||||
const x = [];
|
||||
|
||||
switch (props.p0) {
|
||||
case true: {
|
||||
x.push(props.p2);
|
||||
@@ -44,6 +43,7 @@ function Component(props) {
|
||||
y = x;
|
||||
}
|
||||
}
|
||||
|
||||
t0 = <Component data={x} />;
|
||||
$[0] = props.p0;
|
||||
$[1] = props.p2;
|
||||
|
||||
@@ -34,35 +34,37 @@ import { c as _c } from "react/compiler-runtime"; // @enablePropagateDepsInHIR
|
||||
import { useMemo } from "react";
|
||||
|
||||
function Component(props) {
|
||||
const $ = _c(5);
|
||||
const $ = _c(6);
|
||||
let t0;
|
||||
if (
|
||||
$[0] !== props.a ||
|
||||
$[1] !== props.b ||
|
||||
$[2] !== props.cond ||
|
||||
$[3] !== props.cond2
|
||||
) {
|
||||
bb0: {
|
||||
const y = [];
|
||||
bb0: {
|
||||
let y;
|
||||
if (
|
||||
$[0] !== props.a ||
|
||||
$[1] !== props.b ||
|
||||
$[2] !== props.cond ||
|
||||
$[3] !== props.cond2
|
||||
) {
|
||||
y = [];
|
||||
if (props.cond) {
|
||||
y.push(props.a);
|
||||
}
|
||||
|
||||
if (props.cond2) {
|
||||
t0 = y;
|
||||
break bb0;
|
||||
}
|
||||
|
||||
y.push(props.b);
|
||||
t0 = y;
|
||||
$[0] = props.a;
|
||||
$[1] = props.b;
|
||||
$[2] = props.cond;
|
||||
$[3] = props.cond2;
|
||||
$[4] = y;
|
||||
$[5] = t0;
|
||||
} else {
|
||||
y = $[4];
|
||||
t0 = $[5];
|
||||
}
|
||||
$[0] = props.a;
|
||||
$[1] = props.b;
|
||||
$[2] = props.cond;
|
||||
$[3] = props.cond2;
|
||||
$[4] = t0;
|
||||
} else {
|
||||
t0 = $[4];
|
||||
t0 = y;
|
||||
}
|
||||
const x = t0;
|
||||
return x;
|
||||
|
||||
@@ -33,7 +33,6 @@ function Component(props) {
|
||||
const $ = _c(2);
|
||||
let x = 0;
|
||||
let y = 0;
|
||||
|
||||
while (x === 0) {
|
||||
x = y;
|
||||
y = props.value;
|
||||
|
||||
@@ -29,7 +29,6 @@ function Component(props) {
|
||||
let x = [];
|
||||
x.push(props.p0);
|
||||
const y = x;
|
||||
|
||||
if (props.p1) {
|
||||
let t1;
|
||||
if ($[4] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
|
||||
@@ -59,6 +59,7 @@ function useFoo(props) {
|
||||
return b;
|
||||
},
|
||||
};
|
||||
|
||||
t1 = a.foo().bar();
|
||||
$0[0] = props;
|
||||
$0[1] = t1;
|
||||
|
||||
@@ -43,7 +43,6 @@ function Foo(t0) {
|
||||
<Stringify
|
||||
fn={() => {
|
||||
const arr = [];
|
||||
|
||||
for (const selectedUser of userIds) {
|
||||
arr.push(selectedUser);
|
||||
}
|
||||
|
||||
@@ -49,6 +49,7 @@ function Component() {
|
||||
if ($[0] !== params) {
|
||||
t0 = (partialParams) => {
|
||||
const nextParams = { ...params, ...partialParams };
|
||||
|
||||
nextParams.param = "value";
|
||||
console.log(nextParams);
|
||||
};
|
||||
|
||||
@@ -82,7 +82,6 @@ function Foo() {
|
||||
const result = t1;
|
||||
|
||||
useNoAlias(result, obj);
|
||||
|
||||
if (shouldCaptureObj && result[0] !== obj) {
|
||||
throw new Error("Unexpected");
|
||||
}
|
||||
|
||||
@@ -52,7 +52,6 @@ function Example() {
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t0 = function updateStyles() {
|
||||
const foo = fooRef.current;
|
||||
|
||||
if (barRef.current == null || foo == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -67,6 +67,7 @@ function Component(props) {
|
||||
const key = {};
|
||||
const tmp = (mutate(key), key);
|
||||
const context = { [tmp]: identity([props.value]) };
|
||||
|
||||
mutate(key);
|
||||
t0 = [context, key];
|
||||
$[0] = props.value;
|
||||
|
||||
@@ -72,6 +72,7 @@ function Component(props) {
|
||||
let t2;
|
||||
if ($[3] !== t0) {
|
||||
const linkProps = { url: t0 };
|
||||
|
||||
const x = {};
|
||||
let t3;
|
||||
let t4;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user