사용자 정의 ESLint 플러그인 작성 방법

최근까지 나는 아직 두 가지 기술을 이해하지 못했다.암호화 및 ESLint 플러그인.오늘 나는 마침내 ESLint 플러그인을 이해했다.
몇 달 동안, 나는 개발자의 체험을 어떻게 맞춤형으로 만드는지 보기 위해 맞춤형 ESLint 플러그인을 만들고 싶었다.이 플러그인을 배운 경험을 여러분과 공유하고 앞으로 어떻게 자신의 플러그인을 구축할 것인가에 대한 안내를 드리고 싶습니다.

배경.


나와 나의 팀은 줄곧 고객 프로젝트를 하고 있다. 몇 달 전에 우리는 몇 가지 TypeScript 코드 스타일 약속들을 설정했다. 우리는 이러한 약속들이 우리가 인터페이스, 유형과 스타일화된 구성 요소를 관리하는 데 도움을 줄 것이라고 생각한다.
  • 인터페이스는 문자I로 시작해야 합니다.
  • 유형은 문자T로 시작해야 합니다.
  • 스타일 구성 요소는 문자S로 시작해야 합니다.
  • 우리는 이것이 우리와 다른 개발자들이 전체 코드 라이브러리에서 유형을 사용할 때 유형이 무엇인지 정확하게 알 수 있도록 도와줄 것이라고 믿는다.이것은 하나의 일로 결정했다.유지 관리에는 두 가지 옵션이 있습니다.
  • 이 규칙을 기억해라. 우리가 오류를 보았을 때 코드 심사에서 수정한다
  • ESLint 규칙을 설정하여 자동으로 검사해 줍니다
  • 그래서 저는 이 기회를 빌려 맞춤형 ESLint 플러그인을 구축하고 저희 개발팀에 해결 방안을 제공하는 방법을 배웠습니다.

    나의 브리핑


    나의 생각은 매우 간단하다.TypeScript 인터페이스와 유형을 분석하고 대문자I 또는 대문자T로 시작해야 합니다.양식화된 구성 요소를 분석하고 대문자 S 로 시작해야 한다.그것은 오류를 발견할 때 사용자에게 경고해야 할 뿐만 아니라, 이러한 번거로운 작업을 복구하기 위해 코드 해결 방안도 제공해야 한다.

    ESLint+AST(추상 구문 트리)


    ESLint를 이해하기 위해서는 한 걸음 뒤로 물러나 ESLint의 작동 원리를 더 잘 알아야 합니다.가장 기본적인 것은 ESLint는 코드를 추상적인 문법 트리라고 부르는 것으로 해석해야 한다. 이것은 코드, 정의, 값의 표현 형식이다.컴파일러와 ESLint가 코드를 이해할 수 있는 블록으로 분해하는 방법에 대한 자세한 정보는 그 뒤에 있는 컴퓨터 과학 지식Twillio has a great guide을 참조하십시오.

    플러그인 구성


    간단하게 보기 위해, 본고는 TypeScript 인터페이스에 대한 ESLint 플러그인을 구축하는 방법을 소개할 것이다.

    1단계: 코드 이해


    우선 코드의 모든 인터페이스를 포획하고 이름 (또는 식별자) 을 찾는 방법을 찾아야 한다.이것은 인터페이스 이름이 대문자 I 로 시작하는 약속을 따르는지 확인하는 것을 허용할 것이다.
    추상적인 문법 트리를 시각화하기 위해AST 탐색기라는 도구를 사용할 수 있습니다.Here is an example link시작합니다.당신은 오른쪽에서 생성된AST를 보게 될 것입니다. 미친 것처럼 보이지만 실제로는 이해할 수 있습니다.오른쪽 트리 창에서 를 클릭하고 body 블록을 엽니다.

    기본적으로, 우리가 지금 파악하고 있는 것은 컴파일러가 당신이 작성한 코드를 어떻게 이해하는지에 관한 데이터입니다.다음과 같은 기능이 있습니다.
  • InterfaceDeclaration: 인터페이스 유형
  • Identifier: 인터페이스의 표지(이 예는 AppProps)
  • ObjectTypeAnnotation: 인터페이스 내용
  • 및 코드가 편집기에 있는 위치에 대한 더 많은 데이터
  • 이거 대박이다.이제 우리는 모든 인터페이스를 포획하고 그것들의 표지부 이름을 검사하는 방법을 이해할 수 있다.

    2단계: 전환 규칙 수립


    이제 우리는 해결 방안을 구축하기 시작할 수 있다.ESLint 플러그인을 고려할 때 두 부분으로 나눌 수 있습니다.'탐지기' 검사가 일치하고, '응답기' 가 오류/경고를 보내며, 코드 솔루션을 제공할 수 있습니다.AST explorer에는 '탐지기' 와 '응답기' 를 작성하고 ESLint에서 어떻게 사용하는지 볼 수 있는 편집기가 있습니다.
    먼저 페이지 상단의 메뉴에서 JavaScript 옆에 있는 버튼이 babel-eslint로 설정되어 있는지 확인합니다.그리고 '변환' 단추를 누르고 선택하십시오 ESLint v4.
    transform 창에서 예시 코드를 볼 수 있습니다.ESLint 변환의 작동 방식 대부분을 설명하려면 읽어야 합니다.
  • 규칙은 일련의 일치하는'탐지기'키를 가진 대상(이 예는TemplateLiteral)
  • 하나의 노드가 일치할 때 함수가 터치되고 메시지와 (선택 가능) 코드가 복원된 상하문 보고서를 되돌려줍니다.이것은 사용자에게 전송됩니다
  • .
    이러한 지식을 이용하여 우리는 우리의 플러그인을 위해 해결 방안을 구축할 수 있다.TemplateLiteral 인터페이스 형식 (InterfaceDeclaration 으로 바꾸면 오른쪽 컨트롤러에서 경고를 볼 수 있습니다.이것은 기초입니다. 지금 우리는 변압기 작업을 시범적으로 보여 줍니다.
    이제 우리는 진정한 해결 방안을 써야 한다.인터페이스 id의 첫 번째 문자가 자모 I인지 확인하기 위해 기본 논리를 추가합니다.
    export default function (context) {
      return {
        InterfaceDeclaration(node) {
          if (node.id.name[0] !== "I") {
            context.report({
              node,
              message: "Interfaces must start with a capital I",
            });
          }
        },
      };
    }
    
    우리는 여전히 잘못된 소식을 볼 수 있다.I 전에 알파벳AppProps을 붙이면 오류가 사라진다.위대했어이제 우리는 효과적인 규칙이 하나 생겼다.일이 예상대로 진행되었는지 확인하기 위해 유효하고 무효한 예를 들어 그것을 테스트한다.한 번에 하나의 예를 테스트하는 것이 더 쉬울 수 있습니다.
    interface Card {
      preview: boolean;
    }
    
    interface Card extends Props {
      preview: boolean;
    }
    
    우리는 이제 우리 팀과 개원 커뮤니티를 위해 플러그인을 구축하는 데 필요한 모든 것을 가지고 있다.

    3단계: 프로젝트 구축


    Yeoman ESLint Builderhttps://github.com/eslint/generator-eslint#readme를 사용하여 간편한 플러그인 패키지 구축
    패키지 설치:npm i -g generator-eslintCLI를 실행하고 지침을 따르십시오.yo eslint:pluginTypeScript 파서를 설치해야 합니다.npm i @typescript-eslint/parser --dev lib/rules 디렉토리에 interfaces.js라는 새 파일을 만들고 다음 템플릿 파일을 추가합니다.
    module.exports = {
      meta: {
        type: "suggestion",
        schema: [],
        docs: {
          description: "Enforcing the prefixing of interfaces",
        },
      },
      create: (context) => {
        return {
          TSInterfaceDeclaration(node) {
            if (node.id.name[0] !== "I") {
              context.report({
                node: node.id,
                message: "Interfaces must start with a capital I",
              });
            }
          },
        };
      },
    };
    
    주의해야 할 몇 가지 일:
  • 우리는 원 대상이 하나 있는데 그 중에서 규칙에 대한 세부 사항이 있어서 문서에 매우 유용하다
  • 우리는 InterfaceDeclaration'감청기'를 TSInterfaceDeclaration로 교체한다(아래 참조)
  • 우리는create 함수를 가지고 있는데 그 중에서 우리가 전에 제작한transformer
  • 를 포함한다.

    Why did I replace InterfaceDeclaration for TSInterfaceDeclaration?
    The babel-eslint plugin doesn’t parse TypeScript but does work in the AST explorer. Using the @typescript-eslint/parser ensures we are parsing correctly, and we will add that as our parser in the next steps. This took me 2 hours to debug when writing unit tests.


    마지막으로 단원 테스트를 추가합시다.tests/lib/rules 디렉토리에 interfaces.test.js라는 파일을 추가하고 다음 템플릿 파일을 추가합니다.
    const rule = require("../../../lib/rules/interfaces");
    
    const RuleTester = require("eslint").RuleTester;
    
    RuleTester.setDefaultConfig({
      parserOptions: { ecmaVersion: 6, sourceType: "module" },
      // eslint-disable-next-line node/no-unpublished-require
      parser: require.resolve("@typescript-eslint/parser"),
    });
    
    const tester = new RuleTester();
    
    tester.run("rule: interfaces", rule, {
      valid: ["interface IAnotherInterface { preview: boolean; }"],
      invalid: [
        {
          code: "interface AnotherInterface { preview: boolean; }",
          errors: [{ message: "Interfaces must start with a capital I" }],
          output: "interface IAnotherInterface { preview: boolean; }",
        },
      ],
    });
    
    
    이 중 대부분은 ESLint 팀이 권장하는 테스트 형식입니다.여기서 주요 섹션은 TypeScript 파서를 추가하고 선언할 유효한 테스트와 잘못된 테스트를 추가하는 것입니다.ESLint 문서에서 셀 테스트에 대한 자세한 내용을 읽을 수 있습니다.

    5단계: 코드 수정 추가


    얼마 안 남았어요.코드 복구를 추가하려면 내용에 복구 함수를 추가하십시오.보고서 객체:
    fix: (fixer) => {
        return [fixer.replaceText(node.id, "I" + node.id.name)];
    },
    
    마지막으로, 컴파일 단위 테스트를 확보하고 출력을 단언합니다.
    {
      code: "interface CustomProps extends AppProps { preview: boolean; }",
      errors: [{ message: "Interfaces must start with a capital I" }],
      output: "interface ICustomProps extends AppProps { preview: boolean; }",
    },
    
    이렇게현재, 플러그인을 npm로 전송하거나 로컬 프로젝트에 추가할 수 있습니다.

    다음 단계


    만약 관심이 있다면, 키워드가 자모 I 로 시작된 인터페이스를 어떻게 포착하는지 연구해야 합니다. 예를 들어 InfoBoxProps.이 플러그인은 infobox 이나 idProps 같은 이상한 인터페이스 이름이 있는 가장자리 상황을 더 잘 지원해야 한다. 왜냐하면 우리의 일치로 현재 이 이름을 포착할 수 없기 때문이다.

    Wait, why isn’t the plugin written in TypeScript too
    Good question. It can be, but to keep things simple I opted to just build it in vanilla JS. If I’m adding a lot more rules or working on this project with others, then switching to a TypeScript toolchain would be a great idea


    이것은 아마도 내가 네 번째로 ESLint 플러그인을 구축하려고 시도한 것일 것이다.연구를 진행할 때, 나는 API 문서와 다른 사람들이 작성한 대부분의 안내서와 강좌가 가장 간단한 플러그인 아이디어라도 읽고 이해하기 어렵다는 것을 발견했다.이 안내서가 당신의 시작을 도울 수 있기를 바랍니다.
    너는 나의 리포와 나의 인터페이스 예시, 그리고 내가 여기서 만든 다른 두 가지 (하나는 유형에 사용되고, 하나는 스타일화된 구성 요소에 사용된다) 를 볼 수 있다.

    콰이밍 / eslint 플러그인 접두사 유형


    인터페이스, 유형 및 스타일 지정 구성 요소의 접두어를 강제로 적용하는 ESLint 플러그인


    !

    좋은 웹페이지 즐겨찾기