진단 TypeScript 언어 서비스 플러그인은 어떻게 작성합니까?
TypeScript 언어 서비스 플러그인을 사용하여 TypeScript 사용자의 편집 환경을 변경할 수 있습니다.그것은 컴파일러를 방해하지 않을 것이다.강제 집행이 아니라 지도나 도움을 줄 수밖에 없다는 뜻이다.본고는 저희Todo Or Die use case를 예로 삼아 진단 플러그인을 만드는 방법을 소개합니다.
코드 때문에?이것 좀 보세요repository.
설치 프로그램
우선 공장 함수와 장식기가 있는 간단한 TypeScript 프로젝트가 필요합니다. 공장 함수로 돌아가야 합니다.
TypeScript wikiSetup and Initialization의 단계Decorator Creation와 Writing a Language Service Plugin article를 따릅니다.
다음 코드가 제공됩니다.
function init(modules: { typescript: typeof import("typescript/lib/tsserverlibrary") }) {
const ts = modules.typescript;
function create(info: ts.server.PluginCreateInfo) {
const proxy: ts.LanguageService = Object.create(null);
for (let k of Object.keys(info.languageService) as Array<keyof ts.LanguageService>) {
const x = info.languageService[k]!;
// @ts-expect-error - JS runtime trickery which is tricky to type tersely
proxy[k] = (...args: Array<{}>) => x.apply(info.languageService, args);
}
return proxy;
}
return { create };
}
export = init;
이것은 현재 전달 플러그인일 뿐이지만, 평론에 사용자 정의 행동을 추가할 수 있습니다.습관적 행위
이 장식기를 설정하면 TypeScript의 언어 서비스 기능을 덮어쓸 수 있습니다.진단 서비스 유형을 변경하려면 스크립트에서 세 가지 진단 유형을 정의합니다.
덮어쓸 함수 결정하기
type files에서 TypeScript에서는 이러한 함수를 사용하는 시기를 자세히 설명합니다.이 세 가지 방법은 현재 파일 이름을 매개 변수로 전달하고 되돌려주며, 진단 그룹을 되돌려 달라고 요구합니다.유형에 따라 진단의 모양을 정해야 합니다.덮어쓸 항목을 선택합니다.
구법의
getSyntacticDiagnostics(fileName: string): DiagnosticWithLocation[]
"지시 파일의 잘못된 문법에 대한 오류를 가져옵니다.영어에서'this cdeo have,erorrs'는 맞춤법 오류, 문법 오류, 문장부호 오류가 있기 때문에 문법적으로 무효입니다.마찬가지로 TypeScript의 구문 오류 예로는 if문에 괄호가 없고 일치하지 않는 괄호가 있으며 변수 이름으로 보존 키워드를 사용하는 것이 있습니다.
이 진단의 계산 비용은 매우 낮아서 다른 문서를 이해할 필요가 없다.비공식 결과는
getSemanticDiagnostics
의 오보 가능성을 증가시킬 수 있으니 주의하세요.대부분 문법과 관련된 진단을 대표하지만 유형 시스템이 필요한 경우도 있다
getSemanticDiagnostics
에 나타난다."의미의
getSemanticDiagnostics(fileName: string): Diagnostic[]
주어진 파일의 형식 시스템 문제를 표시하는 경고나 오류를 가져옵니다.의미 진단을 요청하면 유형 시스템을 시작하고 지연 작업을 실행할 수 있기 때문에 첫 번째 호출은 후속 호출보다 시간이 더 오래 걸릴 수 있습니다.
다른 get*Diagnostics 함수와 달리 이러한 진단에는 소스 파일에 대한 참조가 포함되지 않을 수 있습니다.구체적으로 말하면, 처음 그것을 호출할 때, 그것은 관련 위치가 없는 전역 진단으로 되돌아갈 것이다.
의미 진단과 문법 진단 사이의 차이를 비교하기 위해'태양은 녹색이다'는 말을 고려할 수 있다.문법이 정확하다.이것들은 진정한 영어 단어로 문장의 구조가 정확하다.그러나 그것은 의미가 무효다. 왜냐하면 그것은 사실이 아니기 때문이다."
권장 사항
getSuggestionDiagnostics(fileName: string): DiagnosticWithLocation[]
특정 파일에 대한 권장 진단을 받습니다. 이러한 진단은 잠재적인 오류 실행을 지시하는 것이 아니라, 주동적으로 재구성을 권장하는 경향이 있습니다.덮어쓰기 함수
현재, 우리는 설정된
proxy
을 사용하여 상술한 함수 중의 하나를 덮어쓸 수 있다.덮어쓰겠습니다getSemanticDiagnostics
. 그러나 원하는 기능을 가장 잘 선택해야 합니다.getSemanticDiagnostics
는 사용자가 사용하는 현재 파일의 이름을 매개 변수로 보여 줍니다. 이것은 우리가 ts.Diagnostic
의 목록을 되돌려 주기를 바랍니다.이것은 이렇게 보인다.
proxy.getSemanticDiagnostics = (filename) => {
return [];
}
지금 우리가 해야 할 첫 번째 일은 TypeScript 자체나 다른 언어 서비스 플러그인에 기록된 다른 진단을 되돌려 주는 것이다.우리는 info.languageService.getSemanticDiagnostics
를 사용하여 이 점을 실현할 수 있다.proxy.getSemanticDiagnostics = (filename) => {
const prior = languageService.getSemanticDiagnostics(filename);
return [...prior];
}
마지막으로, 우리는 자신의 논리를 추가하여 진단을 되돌릴 수 있다.우선 filename 매개 변수에 따라 파일의 내용을 가져와야 합니다.이를 위해 우리는 사용할 수 있다info.languageService.getProgram()?.getSourceFile(filename)
.이 함수의 결과는 정의되지 않았을 수도 있기 때문에, 우리는 이 상황을 포획하고 되돌아갈 것을 확보한다. prior
proxy.getSemanticDiagnostics = (filename) => {
const prior = info.languageService.getSemanticDiagnostics(filename);
const doc = info.languageService.getProgram()?.getSourceFile(filename);
if (!doc) {
return prior;
}
return [...prior];
}
이후에 우리는 이 파일을 분석하고 이를 바탕으로 진단을 생성할 수 있다.우리의 예에서, 우리는 파일의 줄마다 to-do나die 문장을 검사하기를 희망한다.이 예를 가능한 한 간단하게 하기 위해서, 우리는 // TODO:
로 시작하는 모든 줄을 찾아서 진단을 만들 것입니다.ts.Diagnostic
의 유형은 다음과 같습니다.enum DiagnosticCategory {
Warning = 0,
Error = 1,
Suggestion = 2,
Message = 3
}
interface DiagnosticMessageChain {
messageText: string;
category: DiagnosticCategory;
code: number;
next?: DiagnosticMessageChain[];
}
interface Diagnostic {
category: DiagnosticCategory;
code: number;
file: SourceFile | undefined;
start: number | undefined; // Index of `doc` to start error from
length: number | undefined;
messageText: string | DiagnosticMessageChain;
}
이 정보를 사용하여 진단을 할 수 있도록 필요한 모든 데이터를 수집합니다.우리의 예에서, 우리는 줄 번호와 줄 자체를 추적하기를 희망한다. TODO
주석을 포함한다.// Context
import { DiagnosticCategory } from "typescript";
// Context
proxy.getSemanticDiagnostics = (filename) => {
const prior = info.languageService.getSemanticDiagnostics(filename);
const doc = info.languageService.getProgram()?.getSourceFile(filename);
if (!doc) {
return prior;
}
return [
...prior,
...doc.text
.split("\n")
.reduce<[string, number]][]>((acc, line, index) => {
if (line.trim().startsWith("// TODO:")) {
return [...acc, [line, index]];
}
return acc;
}, [])
.map(([line, lineNumber]) => ({
file: doc,
start: doc.getPositionOfLineAndCharacter(lineNumber, 0),
length: line.length,
messageText: "This TODO comment should be fixed!",
category: DiagnosticCategory.Error,
source: "Your plugin name",
code: 666
}))
];
}
이 코드는 // TODO:
로 시작하는 전체 줄을 표시하고 "이 처리할 사항은 복구되어야 합니다!"를 표시합니다.오류 세부 정보의 메시지입니다.최종 결과
현재 설정 코드 세션과 변이한 프록시 행위를 결합하면 작업 진단 플러그인이 있습니다!
import { DiagnosticCategory } from "typescript";
function init(modules: { typescript: typeof import("typescript/lib/tsserverlibrary") }) {
const ts = modules.typescript;
function create(info: ts.server.PluginCreateInfo) {
const proxy: ts.LanguageService = Object.create(null);
for (let k of Object.keys(info.languageService) as Array<keyof ts.LanguageService>) {
const x = info.languageService[k]!;
// @ts-expect-error - JS runtime trickery which is tricky to type tersely
proxy[k] = (...args: Array<{}>) => x.apply(info.languageService, args);
}
proxy.getSemanticDiagnostics = (filename) => {
const prior = info.languageService.getSemanticDiagnostics(filename);
const doc = info.languageService.getProgram()?.getSourceFile(filename);
if (!doc) {
return prior;
}
return [
...prior,
...doc.text
.split("\n")
.reduce<[string, number][]>((acc, line, index) => {
if (line.trim().startsWith("// TODO:")) {
return [...acc, [line, index]];
}
return acc;
}, [])
.map(([line, lineNumber]) => ({
file: doc,
start: doc.getPositionOfLineAndCharacter(lineNumber, 0),
length: line.length,
messageText: "This TODO comment should be fixed!",
category: DiagnosticCategory.Error,
source: "Your plugin name",
code: 666
}))
];
}
return proxy;
}
return { create };
}
export = init;
로컬 테스트
{
"name": "your-plugin-name",
"version": "1.0.0",
"main": "dist/index.js",
"scripts": {
"build": "tsc -p .",
},
"dependencies": {
"typescript": "^4.5.4"
}
}
npm install
npm run build
npm link
cd ../path-to-repository
npm link "your-plugin-name"
tsconfig
합니다.{
"plugins": [
{ "name": "your-plugin-name" }
]
}
TODO
을 검토합니다.플러그 인 해제
플러그인을 풀려면
package.json
파일에서 상기 코드를 포함하는 파일을 참조해야 합니다.예: { "main": "dist/index.js" }
.현재 플러그인을 npm에 발표하고 다른 프로젝트에 설치합니다!결론
본문을 읽어 주셔서 감사합니다!이것repository의 샘플 플러그인을 보세요.대기 사항이나 사망 플러그인에 적용하는 방법에 관심이 있으시면 https://github.com/ngnijland/typescript-todo-or-die-plugin를 방문하십시오.
Reference
이 문제에 관하여(진단 TypeScript 언어 서비스 플러그인은 어떻게 작성합니까?), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/ngnijland/how-to-write-a-diagnostics-typescript-language-service-plugin-ggm텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)