mirror of
https://github.com/facebook/react.git
synced 2026-02-21 19:31:52 +00:00
[compiler][snap] More minimization improvements (#35689)
* A few new minimization strategies, removing function params and array/object pattern elements * Ensure that we preserve the same set of errors based on not just category+reason but also description.
This commit is contained in:
@@ -18,7 +18,7 @@ type CompileSuccess = {kind: 'success'};
|
|||||||
type CompileParseError = {kind: 'parse_error'; message: string};
|
type CompileParseError = {kind: 'parse_error'; message: string};
|
||||||
type CompileErrors = {
|
type CompileErrors = {
|
||||||
kind: 'errors';
|
kind: 'errors';
|
||||||
errors: Array<{category: string; reason: string}>;
|
errors: Array<{category: string; reason: string; description: string | null}>;
|
||||||
};
|
};
|
||||||
type CompileResult = CompileSuccess | CompileParseError | CompileErrors;
|
type CompileResult = CompileSuccess | CompileParseError | CompileErrors;
|
||||||
|
|
||||||
@@ -70,7 +70,11 @@ function compileAndGetError(
|
|||||||
return {kind: 'success'};
|
return {kind: 'success'};
|
||||||
} catch (e: unknown) {
|
} catch (e: unknown) {
|
||||||
const error = e as Error & {
|
const error = e as Error & {
|
||||||
details?: Array<{category: string; reason: string}>;
|
details?: Array<{
|
||||||
|
category: string;
|
||||||
|
reason: string;
|
||||||
|
description: string | null;
|
||||||
|
}>;
|
||||||
};
|
};
|
||||||
// Check if this is a CompilerError with details
|
// Check if this is a CompilerError with details
|
||||||
if (error.details && error.details.length > 0) {
|
if (error.details && error.details.length > 0) {
|
||||||
@@ -79,6 +83,7 @@ function compileAndGetError(
|
|||||||
errors: error.details.map(detail => ({
|
errors: error.details.map(detail => ({
|
||||||
category: detail.category,
|
category: detail.category,
|
||||||
reason: detail.reason,
|
reason: detail.reason,
|
||||||
|
description: detail.description,
|
||||||
})),
|
})),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -89,6 +94,7 @@ function compileAndGetError(
|
|||||||
{
|
{
|
||||||
category: error.name ?? 'Error',
|
category: error.name ?? 'Error',
|
||||||
reason: error.message,
|
reason: error.message,
|
||||||
|
description: null,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
@@ -108,7 +114,8 @@ function errorsMatch(a: CompileErrors, b: CompileResult): boolean {
|
|||||||
for (let i = 0; i < a.errors.length; i++) {
|
for (let i = 0; i < a.errors.length; i++) {
|
||||||
if (
|
if (
|
||||||
a.errors[i].category !== b.errors[i].category ||
|
a.errors[i].category !== b.errors[i].category ||
|
||||||
a.errors[i].reason !== b.errors[i].reason
|
a.errors[i].reason !== b.errors[i].reason ||
|
||||||
|
a.errors[i].description !== b.errors[i].description
|
||||||
) {
|
) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -217,6 +224,45 @@ function* removeCallArguments(ast: t.File): Generator<t.File> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generator that yields ASTs with function parameters removed one at a time
|
||||||
|
*/
|
||||||
|
function* removeFunctionParameters(ast: t.File): Generator<t.File> {
|
||||||
|
// Collect all functions with parameters
|
||||||
|
const funcSites: Array<{funcIndex: number; paramCount: number}> = [];
|
||||||
|
let funcIndex = 0;
|
||||||
|
t.traverseFast(ast, node => {
|
||||||
|
if (t.isFunction(node) && node.params.length > 0) {
|
||||||
|
funcSites.push({funcIndex, paramCount: node.params.length});
|
||||||
|
funcIndex++;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// For each function, try removing each parameter (from end to start)
|
||||||
|
for (const {funcIndex: targetFuncIdx, paramCount} of funcSites) {
|
||||||
|
for (let paramIdx = paramCount - 1; paramIdx >= 0; paramIdx--) {
|
||||||
|
const cloned = cloneAst(ast);
|
||||||
|
let idx = 0;
|
||||||
|
let modified = false;
|
||||||
|
|
||||||
|
t.traverseFast(cloned, node => {
|
||||||
|
if (modified) return;
|
||||||
|
if (t.isFunction(node) && node.params.length > 0) {
|
||||||
|
if (idx === targetFuncIdx && paramIdx < node.params.length) {
|
||||||
|
node.params.splice(paramIdx, 1);
|
||||||
|
modified = true;
|
||||||
|
}
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (modified) {
|
||||||
|
yield cloned;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generator that simplifies call expressions by replacing them with their arguments.
|
* Generator that simplifies call expressions by replacing them with their arguments.
|
||||||
* For single argument: foo(x) -> x
|
* For single argument: foo(x) -> x
|
||||||
@@ -1566,6 +1612,84 @@ function* removeObjectProperties(ast: t.File): Generator<t.File> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generator that removes elements from array destructuring patterns one at a time
|
||||||
|
*/
|
||||||
|
function* removeArrayPatternElements(ast: t.File): Generator<t.File> {
|
||||||
|
// Collect all array patterns with elements
|
||||||
|
const patternSites: Array<{patternIndex: number; elementCount: number}> = [];
|
||||||
|
let patternIndex = 0;
|
||||||
|
t.traverseFast(ast, node => {
|
||||||
|
if (t.isArrayPattern(node) && node.elements.length > 0) {
|
||||||
|
patternSites.push({patternIndex, elementCount: node.elements.length});
|
||||||
|
patternIndex++;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// For each pattern, try removing each element (from end to start)
|
||||||
|
for (const {patternIndex: targetPatternIdx, elementCount} of patternSites) {
|
||||||
|
for (let elemIdx = elementCount - 1; elemIdx >= 0; elemIdx--) {
|
||||||
|
const cloned = cloneAst(ast);
|
||||||
|
let idx = 0;
|
||||||
|
let modified = false;
|
||||||
|
|
||||||
|
t.traverseFast(cloned, node => {
|
||||||
|
if (modified) return;
|
||||||
|
if (t.isArrayPattern(node) && node.elements.length > 0) {
|
||||||
|
if (idx === targetPatternIdx && elemIdx < node.elements.length) {
|
||||||
|
node.elements.splice(elemIdx, 1);
|
||||||
|
modified = true;
|
||||||
|
}
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (modified) {
|
||||||
|
yield cloned;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generator that removes properties from object destructuring patterns one at a time
|
||||||
|
*/
|
||||||
|
function* removeObjectPatternProperties(ast: t.File): Generator<t.File> {
|
||||||
|
// Collect all object patterns with properties
|
||||||
|
const patternSites: Array<{patternIndex: number; propCount: number}> = [];
|
||||||
|
let patternIndex = 0;
|
||||||
|
t.traverseFast(ast, node => {
|
||||||
|
if (t.isObjectPattern(node) && node.properties.length > 0) {
|
||||||
|
patternSites.push({patternIndex, propCount: node.properties.length});
|
||||||
|
patternIndex++;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// For each pattern, try removing each property (from end to start)
|
||||||
|
for (const {patternIndex: targetPatternIdx, propCount} of patternSites) {
|
||||||
|
for (let propIdx = propCount - 1; propIdx >= 0; propIdx--) {
|
||||||
|
const cloned = cloneAst(ast);
|
||||||
|
let idx = 0;
|
||||||
|
let modified = false;
|
||||||
|
|
||||||
|
t.traverseFast(cloned, node => {
|
||||||
|
if (modified) return;
|
||||||
|
if (t.isObjectPattern(node) && node.properties.length > 0) {
|
||||||
|
if (idx === targetPatternIdx && propIdx < node.properties.length) {
|
||||||
|
node.properties.splice(propIdx, 1);
|
||||||
|
modified = true;
|
||||||
|
}
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (modified) {
|
||||||
|
yield cloned;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generator that simplifies assignment expressions (a = b) -> a or b
|
* Generator that simplifies assignment expressions (a = b) -> a or b
|
||||||
*/
|
*/
|
||||||
@@ -1852,8 +1976,14 @@ function* simplifyIdentifiersRenameRef(ast: t.File): Generator<t.File> {
|
|||||||
const simplificationStrategies = [
|
const simplificationStrategies = [
|
||||||
{name: 'removeStatements', generator: removeStatements},
|
{name: 'removeStatements', generator: removeStatements},
|
||||||
{name: 'removeCallArguments', generator: removeCallArguments},
|
{name: 'removeCallArguments', generator: removeCallArguments},
|
||||||
|
{name: 'removeFunctionParameters', generator: removeFunctionParameters},
|
||||||
{name: 'removeArrayElements', generator: removeArrayElements},
|
{name: 'removeArrayElements', generator: removeArrayElements},
|
||||||
{name: 'removeObjectProperties', generator: removeObjectProperties},
|
{name: 'removeObjectProperties', generator: removeObjectProperties},
|
||||||
|
{name: 'removeArrayPatternElements', generator: removeArrayPatternElements},
|
||||||
|
{
|
||||||
|
name: 'removeObjectPatternProperties',
|
||||||
|
generator: removeObjectPatternProperties,
|
||||||
|
},
|
||||||
{name: 'removeJSXAttributes', generator: removeJSXAttributes},
|
{name: 'removeJSXAttributes', generator: removeJSXAttributes},
|
||||||
{name: 'removeJSXChildren', generator: removeJSXChildren},
|
{name: 'removeJSXChildren', generator: removeJSXChildren},
|
||||||
{name: 'removeJSXFragmentChildren', generator: removeJSXFragmentChildren},
|
{name: 'removeJSXFragmentChildren', generator: removeJSXFragmentChildren},
|
||||||
|
|||||||
Reference in New Issue
Block a user