31
loading...
This website collects cookies to deliver better user experience
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;
getSyntacticDiagnostics(fileName: string): DiagnosticWithLocation[]
getSemanticDiagnostics
.getSemanticDiagnostics
."getSemanticDiagnostics(fileName: string): Diagnostic[]
getSuggestionDiagnostics(fileName: string): DiagnosticWithLocation[]
proxy
we set up to overwrite one of the above functions. I'm going to overwrite getSemanticDiagnostics
, but make sure to choose the function that matches best what you want to achieve.getSemanticDiagnostics
gives us the name of the current file our user works in as an argument and it expects us to return a list of ts.Diagnostic
.proxy.getSemanticDiagnostics = (filename) => {
return [];
}
info.languageService.getSemanticDiagnostics
to do this.proxy.getSemanticDiagnostics = (filename) => {
const prior = languageService.getSemanticDiagnostics(filename);
return [...prior];
}
info.languageService.getProgram()?.getSourceFile(filename)
. Since the result of this function can be undefined we make sure to catch that case and return prior
instead.proxy.getSemanticDiagnostics = (filename) => {
const prior = info.languageService.getSemanticDiagnostics(filename);
const doc = info.languageService.getProgram()?.getSourceFile(filename);
if (!doc) {
return prior;
}
return [...prior];
}
// TODO:
and create a diagnostic for each of them.ts.Diagnostic
is: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
comment.// 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:
and shows the "This TODO commend should be fixed!" message in the details of the error.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
in a TypeScript project.
{
"plugins": [
{ "name": "your-plugin-name" }
]
}
TODO
comments in your repository.package.json
file using the main key. E.g. { "main": "dist/index.js" }
. Now publish your plugin to npm and install it in another project!