TypeScript कंपाइलर API के लिए एक व्यापक गाइड, जिसमें AST, कोड विश्लेषण, ट्रांसफॉर्मेशन और अंतर्राष्ट्रीय डेवलपर्स के लिए जनरेशन शामिल है।
TypeScript कंपाइलर API: AST मैनिपुलेशन और कोड ट्रांसफॉर्मेशन में महारत हासिल करना
TypeScript कंपाइलर API, TypeScript और JavaScript कोड का विश्लेषण, हेरफेर और जनरेशन के लिए एक शक्तिशाली इंटरफ़ेस प्रदान करता है। इसके मूल में एस्ट्रैक्ट सिंटेक्स ट्री (AST) है, जो आपके सोर्स कोड का एक संरचित प्रतिनिधित्व है। AST के साथ काम करना समझना एडवांस्ड टूलिंग बनाने की क्षमताओं को अनलॉक करता है, जैसे लिंटर, कोड फॉर्मेटर, स्टैटिक एनालाइज़र और कस्टम कोड जनरेटर।
TypeScript कंपाइलर API क्या है?
TypeScript कंपाइलर API, TypeScript इंटरफेस और फ़ंक्शन का एक सेट है जो TypeScript कंपाइलर के आंतरिक कार्यों को उजागर करता है। यह डेवलपर्स को संकलन प्रक्रिया के साथ प्रोग्रामेटिक रूप से इंटरैक्ट करने की अनुमति देता है, केवल कोड संकलित करने से परे। आप इसका उपयोग कर सकते हैं:
- कोड का विश्लेषण करें: कोड संरचना का निरीक्षण करें, संभावित समस्याओं की पहचान करें, और सिमेंटिक जानकारी निकालें।
- कोड को रूपांतरित करें: मौजूदा कोड को संशोधित करें, नई सुविधाएँ जोड़ें, या कोड को स्वचालित रूप से रीफैक्टर करें।
- कोड जनरेट करें: टेम्प्लेट या अन्य इनपुट के आधार पर खरोंच से नया कोड बनाएं।
यह API परिष्कृत विकास उपकरण बनाने के लिए आवश्यक है जो कोड की गुणवत्ता में सुधार करते हैं, दोहराए जाने वाले कार्यों को स्वचालित करते हैं, और डेवलपर उत्पादकता को बढ़ाते हैं।
एस्ट्रैक्ट सिंटेक्स ट्री (AST) को समझना
AST आपके कोड की संरचना का एक ट्री-जैसी प्रतिनिधित्व है। ट्री में प्रत्येक नोड एक सिंटैक्टिक कंस्ट्रक्ट का प्रतिनिधित्व करता है, जैसे कि एक चर घोषणा, एक फ़ंक्शन कॉल, या एक नियंत्रण प्रवाह स्टेटमेंट। TypeScript कंपाइलर API AST को ट्रावर्स करने, इसके नोड्स का निरीक्षण करने और उन्हें संशोधित करने के लिए उपकरण प्रदान करता है।
इस साधारण TypeScript कोड पर विचार करें:
function greet(name: string): string {
return `Hello, ${name}!`;
}
console.log(greet("World"));
इस कोड के लिए AST फ़ंक्शन घोषणा, रिटर्न स्टेटमेंट, टेम्पलेट लिटरल, कंसोल.लॉग कॉल और कोड के अन्य तत्वों का प्रतिनिधित्व करेगा। AST को विज़ुअलाइज़ करना चुनौतीपूर्ण हो सकता है, लेकिन AST एक्सप्लोरर (astexplorer.net) जैसे टूल मदद कर सकते हैं। ये टूल आपको कोड दर्ज करने और एक उपयोगकर्ता-अनुकूल प्रारूप में उसके संबंधित AST को देखने की अनुमति देते हैं। AST एक्सप्लोरर का उपयोग करने से आपको उस कोड संरचना को समझने में मदद मिलेगी जिसे आप हेरफेर करेंगे।
मुख्य AST नोड प्रकार
TypeScript कंपाइलर API विभिन्न AST नोड प्रकारों को परिभाषित करता है, प्रत्येक एक अलग सिंटैक्टिक कंस्ट्रक्ट का प्रतिनिधित्व करता है। यहाँ कुछ सामान्य नोड प्रकार दिए गए हैं:
- SourceFile: एक संपूर्ण TypeScript फ़ाइल का प्रतिनिधित्व करता है।
- FunctionDeclaration: एक फ़ंक्शन परिभाषा का प्रतिनिधित्व करता है।
- VariableDeclaration: एक चर घोषणा का प्रतिनिधित्व करता है।
- Identifier: एक पहचानकर्ता (जैसे, चर नाम, फ़ंक्शन नाम) का प्रतिनिधित्व करता है।
- StringLiteral: एक स्ट्रिंग लिटरल का प्रतिनिधित्व करता है।
- CallExpression: एक फ़ंक्शन कॉल का प्रतिनिधित्व करता है।
- ReturnStatement: एक रिटर्न स्टेटमेंट का प्रतिनिधित्व करता है।
प्रत्येक नोड प्रकार में वे गुण होते हैं जो संबंधित कोड तत्व के बारे में जानकारी प्रदान करते हैं। उदाहरण के लिए, `FunctionDeclaration` नोड में उसके नाम, पैरामीटर, रिटर्न प्रकार और बॉडी के लिए गुण हो सकते हैं।
कंपाइलर API के साथ शुरुआत करना
कंपाइलर API का उपयोग शुरू करने के लिए, आपको TypeScript इंस्टॉल करना होगा और TypeScript सिंटैक्स की बुनियादी समझ होनी चाहिए। यहाँ एक सरल उदाहरण दिया गया है जो TypeScript फ़ाइल को पढ़ने और उसके 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);
स्पष्टीकरण:
- मॉड्यूल आयात करें: फ़ाइल सिस्टम संचालन के लिए `typescript` मॉड्यूल और `fs` मॉड्यूल आयात करता है।
- सोर्स फ़ाइल पढ़ें: `example.ts` नामक TypeScript फ़ाइल की सामग्री पढ़ता है। इसे काम करने के लिए आपको `example.ts` फ़ाइल बनाने की आवश्यकता होगी।
- SourceFile बनाएं: `SourceFile` ऑब्जेक्ट बनाता है, जो AST के रूट का प्रतिनिधित्व करता है। `ts.createSourceFile` फ़ंक्शन सोर्स कोड को पार्स करता है और AST जनरेट करता है।
- AST प्रिंट करें: एक रिकर्सिव फ़ंक्शन `printAST` को परिभाषित करता है जो AST को ट्रावर्स करता है और प्रत्येक नोड के प्रकार को प्रिंट करता है।
- printAST को कॉल करें: रूट `SourceFile` नोड से AST को प्रिंट करना शुरू करने के लिए `printAST` को कॉल करता है।
इस कोड को चलाने के लिए, इसे `.ts` फ़ाइल (जैसे, `ast-example.ts`) के रूप में सहेजें, कुछ TypeScript कोड के साथ `example.ts` फ़ाइल बनाएं, और फिर कोड को संकलित और चलाएं:
tsc ast-example.ts
node ast-example.js
यह आपके `example.ts` फ़ाइल के AST को कंसोल पर प्रिंट करेगा। आउटपुट नोड्स की पदानुक्रम और उनके प्रकार दिखाएगा। उदाहरण के लिए, यह `FunctionDeclaration`, `Identifier`, `Block`, और अन्य नोड प्रकार दिखा सकता है।
AST को ट्रावर्स करना
कंपाइलर API AST को ट्रावर्स करने के कई तरीके प्रदान करता है। सबसे सरल `forEachChild` विधि का उपयोग करना है, जैसा कि पिछले उदाहरण में दिखाया गया है। यह विधि किसी दिए गए नोड के प्रत्येक चाइल्ड नोड पर जाती है।
अधिक जटिल ट्रावर्सल परिदृश्यों के लिए, आप एक `Visitor` पैटर्न का उपयोग कर सकते हैं। एक विज़िटर एक ऑब्जेक्ट है जो विशिष्ट नोड प्रकारों के लिए कॉल किए जाने वाले तरीकों को परिभाषित करता है। यह आपको ट्रावर्सल प्रक्रिया को अनुकूलित करने और नोड प्रकार के आधार पर क्रियाएं करने की अनुमति देता है।
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);
स्पष्टीकरण:
- IdentifierVisitor क्लास: एक `visit` विधि के साथ एक `IdentifierVisitor` क्लास को परिभाषित करता है।
- Visit मेथड: `visit` विधि जांच करती है कि वर्तमान नोड एक `Identifier` है या नहीं। यदि है, तो यह पहचानकर्ता का टेक्स्ट प्रिंट करता है। फिर यह चाइल्ड नोड्स पर जाने के लिए `ts.forEachChild` को रिकर्सिव रूप से कॉल करता है।
- विज़िटर बनाएं: `IdentifierVisitor` का एक इंस्टेंस बनाता है।
- ट्रावर्सल शुरू करें: ट्रावर्सल शुरू करने के लिए `SourceFile` पर `visit` विधि को कॉल करता है।
यह उदाहरण AST में सभी पहचानकर्ताओं को खोजने का तरीका बताता है। आप अन्य नोड प्रकारों को खोजने और विभिन्न क्रियाएं करने के लिए इस पैटर्न को अनुकूलित कर सकते हैं।
AST को रूपांतरित करना
कंपाइलर API की वास्तविक शक्ति AST को रूपांतरित करने की इसकी क्षमता में निहित है। आप अपने कोड की संरचना और व्यवहार को बदलने के लिए AST को संशोधित कर सकते हैं। यह कोड रीफैक्टरिंग टूल, कोड जनरेटर और अन्य एडवांस्ड टूलिंग का आधार है।
AST को रूपांतरित करने के लिए, आपको `ts.transform` फ़ंक्शन का उपयोग करना होगा। यह फ़ंक्शन एक `SourceFile` और `TransformerFactory` फ़ंक्शन की एक सूची लेता है। `TransformerFactory` एक फ़ंक्शन है जो `TransformationContext` लेता है और `Transformer` फ़ंक्शन लौटाता है। `Transformer` फ़ंक्शन AST में नोड्स पर जाने और उन्हें बदलने के लिए जिम्मेदार है।
यहाँ एक सरल उदाहरण दिया गया है जो TypeScript फ़ाइल की शुरुआत में एक टिप्पणी जोड़ने का तरीका प्रदर्शित करता है:
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);
स्पष्टीकरण:
- TransformerFactory: एक `TransformerFactory` फ़ंक्शन को परिभाषित करता है जो एक `Transformer` फ़ंक्शन लौटाता है।
- Transformer: `Transformer` फ़ंक्शन जांच करता है कि वर्तमान नोड `SourceFile` है या नहीं। यदि है, तो यह `ts.addSyntheticLeadingComment` का उपयोग करके नोड में एक अग्रणी टिप्पणी जोड़ता है।
- ts.transform: `SourceFile` पर परिवर्तन लागू करने के लिए `ts.transform` को कॉल करता है।
- Printer: ट्रांसफ़ॉर्म किए गए AST से कोड जनरेट करने के लिए एक `Printer` ऑब्जेक्ट बनाता है।
- प्रिंट और लिखें: ट्रांसफ़ॉर्म किए गए कोड को प्रिंट करता है और इसे `example.transformed.ts` नामक एक नई फ़ाइल में लिखता है।
यह उदाहरण एक सरल परिवर्तन प्रदर्शित करता है, लेकिन आप कोड रीफैक्टरिंग, लॉगिंग स्टेटमेंट जोड़ने, या दस्तावेज़ीकरण उत्पन्न करने जैसे अधिक जटिल परिवर्तन करने के लिए एक ही पैटर्न का उपयोग कर सकते हैं।
एडवांस्ड ट्रांसफॉर्मेशन तकनीकें
यहाँ कुछ एडवांस्ड ट्रांसफॉर्मेशन तकनीकें दी गई हैं जिनका आप कंपाइलर API के साथ उपयोग कर सकते हैं:
- नए नोड्स बनाना: नए AST नोड्स बनाने के लिए `ts.createXXX` फ़ंक्शन का उपयोग करें। उदाहरण के लिए, `ts.createVariableDeclaration` एक नया चर घोषणा नोड बनाता है।
- नोड्स को बदलना: `ts.visitEachChild` फ़ंक्शन का उपयोग करके मौजूदा नोड्स को नए नोड्स से बदलें।
- नोड्स जोड़ना: `ts.updateXXX` फ़ंक्शन का उपयोग करके AST में नए नोड्स जोड़ें। उदाहरण के लिए, `ts.updateBlock` नए स्टेटमेंट के साथ एक ब्लॉक स्टेटमेंट को अपडेट करता है।
- नोड्स हटाना: ट्रांसफ़ॉर्मर फ़ंक्शन से `undefined` लौटाकर AST से नोड्स हटाएँ।
कोड जनरेशन
AST को रूपांतरित करने के बाद, आपको इससे कोड जनरेट करना होगा। कंपाइलर API इस उद्देश्य के लिए एक `Printer` ऑब्जेक्ट प्रदान करता है। `Printer` एक AST लेता है और कोड का एक स्ट्रिंग प्रतिनिधित्व जनरेट करता है।
`ts.createPrinter` फ़ंक्शन एक `Printer` ऑब्जेक्ट बनाता है। आप विभिन्न विकल्पों के साथ प्रिंटर को कॉन्फ़िगर कर सकते हैं, जैसे कि उपयोग करने के लिए नई लाइन कैरेक्टर और टिप्पणियों को उत्सर्जित करना है या नहीं।
`printer.printFile` विधि एक `SourceFile` लेती है और कोड का स्ट्रिंग प्रतिनिधित्व लौटाती है। आप इस स्ट्रिंग को फ़ाइल में लिख सकते हैं।
कंपाइलर API के व्यावहारिक अनुप्रयोग
सॉफ़्टवेयर विकास में TypeScript कंपाइलर API के कई व्यावहारिक अनुप्रयोग हैं। यहाँ कुछ उदाहरण दिए गए हैं:
- लिंटर: कोडिंग मानकों को लागू करने और आपके कोड में संभावित समस्याओं की पहचान करने के लिए कस्टम लिंटर बनाएं।
- कोड फॉर्मेटर: आपके कोड को एक विशिष्ट शैली गाइड के अनुसार स्वचालित रूप से प्रारूपित करने के लिए कोड फॉर्मेटर बनाएं।
- स्टैटिक एनालाइज़र: आपके कोड में बग, सुरक्षा भेद्यता और प्रदर्शन बाधाओं का पता लगाने के लिए स्टैटिक एनालाइज़र विकसित करें।
- कोड जनरेटर: टेम्प्लेट या अन्य इनपुट से कोड जनरेट करें, दोहराए जाने वाले कार्यों को स्वचालित करें और बॉयलरप्लेट कोड को कम करें। उदाहरण के लिए, एक विवरण फ़ाइल से एपीआई क्लाइंट या डेटाबेस स्कीमा जनरेट करना।
- रीफैक्टरिंग टूल: चर का नाम बदलने, फ़ंक्शन निकालने, या फ़ाइलों के बीच कोड ले जाने के लिए रीफैक्टरिंग टूल बनाएं।
- अंतर्राष्ट्रीयकरण (i18n) स्वचालन: स्वचालित रूप से अपने TypeScript कोड से अनुवाद योग्य स्ट्रिंग्स निकालें और विभिन्न भाषाओं के लिए स्थानीयकरण फ़ाइलें जनरेट करें। उदाहरण के लिए, एक टूल `translate()` फ़ंक्शन में पास किए गए स्ट्रिंग्स के लिए कोड स्कैन कर सकता है और उन्हें स्वचालित रूप से एक अनुवाद संसाधन फ़ाइल में जोड़ सकता है।
उदाहरण: एक साधारण लिंटर बनाना
आइए एक साधारण लिंटर बनाएं जो TypeScript कोड में अप्रयुक्त चर की जांच करता है। यह लिंटर उन चर की पहचान करेगा जो घोषित हैं लेकिन कभी उपयोग नहीं किए गए हैं।
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.");
}
स्पष्टीकरण:
- findUnusedVariables फ़ंक्शन: `SourceFile` को इनपुट के रूप में लेने वाला `findUnusedVariables` फ़ंक्शन को परिभाषित करता है।
- usedVariables सेट: उपयोग किए गए चर के नामों को संग्रहीत करने के लिए एक `Set` बनाता है।
- visit फ़ंक्शन: एक रिकर्सिव फ़ंक्शन `visit` को परिभाषित करता है जो AST को ट्रावर्स करता है और सभी पहचानकर्ताओं के नामों को `usedVariables` सेट में जोड़ता है।
- checkVariableDeclaration फ़ंक्शन: एक रिकर्सिव फ़ंक्शन `checkVariableDeclaration` को परिभाषित करता है जो जांच करता है कि चर घोषणा अप्रयुक्त है या नहीं। यदि यह है, तो यह चर नाम को `unusedVariables` ऐरे में जोड़ता है।
- Return unusedVariables: किसी भी अप्रयुक्त चर वाले ऐरे को लौटाता है।
- आउटपुट: अप्रयुक्त चर को कंसोल पर प्रिंट करता है।
यह उदाहरण एक सरल लिंटर को प्रदर्शित करता है। आप इसे अन्य कोडिंग मानकों की जांच करने और अपने कोड में अन्य संभावित समस्याओं की पहचान करने के लिए बढ़ा सकते हैं। उदाहरण के लिए, आप अप्रयुक्त आयात, अत्यधिक जटिल फ़ंक्शन, या संभावित सुरक्षा भेद्यताओं की जांच कर सकते हैं। मुख्य बात यह समझना है कि AST को कैसे ट्रावर्स किया जाए और उन विशिष्ट नोड प्रकारों की पहचान की जाए जिनमें आपकी रुचि है।
सर्वोत्तम प्रथाएं और विचार
- AST को समझें: AST की संरचना को समझने में समय व्यतीत करें। अपने कोड के AST को विज़ुअलाइज़ करने के लिए AST एक्सप्लोरर जैसे टूल का उपयोग करें।
- टाइप गार्ड का उपयोग करें: सुनिश्चित करें कि आप सही नोड प्रकारों के साथ काम कर रहे हैं, यह सुनिश्चित करने के लिए टाइप गार्ड (`ts.isXXX`) का उपयोग करें।
- प्रदर्शन पर विचार करें: AST परिवर्तन कम्प्यूटेशनल रूप से महंगे हो सकते हैं। आपके द्वारा ट्रावर्स और रूपांतरित किए जाने वाले नोड्स की संख्या को कम करने के लिए अपने कोड को अनुकूलित करें।
- त्रुटियों को संभालें: त्रुटियों को शालीनता से संभालें। यदि आप AST पर अमान्य संचालन करने का प्रयास करते हैं तो कंपाइलर API अपवाद फेंक सकता है।
- पूरी तरह से परीक्षण करें: यह सुनिश्चित करने के लिए कि वे वांछित परिणाम उत्पन्न करते हैं और नए बग पेश नहीं करते हैं, अपने परिवर्तनों का पूरी तरह से परीक्षण करें।
- मौजूदा लाइब्रेरी का उपयोग करें: उन मौजूदा लाइब्रेरी का उपयोग करने पर विचार करें जो कंपाइलर API पर उच्च-स्तरीय अमूर्तता प्रदान करती हैं। ये लाइब्रेरी सामान्य कार्यों को सरल बना सकती हैं और आपको लिखने वाले कोड की मात्रा को कम कर सकती हैं। उदाहरणों में `ts-morph` और `typescript-eslint` शामिल हैं।
निष्कर्ष
TypeScript कंपाइलर API एडवांस्ड डेवलपमेंट टूल बनाने के लिए एक शक्तिशाली उपकरण है। AST के साथ काम करना समझकर, आप लिंटर, कोड फॉर्मेटर, स्टैटिक एनालाइज़र और अन्य टूल बना सकते हैं जो कोड की गुणवत्ता में सुधार करते हैं, दोहराए जाने वाले कार्यों को स्वचालित करते हैं, और डेवलपर उत्पादकता को बढ़ाते हैं। जबकि API जटिल हो सकता है, इसमें महारत हासिल करने के लाभ महत्वपूर्ण हैं। यह व्यापक गाइड कंपाइलर API को आपके प्रोजेक्ट्स में प्रभावी ढंग से एक्सप्लोर करने और उपयोग करने के लिए एक आधार प्रदान करता है। AST एक्सप्लोरर जैसे टूल का लाभ उठाना, नोड प्रकारों को सावधानीपूर्वक संभालना और अपने परिवर्तनों का पूरी तरह से परीक्षण करना याद रखें। अभ्यास और समर्पण के साथ, आप TypeScript कंपाइलर API की पूरी क्षमता को अनलॉक कर सकते हैं और सॉफ़्टवेयर विकास परिदृश्य के लिए नवीन समाधान बना सकते हैं।
आगे की खोज:
- TypeScript कंपाइलर API प्रलेखन: [https://github.com/microsoft/TypeScript/wiki/Using-the-Compiler-API](https://github.com/microsoft/TypeScript/wiki/Using-the-Compiler-API)
- AST एक्सप्लोरर: [https://astexplorer.net/](https://astexplorer.net/)
- ts-morph लाइब्रेरी: [https://ts-morph.com/](https://ts-morph.com/)
- typescript-eslint: [https://typescript-eslint.io/](https://typescript-eslint.io/)