Configuration
- TypeScript course
- Expert
- Lesson 30/35
- 5 min
Add plugin configuration options.
Plugin configuration
Plugin configuration is given in the plugins array of tsconfig.json. Each entry carries a name and custom fields. In the plugin code you access these fields via info.config.
// tsconfig.json:
// "plugins": [
// { "name": "my-plugin", "prefix": "[lint]" }
// ]Reading configuration
info.config can be undefined; so you read safely with ?. and ??. Providing default values for custom fields makes the plugin robust.
const prefix: string =
info.config?.prefix ?? "[lint]";Practice Plugin with configuration
Write a plugin that reads a prefix from info.config?.prefix (default "[lint]"). Wrap getSemanticDiagnostics: for each VariableDeclaration without a type annotation, produce a diagnostic whose message starts with the prefix. Test: source let x = 1;, config.prefix = "[X]"; print the first diagnostic's messageText.
Starter code
import * as ts from "typescript";
// Bir plugin yaz: info'dan prefix ayarını oku
// - Yapılandırmadan prefix oku (varsayılan "[lint]")
// - Diagnostic metodunu sar
// - Tür eklemesi olmayan VariableDeclaration için diagnostic üret
// - Mesajı prefix ile başlat
// Test: prefix = "[X]" ile çağır, ilk diagnostic mesajını yazdır.
// kodunu buraya yazSample solution
import ts from "typescript";
function createPlugin(info: ts.server.PluginCreateInfo): ts.LanguageService {
const ls = info.languageService;
const prefix: string = info.config?.prefix ?? "[lint]";
return {
...ls,
getSemanticDiagnostics: function(fileName: string) {
const prior = ls.getSemanticDiagnostics(fileName);
const sf = ls.getProgram().getSourceFile(fileName);
if (!sf) return prior;
const extras: ts.Diagnostic[] = [];
function visit(node: ts.Node) {
if (ts.isVariableDeclaration(node) && !node.type) {
extras.push({
file: sf,
start: node.getStart(sf),
length: node.getWidth(sf),
category: ts.DiagnosticCategory.Warning,
code: 9001,
messageText: prefix + " Missing type annotation",
});
}
ts.forEachChild(node, visit);
}
visit(sf);
return [...prior, ...extras];
},
};
}
const sf = ts.createSourceFile("app.ts", "let x = 1;", ts.ScriptTarget.Latest, true);
const fakeLs = {
getSemanticDiagnostics: function() { return [] as ts.Diagnostic[]; },
getProgram: function() { return { getSourceFile: function(n: string) { return n === "app.ts" ? sf : undefined; } } as unknown as ts.Program; },
} as unknown as ts.LanguageService;
const info = { languageService: fakeLs, config: { prefix: "[X]" } } as unknown as ts.server.PluginCreateInfo;
const plugin = createPlugin(info);
const diags = plugin.getSemanticDiagnostics("app.ts");
console.log((diags[0] as ts.Diagnostic).messageText);Expected output
[X] Missing type annotation
Questions and answers
Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.
1 What does info.config carry?
- Diagnostic list
- SourceFile
- Plugin configuration options Correct answer
- Program object
Explanation: info.config carries the plugin configuration from tsconfig.json; it does not carry a Program, a diagnostic list, or a SourceFile.
2 Read configuration
const prefix: string = info.____?.prefix ?? "[lint]";
const prefix: string = info.config?.prefix ?? "[lint]";
Explanation: info.config carries the configuration object; options, settings and plugin do not exist on PluginCreateInfo.
3 Config parts
| Term | Meaning |
|---|---|
info.config |
Carries the configuration object |
info.languageService |
Carries the language service |
config.prefix |
Is a custom option example |
?? |
Provides a default value |