Visaptverošs ceļvedis TypeScript Compiler API, kas aptver abstraktās sintakses koku (AST), koda analīzi, transformāciju un ģenerēšanu starptautiskiem izstrādātājiem.
TypeScript Compiler API: AST manipulācijas un koda transformācijas apgūšana
TypeScript Compiler API nodrošina jaudīgu saskarni TypeScript un JavaScript koda analīzei, manipulācijai un ģenerēšanai. Tās pamatā ir Abstract Syntax Tree (AST) – strukturēta jūsu avota koda reprezentācija. Izpratne par darbu ar AST paver iespējas uzlabotu rīku izveidei, piemēram, linters, koda formatētāji, statiskie analizatori un pielāgoti koda ģeneratori.
Kas ir TypeScript Compiler API?
TypeScript Compiler API ir TypeScript interfeisu un funkciju kopums, kas atklāj TypeScript kompilatora iekšējo darbību. Tā ļauj izstrādātājiem programmatiski mijiedarboties ar kompilācijas procesu, pārsniedzot vienkāršu koda kompilēšanu. Jūs varat to izmantot, lai:
- Analizētu kodu: Pārbaudiet koda struktūru, identificējiet iespējamās problēmas un izgūstiet semantisko informāciju.
- Transformētu kodu: Modificējiet esošo kodu, pievienojiet jaunas funkcijas vai automātiski refaktorizējiet kodu.
- Ģenerētu kodu: Izveidojiet jaunu kodu no nulles, pamatojoties uz veidnem vai citiem ievaddatiem.
Šī API ir būtiska, lai izveidotu sarežģītus izstrādes rīkus, kas uzlabo koda kvalitāti, automatizē atkārtotus uzdevumus un palielina izstrādātāju produktivitāti.
Abstraktās sintakses koka (AST) izpratne
AST ir koka struktūra, kas reprezentē jūsu koda struktūru. Katrs koka mezgls (node) attēlo sintaktisku konstrukt, piemēram, mainīgā deklarāciju, funkcijas izsaukumu vai vadības plūsmas izteikumu. TypeScript Compiler API nodrošina rīkus AST izbraukāšanai, tās mezglu pārbaudei un modificēšanai.
Apsveriet šo vienkāršo TypeScript kodu:
function greet(name: string): string {
return `Hello, ${name}!`;
}
console.log(greet("World"));
Šī koda AST reprezentētu funkcijas deklarāciju, return izteikumu, template literal, console.log izsaukumu un citus koda elementus. AST vizualizēšana var būt sarežģīta, taču rīki, piemēram, AST explorer (astexplorer.net), var palīdzēt. Šie rīki ļauj ievadīt kodu un redzēt tā atbilstošo AST lietotājam draudzīgā formātā. AST Explorer izmantošana palīdzēs jums izprast koda struktūru, ar kuru jūs manipulēsiet.
Galvenie AST mezglu tipi
TypeScript Compiler API definē dažādus AST mezglu tipus, katrs no kuriem reprezentē atšķirīgu sintaktisku konstruktu. Šeit ir daži bieži sastopami mezglu tipi:
- SourceFile: Reprezentē visu TypeScript failu.
- FunctionDeclaration: Reprezentē funkcijas definīciju.
- VariableDeclaration: Reprezentē mainīgā deklarāciju.
- Identifier: Reprezentē identifikatoru (piemēram, mainīgā nosaukumu, funkcijas nosaukumu).
- StringLiteral: Reprezentē string literal.
- CallExpression: Reprezentē funkcijas izsaukumu.
- ReturnStatement: Reprezentē return izteikumu.
Katram mezglu tipam ir īpašības, kas sniedz informāciju par atbilstošo koda elementu. Piemēram, `FunctionDeclaration` mezglam var būt īpašības tā nosaukumam, parametriem, atgriešanās tipam un ķermenim.
Darba sākšana ar Compiler API
Lai sāktu izmantot Compiler API, jums būs jāinstalē TypeScript un jābūt pamata izpratnei par TypeScript sintaksi. Šeit ir vienkāršs piemērs, kas demonstrē, kā nolasīt TypeScript failu un izdrukāt tā AST:
import * as ts from "typescript";
import * as fs from "fs";
const fileName = "example.ts";
const sourceCode = fs.readFileSync(fileName, "utf8");
const sourceFile = ts.createSourceFile(
fileName,
sourceCode,
ts.ScriptTarget.ES2015, // Target ECMAScript version
true // SetParentNodes: true to retain parent references in the AST
);
function printAST(node: ts.Node, indent = 0) {
const indentStr = " ".repeat(indent);
console.log(`${indentStr}${ts.SyntaxKind[node.kind]}`);
node.forEachChild(child => printAST(child, indent + 1));
}
printAST(sourceFile);
Skaidrojums:
- Moduļu importēšana: Importē `typescript` moduli un `fs` moduli failu sistēmas operācijām.
- Avota faila nolasīšana: Nolasiet faila ar nosaukumu `example.ts` saturu. Lai tas darbotos, jums būs jāizveido `example.ts` fails.
- SourceFile izveide: Izveido `SourceFile` objektu, kas reprezentē AST sakni. `ts.createSourceFile` funkcija analizē avota kodu un ģenerē AST.
- AST drukāšana: Definē rekursīvu funkciju `printAST`, kas izbrauc AST un drukā katra mezgla veidu.
- printAST izsaukums: Izsauc `printAST`, lai sāktu AST drukāšanu no saknes `SourceFile` mezgla.
Lai palaistu šo kodu, saglabājiet to kā `.ts` failu (piemēram, `ast-example.ts`), izveidojiet `example.ts` failu ar kādu TypeScript kodu, un pēc tam kompilējiet un palaidiet kodu:
tsc ast-example.ts
node ast-example.js
Tas konsolē izdrukās jūsu `example.ts` faila AST. Izvade parādīs mezglu hierarhiju un to veidus. Piemēram, tā varētu parādīt `FunctionDeclaration`, `Identifier`, `Block` un citus mezglu tipus.
AST izbraukāšana
Compiler API nodrošina vairākus veidus, kā izbraukāt AST. Vienkāršākais ir izmantot `forEachChild` metodi, kā parādīts iepriekšējā piemērā. Šī metode apmeklē katru dotā mezgla bērnu mezglu.
Sarežģītākiem izbraukāšanas scenārijiem varat izmantot `Visitor` dizaina modeli. Visitor ir objekts, kas definē metodes, kuras tiks izsauktas konkrētiem mezglu tipiem. Tas ļauj pielāgot izbraukšanas procesu un veikt darbības, pamatojoties uz mezgla tipu.
import * as ts from "typescript";
import * as fs from "fs";
const fileName = "example.ts";
const sourceCode = fs.readFileSync(fileName, "utf8");
const sourceFile = ts.createSourceFile(
fileName,
sourceCode,
ts.ScriptTarget.ES2015,
true
);
class IdentifierVisitor {
visit(node: ts.Node) {
if (ts.isIdentifier(node)) {
console.log(`Found identifier: ${node.text}`);
}
ts.forEachChild(node, n => this.visit(n));
}
}
const visitor = new IdentifierVisitor();
visitor.visit(sourceFile);
Skaidrojums:
- IdentifierVisitor klase: Definē klasi `IdentifierVisitor` ar metodi `visit`.
- Visit metode: `visit` metode pārbauda, vai pašreizējais mezgls ir `Identifier`. Ja tas ir, tā izdrukā identifikatora tekstu. Pēc tam tā rekursīvi izsauc `ts.forEachChild`, lai apmeklētu bērnu mezglus.
- Visitor izveide: Izveido `IdentifierVisitor` instanci.
- Traversēšanas sākums: Izsauc `visit` metodi `SourceFile`, lai sāktu izbraukāšanu.
Šis piemērs demonstrē, kā atrast visus identifikatorus AST. Jūs varat pielāgot šo modeli, lai atrastu citus mezglu tipus un veiktu dažādas darbības.
AST transformēšana
Compiler API patiesā jauda slēpjas tās spējā transformēt AST. Jūs varat modificēt AST, lai mainītu jūsu koda struktūru un uzvedību. Tas ir pamats koda refaktorizācijas rīkiem, koda ģeneratoriem un citiem uzlabotiem rīkiem.
Lai transformētu AST, jums būs jāizmanto `ts.transform` funkcija. Šī funkcija pieņem `SourceFile` un `TransformerFactory` funkciju sarakstu. `TransformerFactory` ir funkcija, kas pieņem `TransformationContext` un atgriež `Transformer` funkciju. `Transformer` funkcija ir atbildīga par mezglu izbraukšanu un transformēšanu AST.
Šeit ir vienkāršs piemērs, kas demonstrē, kā pievienot komentāru TypeScript faila sākumam:
import * as ts from "typescript";
import * as fs from "fs";
const fileName = "example.ts";
const sourceCode = fs.readFileSync(fileName, "utf8");
const sourceFile = ts.createSourceFile(
fileName,
sourceCode,
ts.ScriptTarget.ES2015,
true
);
const transformerFactory: ts.TransformerFactory = context => {
return transformer => {
return node => {
if (ts.isSourceFile(node)) {
// Create a leading comment
const comment = ts.addSyntheticLeadingComment(
node,
ts.SyntaxKind.MultiLineCommentTrivia,
" This file was automatically transformed ",
true // hasTrailingNewLine
);
return node;
}
return node;
};
};
};
const { transformed } = ts.transform(sourceFile, [transformerFactory]);
const printer = ts.createPrinter({
newLine: ts.NewLineKind.LineFeed
});
const result = printer.printFile(transformed[0]);
fs.writeFileSync("example.transformed.ts", result);
Skaidrojums:
- TransformerFactory: Definē `TransformerFactory` funkciju, kas atgriež `Transformer` funkciju.
- Transformer: `Transformer` funkcija pārbauda, vai pašreizējais mezgls ir `SourceFile`. Ja tas ir, tā pievieno vadošo komentāru mezglam, izmantojot `ts.addSyntheticLeadingComment`.
- ts.transform: Izsauc `ts.transform`, lai lietotu transformāciju uz `SourceFile`.
- Printer: Izveido `Printer` objektu, lai ģenerētu kodu no transformētā AST.
- Drukāt un rakstīt: Izdrukā transformēto kodu un ieraksta to jaunā failā ar nosaukumu `example.transformed.ts`.
Šis piemērs demonstrē vienkāršu transformāciju, taču jūs varat izmantot to pašu modeli, lai veiktu sarežģītākas transformācijas, piemēram, kodu refaktorizāciju, žurnālu izrakstu pievienošanu vai dokumentācijas ģenerēšanu.
Papildu transformācijas paņēmieni
Šeit ir daži papildu transformācijas paņēmieni, ko varat izmantot ar Compiler API:
- Jaunu mezglu izveide: Izmantojiet `ts.createXXX` funkcijas, lai izveidotu jaunus AST mezglus. Piemēram, `ts.createVariableDeclaration` izveido jaunu mainīgā deklarācijas mezglu.
- Mezglu aizstāšana: Aizstājiet esošos mezglus ar jauniem mezgliem, izmantojot `ts.visitEachChild` funkciju.
- Mezglu pievienošana: Pievienojiet jaunus mezglus AST, izmantojot `ts.updateXXX` funkcijas. Piemēram, `ts.updateBlock` atjaunina bloka izteikumu ar jauniem izteikumiem.
- Mezglu noņemšana: Noņemiet mezglus no AST, atgriežot `undefined` no transformatora funkcijas.
Koda ģenerēšana
Pēc AST transformēšanas jums būs jāģenerē no tā kods. Compiler API šim nolūkam nodrošina `Printer` objektu. `Printer` pieņem AST un ģenerē koda virknes reprezentāciju.
ts.createPrinter funkcija izveido `Printer` objektu. Jūs varat konfigurēt printeri ar dažādiem iestatījumiem, piemēram, izmantojamo rindiņas pārtraukuma rakstzīmi un to, vai pievienot komentārus.
`printer.printFile` metode pieņem `SourceFile` un atgriež koda virknes reprezentāciju. Pēc tam jūs varat ierakstīt šo virkni failā.
Compiler API praktiskie pielietojumi
TypeScript Compiler API ir daudz praktisku pielietojumu programmatūras izstrādē. Šeit ir daži piemēri:
- Linters: Izveidojiet pielāgotus linters, lai nodrošinātu kodēšanas standartus un identificētu iespējamās problēmas jūsu kodā.
- Koda formatētāji: Izveidojiet koda formatētājus, lai automātiski formatētu savu kodu atbilstoši noteiktam stilam.
- Statiskie analizatori: Izstrādājiet statiskos analizatorus, lai atklātu kļūdas, drošības ievainojamības un veiktspējas problēmas jūsu kodā.
- Koda ģeneratori: Ģenerējiet kodu no veidnem vai citiem ievaddatiem, automatizējot atkārtotus uzdevumus un samazinot boilerplate kodu. Piemēram, ģenerējot API klientus vai datubāzes shēmas no apraksta faila.
- Refaktorizācijas rīki: Izveidojiet refaktorizācijas rīkus, lai automātiski pārdēvētu mainīgos, izvilktu funkcijas vai pārvietotu kodu starp failiem.
- Internationalizācijas (i18n) automatizācija: Automātiski izgūstiet tulkojamās virknes no jūsu TypeScript koda un ģenerējiet lokalizācijas failus dažādām valodām. Piemēram, rīks varētu skenēt kodu pēc virknēm, kas nodotas `translate()` funkcijai, un automātiski pievienot tās tulkojuma resursu failam.
Piemērs: Vienkārša linters izveide
Izveidosim vienkāršu linters, kas pārbauda neizmantotos mainīgos TypeScript kodā. Šis linters identificēs mainīgos, kas ir deklarēti, bet nekad netiek izmantoti.
import * as ts from "typescript";
import * as fs from "fs";
const fileName = "example.ts";
const sourceCode = fs.readFileSync(fileName, "utf8");
const sourceFile = ts.createSourceFile(
fileName,
sourceCode,
ts.ScriptTarget.ES2015,
true
);
function findUnusedVariables(sourceFile: ts.SourceFile) {
const usedVariables = new Set();
function visit(node: ts.Node) {
if (ts.isIdentifier(node)) {
usedVariables.add(node.text);
}
ts.forEachChild(node, visit);
}
visit(sourceFile);
const unusedVariables: string[] = [];
function checkVariableDeclaration(node: ts.Node) {
if (ts.isVariableDeclaration(node) && node.name && ts.isIdentifier(node.name)) {
const variableName = node.name.text;
if (!usedVariables.has(variableName)) {
unusedVariables.push(variableName);
}
}
ts.forEachChild(node, checkVariableDeclaration);
}
checkVariableDeclaration(sourceFile);
return unusedVariables;
}
const unusedVariables = findUnusedVariables(sourceFile);
if (unusedVariables.length > 0) {
console.log("Unused variables:");
unusedVariables.forEach(variable => console.log(`- ${variable}`));
} else {
console.log("No unused variables found.");
}
Skaidrojums:
- findUnusedVariables funkcija: Definē funkciju `findUnusedVariables`, kas kā ievadi saņem `SourceFile`.
- usedVariables kopa: Izveido `Set` izmantoto mainīgo nosaukumu glabāšanai.
- visit funkcija: Definē rekursīvu funkciju `visit`, kas izbrauc AST un pievieno visus identifikatoru nosaukumus `usedVariables` kopai.
- checkVariableDeclaration funkcija: Definē rekursīvu funkciju `checkVariableDeclaration`, kas pārbauda, vai mainīgā deklarācija netiek izmantota. Ja tā netiek izmantota, tā pievieno mainīgā nosaukumu `unusedVariables` masīvam.
- unusedVariables atgriešana: Atgriež masīvu ar neizmantoto mainīgo nosaukumiem.
- Izvade: Konsolē izdrukā neizmantotos mainīgos.
Šis piemērs demonstrē vienkāršu linters. Jūs varat to paplašināt, lai pārbaudītu citus kodēšanas standartus un identificētu citas iespējamās problēmas jūsu kodā. Piemēram, jūs varētu pārbaudīt neizmantotus importus, pārmērīgi sarežģītas funkcijas vai potenciālas drošības nepilnības. Galvenais ir izprast, kā izbraukāt AST un identificēt konkrētos mezglu tipus, kas jūs interesē.
Labākā prakse un apsvērumi
- Izprotiet AST: Veltiet laiku, lai izprastu AST struktūru. Izmantojiet rīkus, piemēram, AST explorer, lai vizualizētu sava koda AST.
- Izmantojiet tipu pārbaudes (Type Guards): Izmantojiet tipu pārbaudes (`ts.isXXX`), lai nodrošinātu, ka strādājat ar pareizajiem mezglu tipiem.
- Apsveriet veiktspēju: AST transformācijas var būt aprēķinietilpas. Optimizējiet savu kodu, lai samazinātu apmeklēto un transformēto mezglu skaitu.
- Apstrādājiet kļūdas: Kļūdas apstrādājiet saudzīgi. Compiler API var izraisīt izņēmumus, ja mēģināt veikt nepareizas operācijas ar AST.
- Testējiet rūpīgi: Rūpīgi testējiet savas transformācijas, lai nodrošinātu, ka tās rada vēlamos rezultātus un neievieš jaunas kļūdas.
- Izmantojiet esošās bibliotēkas: Apsveriet iespēju izmantot esošās bibliotēkas, kas nodrošina augstāka līmeņa abstrakcijas pār Compiler API. Šīs bibliotēkas var vienkāršot biežāk sastopamos uzdevumus un samazināt jūsu rakstāmā koda apjomu. Piemēri ietver `ts-morph` un `typescript-eslint`.
Secinājums
TypeScript Compiler API ir jaudīgs rīks uzlabotu izstrādes rīku izveidei. Izprotot, kā strādāt ar AST, jūs varat izveidot linters, koda formatētājus, statiskos analizatorus un citus rīkus, kas uzlabo koda kvalitāti, automatizē atkārtotus uzdevumus un palielina izstrādātāju produktivitāti. Lai gan API var būt sarežģīta, tās apgūšanas priekšrocības ir ievērojamas. Šis visaptverošais ceļvedis sniedz pamatu Compiler API efektīvai izpētei un izmantošanai jūsu projektos. Atcerieties izmantot tādus rīkus kā AST Explorer, rūpīgi apstrādāt mezglu tipus un rūpīgi testēt savas transformācijas. Ar praksi un apņēmību jūs varat atbrīvot pilnu TypeScript Compiler API potenciālu un izveidot novatoriskus risinājumus programmatūras izstrādes ainavā.
Tālākai izpētei:
- TypeScript Compiler API dokumentācija: [https://github.com/microsoft/TypeScript/wiki/Using-the-Compiler-API](https://github.com/microsoft/TypeScript/wiki/Using-the-Compiler-API)
- AST Explorer: [https://astexplorer.net/](https://astexplorer.net/)
- ts-morph bibliotēka: [https://ts-morph.com/](https://ts-morph.com/)
- typescript-eslint: [https://typescript-eslint.io/](https://typescript-eslint.io/)