import {RuleTester} from 'eslint';
import {allRules} from '../src/shared/ReactCompiler';
const ESLintTesterV8 = require('eslint-v8').RuleTester;
function normalizeIndent(strings: TemplateStringsArray): string {
const codeLines = strings[0]?.split('\n') ?? [];
const leftPadding = codeLines[1]?.match(/\s+/)![0] ?? '';
return codeLines.map(line => line.slice(leftPadding.length)).join('\n');
}
type CompilerTestCases = {
valid: RuleTester.ValidTestCase[];
invalid: RuleTester.InvalidTestCase[];
};
const tests: CompilerTestCases = {
valid: [
{
name: '[Heuristic/Flow] Skips files with only lowercase utility functions',
filename: 'utils.js',
code: normalizeIndent`
function helper(obj) {
obj.key = 'value';
return obj;
}
`,
},
{
name: '[Heuristic/Flow] Skips lowercase arrow functions even with mutations',
filename: 'helpers.js',
code: normalizeIndent`
const processData = (input) => {
input.modified = true;
return input;
};
`,
},
],
invalid: [
{
name: '[Heuristic/Flow] Compiles Flow component declaration - detects prop mutation',
filename: 'component.js',
code: normalizeIndent`
component MyComponent(a: {key: string}) {
a.key = 'value';
return <div />;
}
`,
errors: [
{
message: /Modifying component props/,
},
],
},
{
name: '[Heuristic/Flow] Compiles exported Flow component declaration - detects prop mutation',
filename: 'component.js',
code: normalizeIndent`
export component MyComponent(a: {key: string}) {
a.key = 'value';
return <div />;
}
`,
errors: [
{
message: /Modifying component props/,
},
],
},
{
name: '[Heuristic/Flow] Compiles default exported Flow component declaration - detects prop mutation',
filename: 'component.js',
code: normalizeIndent`
export default component MyComponent(a: {key: string}) {
a.key = 'value';
return <div />;
}
`,
errors: [
{
message: /Modifying component props/,
},
],
},
{
name: '[Heuristic/Flow] Compiles Flow hook declaration - detects argument mutation',
filename: 'hooks.js',
code: normalizeIndent`
hook useMyHook(a: {key: string}) {
a.key = 'value';
return a;
}
`,
errors: [
{
message: /Modifying component props or hook arguments/,
},
],
},
{
name: '[Heuristic/Flow] Compiles exported Flow hook declaration - detects argument mutation',
filename: 'hooks.js',
code: normalizeIndent`
export hook useMyHook(a: {key: string}) {
a.key = 'value';
return a;
}
`,
errors: [
{
message: /Modifying component props or hook arguments/,
},
],
},
],
};
const eslintTester = new ESLintTesterV8({
parser: require.resolve('hermes-eslint'),
parserOptions: {
sourceType: 'module',
enableExperimentalComponentSyntax: true,
},
});
eslintTester.run('react-compiler', allRules['immutability'].rule, tests);