main
ts 147 lines 4.22 KB
Raw
1 /**
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 */
7
8 import {RuleTester} from 'eslint';
9 import {allRules} from '../src/shared/ReactCompiler';
10
11 const ESLintTesterV8 = require('eslint-v8').RuleTester;
12
13 /**
14 * A string template tag that removes padding from the left side of multi-line strings
15 * @param {Array} strings array of code strings (only one expected)
16 */
17 function normalizeIndent(strings: TemplateStringsArray): string {
18 const codeLines = strings[0]?.split('\n') ?? [];
19 const leftPadding = codeLines[1]?.match(/\s+/)![0] ?? '';
20 return codeLines.map(line => line.slice(leftPadding.length)).join('\n');
21 }
22
23 type CompilerTestCases = {
24 valid: RuleTester.ValidTestCase[];
25 invalid: RuleTester.InvalidTestCase[];
26 };
27
28 const tests: CompilerTestCases = {
29 valid: [
30 // ===========================================
31 // Tests for mayContainReactCode heuristic with Flow syntax
32 // Files that should be SKIPPED (no React-like function names)
33 // These contain code that WOULD trigger errors if compiled,
34 // but since the heuristic skips them, no errors are reported.
35 // ===========================================
36 {
37 name: '[Heuristic/Flow] Skips files with only lowercase utility functions',
38 filename: 'utils.js',
39 code: normalizeIndent`
40 function helper(obj) {
41 obj.key = 'value';
42 return obj;
43 }
44 `,
45 },
46 {
47 name: '[Heuristic/Flow] Skips lowercase arrow functions even with mutations',
48 filename: 'helpers.js',
49 code: normalizeIndent`
50 const processData = (input) => {
51 input.modified = true;
52 return input;
53 };
54 `,
55 },
56 ],
57 invalid: [
58 // ===========================================
59 // Tests for mayContainReactCode heuristic with Flow component/hook syntax
60 // These use Flow's component/hook declarations which should be detected
61 // ===========================================
62 {
63 name: '[Heuristic/Flow] Compiles Flow component declaration - detects prop mutation',
64 filename: 'component.js',
65 code: normalizeIndent`
66 component MyComponent(a: {key: string}) {
67 a.key = 'value';
68 return <div />;
69 }
70 `,
71 errors: [
72 {
73 message: /Modifying component props/,
74 },
75 ],
76 },
77 {
78 name: '[Heuristic/Flow] Compiles exported Flow component declaration - detects prop mutation',
79 filename: 'component.js',
80 code: normalizeIndent`
81 export component MyComponent(a: {key: string}) {
82 a.key = 'value';
83 return <div />;
84 }
85 `,
86 errors: [
87 {
88 message: /Modifying component props/,
89 },
90 ],
91 },
92 {
93 name: '[Heuristic/Flow] Compiles default exported Flow component declaration - detects prop mutation',
94 filename: 'component.js',
95 code: normalizeIndent`
96 export default component MyComponent(a: {key: string}) {
97 a.key = 'value';
98 return <div />;
99 }
100 `,
101 errors: [
102 {
103 message: /Modifying component props/,
104 },
105 ],
106 },
107 {
108 name: '[Heuristic/Flow] Compiles Flow hook declaration - detects argument mutation',
109 filename: 'hooks.js',
110 code: normalizeIndent`
111 hook useMyHook(a: {key: string}) {
112 a.key = 'value';
113 return a;
114 }
115 `,
116 errors: [
117 {
118 message: /Modifying component props or hook arguments/,
119 },
120 ],
121 },
122 {
123 name: '[Heuristic/Flow] Compiles exported Flow hook declaration - detects argument mutation',
124 filename: 'hooks.js',
125 code: normalizeIndent`
126 export hook useMyHook(a: {key: string}) {
127 a.key = 'value';
128 return a;
129 }
130 `,
131 errors: [
132 {
133 message: /Modifying component props or hook arguments/,
134 },
135 ],
136 },
137 ],
138 };
139
140 const eslintTester = new ESLintTesterV8({
141 parser: require.resolve('hermes-eslint'),
142 parserOptions: {
143 sourceType: 'module',
144 enableExperimentalComponentSyntax: true,
145 },
146 });
147 eslintTester.run('react-compiler', allRules['immutability'].rule, tests);