brandongregoryscott / eslint-plugin-collation

ESLint plugin for making your code easier to read, with autofix and TypeScript support
https://eslint-plugin-collation.brandonscott.me
Apache License 2.0
4 stars 0 forks source link

Rule: `main-comp-first` #56

Open brandongregoryscott opened 2 years ago

brandongregoryscott commented 2 years ago

Implement a new rule with restrictions on multiple components in a file.

Multiple components are allowed per file if the primary component appears first

  1. A Component is defined as:

    1. A VariableDeclaration, FunctionDeclaration OR a ClassDeclaration that contains JSXElement children in a return statement
  2. The Primary Component is defined as (in priority order):

    1. The default export
    2. The VariableDeclaration, FunctionDeclaration or ClassDeclaration that matches the filename (i.e. const App might be app.tsx)
    3. The VariableDeclaration, FunctionDeclaration or ClassDeclaration that matches the parent directory name if the filename is index.tsx
    4. The named, exported component (if multiple exist, the first one that appears in the file should be the primary component)

These cases would be valid:

const App = () => {
    return <div />;
};
// app.tsx
const App = () => {
    return <Row />;
}

const Row = () => {
    return <div />;
}
// app/index.tsx
const App = () => {
    return <Row />;
}

const Row = () => {
    return <div />;
}
const App = () => {
    return <Row />;
}

const Row = () => {
    return <div />;
}

export default App;
export const App = () => {
    return <Row />;
}

const Row = () => {
    return <div />;
}

These cases would be invalid:

Component appears before primary component based on filename

// app.tsx
const Row = () => {
    return <div />;
}

const App = () => {
    return <Row />;
}

Component appears before primary component based on directory structure

// app/index.tsx
const Row = () => {
    return <div />;
}

const App = () => {
    return <Row />;
}

Component appears before exported component

const Row = () => {
    return <div />;
}

const App = () => {
    return <Row />;
}

export default App;

Component appears before exported component

const Row = () => {
    return <div />;
}

const App = () => {
    return <Row />;
}

export { App };

Component appears before exported component

const Row = () => {
    return <div />;
}

export const App = () => {
    return <Row />;
}

Autofix behavior Still need to figure out if it's possible to extract out a node into a new file via ESLint, or if that would be too heavy-handed.

brandongregoryscott commented 2 years ago

According to the ESLint Architecture documentation, accessing the file-system is frowned upon. For the basic rule (i.e. restricting 1 file <> 1 component), I'm not sure what else an autofix could do, and this would be equivalent to react/no-multi-comp.

For the variation of the rule that enforces the primary component appears before any other components, we could still provide an autofix that would move that node after the primary component. Some of that logic is in progress in this branch: https://github.com/brandongregoryscott/eslint-plugin-collation/tree/rule-multi-comp but I think I'd like to rename the rule and focus it more toward that behavior, if moving forward with it