Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions compiler/apps/playground/components/AccordionWindow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

import {Resizable} from 're-resizable';
import React, {
useCallback,
useId,
unstable_ViewTransition as ViewTransition,
unstable_addTransitionType as addTransitionType,
Expand Down Expand Up @@ -66,7 +65,7 @@ function AccordionWindowItem({

const transitionName = `accordion-window-item-${id}`;

const toggleTabs = () => {
const toggleTabs = (): void => {
startTransition(() => {
addTransitionType(EXPAND_ACCORDION_TRANSITION);
const nextState = new Set(tabsOpen);
Expand Down
6 changes: 1 addition & 5 deletions compiler/apps/playground/components/Editor/EditorImpl.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,7 @@ import BabelPluginReactCompiler, {
printFunctionWithOutlined,
type LoggerEvent,
} from 'babel-plugin-react-compiler';
import {
useDeferredValue,
useMemo,
unstable_ViewTransition as ViewTransition,
} from 'react';
import {useDeferredValue, useMemo} from 'react';
import {useStore} from '../StoreContext';
import ConfigEditor from './ConfigEditor';
import Input from './Input';
Expand Down
10 changes: 8 additions & 2 deletions compiler/apps/playground/components/Editor/Output.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -372,12 +372,18 @@ function TextTabContent({
loading={''}
options={{
...monacoOptions,
scrollbar: {
vertical: 'hidden',
},
dimension: {
width: 0,
height: 0,
},
readOnly: true,
lineNumbers: 'off',
glyphMargin: false,
// Undocumented see https://github.com/Microsoft/vscode/issues/30795#issuecomment-410998882
lineDecorationsWidth: 0,
lineNumbersMinChars: 0,
overviewRulerLanes: 0,
}}
/>
) : (
Expand Down
8 changes: 8 additions & 0 deletions compiler/apps/playground/styles/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -124,3 +124,11 @@
::view-transition-group(.expand-accordion) {
overflow: clip;
}

/**
* For some reason, the original Monaco editor is still visible to the
* left of the DiffEditor. This is a workaround for better visual clarity.
*/
.monaco-diff-editor .editor.original{
visibility: hidden !important;
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -161,69 +161,21 @@ function makeRule(rule: LintRule): Rule.RuleModule {
};
}

export const NoUnusedDirectivesRule: Rule.RuleModule = {
meta: {
type: 'suggestion',
docs: {
recommended: true,
},
fixable: 'code',
hasSuggestions: true,
// validation is done at runtime with zod
schema: [{type: 'object', additionalProperties: true}],
},
create(context: Rule.RuleContext): Rule.RuleListener {
const results = getReactCompilerResult(context);

for (const directive of results.unusedOptOutDirectives) {
context.report({
message: `Unused '${directive.directive}' directive`,
loc: directive.loc,
suggest: [
{
desc: 'Remove the directive',
fix(fixer): Rule.Fix {
return fixer.removeRange(directive.range);
},
},
],
});
}
return {};
},
};

type RulesConfig = {
[name: string]: {rule: Rule.RuleModule; severity: ErrorSeverity};
};

export const allRules: RulesConfig = LintRules.reduce(
(acc, rule) => {
acc[rule.name] = {rule: makeRule(rule), severity: rule.severity};
return acc;
},
{
'no-unused-directives': {
rule: NoUnusedDirectivesRule,
severity: ErrorSeverity.Error,
},
} as RulesConfig,
);
export const allRules: RulesConfig = LintRules.reduce((acc, rule) => {
acc[rule.name] = {rule: makeRule(rule), severity: rule.severity};
return acc;
}, {} as RulesConfig);

export const recommendedRules: RulesConfig = LintRules.filter(
rule => rule.recommended,
).reduce(
(acc, rule) => {
acc[rule.name] = {rule: makeRule(rule), severity: rule.severity};
return acc;
},
{
'no-unused-directives': {
rule: NoUnusedDirectivesRule,
severity: ErrorSeverity.Error,
},
} as RulesConfig,
);
).reduce((acc, rule) => {
acc[rule.name] = {rule: makeRule(rule), severity: rule.severity};
return acc;
}, {} as RulesConfig);

export function mapErrorSeverityToESlint(
severity: ErrorSeverity,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,18 @@
* LICENSE file in the root directory of this source tree.
*/

import {transformFromAstSync, traverse} from '@babel/core';
import {transformFromAstSync} from '@babel/core';
import {parse as babelParse} from '@babel/parser';
import {Directive, File} from '@babel/types';
import {File} from '@babel/types';
// @ts-expect-error: no types available
import PluginProposalPrivateMethods from '@babel/plugin-proposal-private-methods';
import BabelPluginReactCompiler, {
parsePluginOptions,
validateEnvironmentConfig,
OPT_OUT_DIRECTIVES,
type PluginOptions,
} from 'babel-plugin-react-compiler/src';
import {Logger, LoggerEvent} from 'babel-plugin-react-compiler/src/Entrypoint';
import type {SourceCode} from 'eslint';
import {SourceLocation} from 'estree';
// @ts-expect-error: no types available
import * as HermesParser from 'hermes-parser';
import {isDeepStrictEqual} from 'util';
Expand All @@ -45,17 +43,11 @@ const COMPILER_OPTIONS: PluginOptions = {
}),
};

export type UnusedOptOutDirective = {
loc: SourceLocation;
range: [number, number];
directive: string;
};
export type RunCacheEntry = {
sourceCode: string;
filename: string;
userOpts: PluginOptions;
flowSuppressions: Array<{line: number; code: string}>;
unusedOptOutDirectives: Array<UnusedOptOutDirective>;
events: Array<LoggerEvent>;
};

Expand Down Expand Up @@ -87,25 +79,6 @@ function getFlowSuppressions(
return results;
}

function filterUnusedOptOutDirectives(
directives: ReadonlyArray<Directive>,
): Array<UnusedOptOutDirective> {
const results: Array<UnusedOptOutDirective> = [];
for (const directive of directives) {
if (
OPT_OUT_DIRECTIVES.has(directive.value.value) &&
directive.loc != null
) {
results.push({
loc: directive.loc,
directive: directive.value.value,
range: [directive.start!, directive.end!],
});
}
}
return results;
}

function runReactCompilerImpl({
sourceCode,
filename,
Expand All @@ -125,7 +98,6 @@ function runReactCompilerImpl({
filename,
userOpts,
flowSuppressions: [],
unusedOptOutDirectives: [],
events: [],
};
const userLogger: Logger | null = options.logger;
Expand Down Expand Up @@ -181,29 +153,6 @@ function runReactCompilerImpl({
configFile: false,
babelrc: false,
});

if (results.events.filter(e => e.kind === 'CompileError').length === 0) {
traverse(babelAST, {
FunctionDeclaration(path) {
path.node;
results.unusedOptOutDirectives.push(
...filterUnusedOptOutDirectives(path.node.body.directives),
);
},
ArrowFunctionExpression(path) {
if (path.node.body.type === 'BlockStatement') {
results.unusedOptOutDirectives.push(
...filterUnusedOptOutDirectives(path.node.body.directives),
);
}
},
FunctionExpression(path) {
results.unusedOptOutDirectives.push(
...filterUnusedOptOutDirectives(path.node.body.directives),
);
},
});
}
} catch (err) {
/* errors handled by injected logger */
}
Expand Down
5 changes: 1 addition & 4 deletions fixtures/eslint-v6/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
{
"root": true,
"extends": ["plugin:react-hooks/recommended-legacy"],
"extends": ["plugin:react-hooks/recommended-latest-legacy"],
"parserOptions": {
"ecmaVersion": 2020,
"sourceType": "module",
"ecmaFeatures": {
"jsx": true
}
},
"rules": {
"react-hooks/exhaustive-deps": "error"
}
}
24 changes: 24 additions & 0 deletions fixtures/eslint-v6/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -141,3 +141,27 @@ function useHookInLoops() {
useHook4();
}
}

/**
* Compiler Rules
*/
// Invalid: component factory
function InvalidComponentFactory() {
const DynamicComponent = () => <div>Hello</div>;
// eslint-disable-next-line react-hooks/static-components
return <DynamicComponent />;
}

// Invalid: mutating globals
function InvalidGlobals() {
// eslint-disable-next-line react-hooks/immutability
window.myGlobal = 42;
return <div>Done</div>;
}

// Invalid: useMemo with wrong deps - triggers preserve-manual-memoization
function InvalidUseMemo({items}) {
// eslint-disable-next-line react-hooks/preserve-manual-memoization, react-hooks/exhaustive-deps
const sorted = useMemo(() => [...items].sort(), []);
return <div>{sorted.length}</div>;
}
Loading
Loading