Skip to content
This repository has been archived by the owner on Oct 9, 2024. It is now read-only.

Commit

Permalink
chore: Add lint rule for type imports
Browse files Browse the repository at this point in the history
  • Loading branch information
mohebifar committed Mar 3, 2024
1 parent 1437e50 commit 7f5cb0e
Show file tree
Hide file tree
Showing 23 changed files with 91 additions and 58 deletions.
7 changes: 7 additions & 0 deletions packages/babel-plugin/.eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,12 @@ module.exports = {
project: true,
tsConfigRootDir: __dirname,
},
settings: {
"import/resolver": {
typescript: {
project: __dirname,
},
},
},
ignorePatterns: ["src/tests/fixtures/**/*.tsx"],
};
2 changes: 1 addition & 1 deletion packages/babel-plugin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
"dev": "yarn build --watch",
"build": "tsup",
"test": "jest",
"lint": "eslint src/**/*.{ts,tsx} --max-warnings 15"
"lint": "eslint src/ --max-warnings 15"
},
"devDependencies": {
"@babel/plugin-syntax-jsx": "^7.23.3",
Expand Down
5 changes: 2 additions & 3 deletions packages/babel-plugin/src/classes/Component.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type * as babel from "@babel/core";
import { Binding } from "@babel/traverse";
import type { Binding } from "@babel/traverse";
import * as t from "@babel/types";
import {
DEFAULT_CACHE_COMMIT_VARIABLE_NAME,
Expand All @@ -10,8 +10,7 @@ import {
import { isControlFlowStatement } from "~/utils/path-tools/control-flow-utils";
import { isInTheSameFunctionScope } from "~/utils/path-tools/is-in-the-same-function-scope";
import { isChildOfScope } from "~/utils/scope-tools/is-scope-descendant-of";
import { getFunctionParent } from "~/utils/path-tools/get-function-parent";
import { ComponentMutableSegment } from "./ComponentMutableSegment";
import type { ComponentMutableSegment } from "./ComponentMutableSegment";
import { ComponentRunnableSegment } from "./ComponentRunnableSegment";
import { ComponentVariable } from "./ComponentVariable";

Expand Down
9 changes: 7 additions & 2 deletions packages/babel-plugin/src/classes/ComponentMutableSegment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import * as t from "@babel/types";
import { makeDependencyCondition } from "~/utils/ast-factories/make-dependency-condition";
import { DEFAULT_SEGMENT_CALLABLE_VARIABLE_NAME } from "~/utils/constants";
import { hasHookCall } from "~/utils/path-tools/has-hook-call";
import { Component } from "./Component";
import { isAccessorNode } from "~/utils/ast-tools/is-accessor-node";
import type { Component } from "./Component";
import type { ComponentRunnableSegment } from "./ComponentRunnableSegment";
import { ComponentSegmentDependency } from "./ComponentSegmentDependency";
import type { ComponentVariable } from "./ComponentVariable";
Expand Down Expand Up @@ -79,9 +80,13 @@ export abstract class ComponentMutableSegment {
return;
}

if (!isAccessorNode(accessorNode)) {
return;
}

const componentSegmentDependency = new ComponentSegmentDependency(
componentVariable,
accessorNode as any
accessorNode
);

let alreadyHasDependency = false;
Expand Down
13 changes: 7 additions & 6 deletions packages/babel-plugin/src/classes/ComponentRunnableSegment.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as babel from "@babel/core";
import type * as babel from "@babel/core";
import * as t from "@babel/types";
import { convertStatementToSegmentCallable } from "~/utils/micro-transformers/convert-statement-to-segment-callable";
import { convertDeclarationToAssignments } from "~/utils/micro-transformers/convert-declaration-to-assignments";
Expand All @@ -11,13 +11,14 @@ import { getReferencedVariablesInside } from "~/utils/path-tools/get-referenced-
import { reorderByTopology } from "~/utils/path-tools/reorder-by-topology";
import { unwrapJsxElements } from "~/utils/micro-transformers/unwrap-jsx-elements";
import { unwrapJsxExpressions } from "~/utils/micro-transformers/unwrap-jsx-expressions";
import { Component } from "./Component";
import type { Component } from "./Component";
import type {
SegmentTransformationResult} from "./ComponentMutableSegment";
import {
ComponentMutableSegment,
SegmentTransformationResult,
ComponentMutableSegment
} from "./ComponentMutableSegment";
import { ComponentSegmentDependency } from "./ComponentSegmentDependency";
import { ComponentVariable } from "./ComponentVariable";
import type { ComponentSegmentDependency } from "./ComponentSegmentDependency";
import type { ComponentVariable } from "./ComponentVariable";

export class ComponentRunnableSegment extends ComponentMutableSegment {
private blockReturnStatement: babel.NodePath<babel.types.ReturnStatement> | null =
Expand Down
22 changes: 6 additions & 16 deletions packages/babel-plugin/src/classes/ComponentSegmentDependency.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import * as t from "@babel/types";
import { ComponentVariable } from "./ComponentVariable";

type AccessorNode =
| t.MemberExpression
| t.OptionalMemberExpression
| t.Identifier
| t.PrivateName;
import type { AccessorNode } from "~/utils/ast-tools/is-accessor-node";
import { isAccessorNode } from "~/utils/ast-tools/is-accessor-node";
import type { ComponentVariable } from "./ComponentVariable";

/**
* A singly linked list of member expressions
*/
export class AccessChainItem {
public nextComputed = false;
public right?: AccessChainItem = undefined;
Expand All @@ -27,15 +26,6 @@ export class AccessChainItem {
}
}

function isAccessorNode(node: t.Node): node is AccessorNode {
return (
t.isMemberExpression(node) ||
t.isOptionalMemberExpression(node) ||
t.isIdentifier(node) ||
t.isPrivateName(node)
);
}

// When the variable is used in a member expression, we should optimize comparisons to the last member of member expression as well
export class ComponentSegmentDependency {
private root: AccessChainItem;
Expand Down
15 changes: 8 additions & 7 deletions packages/babel-plugin/src/classes/ComponentVariable.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type * as babel from "@babel/core";
import { Binding } from "@babel/traverse";
import type { Binding } from "@babel/traverse";
import * as t from "@babel/types";
import { convertStatementToSegmentCallable } from "~/utils/micro-transformers/convert-statement-to-segment-callable";
import { makeCacheEnqueueCallStatement } from "~/utils/ast-factories/make-cache-enqueue-call-statement";
Expand All @@ -12,16 +12,17 @@ import {
} from "~/utils/constants";
import { findMutatingExpression } from "~/utils/path-tools/find-mutating-expression";
import { getReferencedVariablesInside } from "~/utils/path-tools/get-referenced-variables-inside";
import { UnwrappedAssignmentEntry } from "~/utils/micro-transformers/unwrap-pattern-assignment";
import type { UnwrappedAssignmentEntry } from "~/utils/micro-transformers/unwrap-pattern-assignment";
import { isForStatementInit } from "~/utils/path-tools/control-flow-utils";
import { getDeclaredIdentifiersInLVal } from "../utils/path-tools/get-declared-identifiers-in-lval";
import { Component } from "./Component";
import type { Component } from "./Component";
import type {
SegmentTransformationResult} from "./ComponentMutableSegment";
import {
ComponentMutableSegment,
SegmentTransformationResult,
ComponentMutableSegment
} from "./ComponentMutableSegment";
import type { ComponentRunnableSegment } from "./ComponentRunnableSegment";
import { ComponentSegmentDependency } from "./ComponentSegmentDependency";
import { isForStatementInit } from "~/utils/path-tools/control-flow-utils";
import type { ComponentSegmentDependency } from "./ComponentSegmentDependency";

export class ComponentVariable extends ComponentMutableSegment {
private runnableSegmentsMutatingThis = new Set<ComponentMutableSegment>();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as t from "@babel/types";
import { ComponentMutableSegment } from "~/classes/ComponentMutableSegment";
import type { ComponentMutableSegment } from "~/classes/ComponentMutableSegment";

export function makeDependencyCondition(
mutableSegment: ComponentMutableSegment
Expand Down
16 changes: 16 additions & 0 deletions packages/babel-plugin/src/utils/ast-tools/is-accessor-node.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import * as t from "@babel/types";

export type AccessorNode =
| t.MemberExpression
| t.OptionalMemberExpression
| t.Identifier
| t.PrivateName;

export function isAccessorNode(node: t.Node): node is AccessorNode {
return (
t.isMemberExpression(node) ||
t.isOptionalMemberExpression(node) ||
t.isIdentifier(node) ||
t.isPrivateName(node)
);
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as t from "@babel/types";
import type * as t from "@babel/types";

export class RightmostIdNotFound extends Error {
constructor(path: t.Node) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as babel from "@babel/core";
import type * as babel from "@babel/core";
import * as t from "@babel/types";

export function unwrapGenericExpression(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as babel from "@babel/core";
import type * as babel from "@babel/core";
import * as t from "@babel/types";
import { Component } from "~/classes/Component";
import type { Component } from "~/classes/Component";
import { DEFAULT_UNWRAPPED_JSX_ELEMENT_VARIABLE_NAME } from "../constants";
import { getParentBlockStatement } from "../path-tools/get-parent-block-statement";
import { isInTheSameFunctionScope } from "../path-tools/is-in-the-same-function-scope";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as babel from "@babel/core";
import type * as babel from "@babel/core";
import * as t from "@babel/types";
import { Component } from "~/classes/Component";
import type { Component } from "~/classes/Component";
import { DEFAULT_UNWRAPPED_JSX_EXPRESSION_VARIABLE_NAME } from "../constants";
import { getParentBlockStatement } from "../path-tools/get-parent-block-statement";
import { isInTheSameFunctionScope } from "../path-tools/is-in-the-same-function-scope";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import type * as babel from "@babel/core";
import * as t from "@babel/types";
import { Component } from "../../classes/Component";
import { getReturnsOfFunction } from "./get-returns-of-function";
import { doesMatchHookName } from "../ast-tools/is-hook-call";
import { expandArrowFunctionToBlockStatement } from "../expand-arrow-function-to-block-statement";
import { getReturnsOfFunction } from "./get-returns-of-function";

export function findComponents(program: babel.NodePath<babel.types.Program>) {
const components: Component[] = [];
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { MUTATING_METHODS } from "../constants";
import { getDeclaredIdentifiersInLVal } from "./get-declared-identifiers-in-lval";
import { getLeftmostIdName } from "../ast-tools/get-leftmost-id-name";
import { getRightmostIdName } from "../ast-tools/get-rightmost-id-name";
import { getDeclaredIdentifiersInLVal } from "./get-declared-identifiers-in-lval";

export function findMutatingExpression(
path: babel.NodePath<babel.types.Node>,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as babel from "@babel/core";
import type * as babel from "@babel/core";
import * as t from "@babel/types";
import { Scope } from "@babel/traverse";
import type { Scope } from "@babel/traverse";

// We need this to properly detect if return statements belong to the same function
export function isInTheSameFunctionScope(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ComponentMutableSegment } from "~/classes/ComponentMutableSegment";
import type { ComponentMutableSegment } from "~/classes/ComponentMutableSegment";
import { CircularDependencyError } from "../errors/CircularDependencyError";

type StatementPath = babel.NodePath<babel.types.Statement>;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as babel from "@babel/core";
import type * as babel from "@babel/core";
import { isInTheSameFunctionScope } from "../is-in-the-same-function-scope";
import { parse } from "../../testing";

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Scope } from "@babel/traverse";
import type { Scope } from "@babel/traverse";

export function isChildOfScope(parent: Scope, child: Scope) {
let currentScope = child;
Expand Down
4 changes: 2 additions & 2 deletions packages/babel-plugin/src/utils/testing.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import * as fs from "fs";
import * as path from "path";
import * as babel from "@babel/core";
import * as generateBase from "@babel/generator";
import traverse from "@babel/traverse";
import type * as t from "@babel/types";
import * as fs from "fs";
import * as path from "path";
import { visitProgram } from "~/visit-program";
import babelPlugin from "../main";

Expand Down
25 changes: 19 additions & 6 deletions packages/eslint-config/library.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,7 @@ const project = resolve(process.cwd(), "tsconfig.json");

/** @type {import("eslint").Linter.Config} */
module.exports = {
extends: [
"plugin:@typescript-eslint/recommended",
"prettier",
"eslint-config-turbo",
],
plugins: ["only-warn"],
extends: ["prettier", "eslint-config-turbo"],
globals: {
React: true,
JSX: true,
Expand All @@ -34,6 +29,24 @@ module.exports = {
overrides: [
{
files: ["*.js?(x)", "*.ts?(x)"],
extends: [
"plugin:@typescript-eslint/recommended",
"plugin:import/recommended",
],
rules: {
"@typescript-eslint/consistent-type-imports": "error",
"import/order": [
"error",
{
pathGroups: [
{
pattern: "~/**",
group: "external",
},
],
},
],
},
},
{
files: ["**/tests/**/*"],
Expand Down
1 change: 1 addition & 0 deletions packages/eslint-config/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"@vercel/style-guide": "^5.1.0",
"eslint-config-prettier": "^9.1.0",
"eslint-config-turbo": "^1.11.3",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-only-warn": "^1.1.0",
"typescript": "^5.3.3"
}
Expand Down
2 changes: 1 addition & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4747,7 +4747,7 @@ eslint-plugin-eslint-comments@^3.2.0:
escape-string-regexp "^1.0.5"
ignore "^5.0.5"

eslint-plugin-import@^2.28.1:
eslint-plugin-import@^2.28.1, eslint-plugin-import@^2.29.1:
version "2.29.1"
resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz#d45b37b5ef5901d639c15270d74d46d161150643"
integrity sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==
Expand Down

0 comments on commit 7f5cb0e

Please sign in to comment.