From ee44ee3e9bd41dd0bc72daba78d4be5e65aafa2b Mon Sep 17 00:00:00 2001 From: "yilun.sun" Date: Wed, 6 Mar 2024 10:09:12 +0800 Subject: [PATCH] fix: add more detailed documentation for the transpiler --- src/phpdoc-parser/transpiler/README.md | 100 ++++++++++++++++--------- 1 file changed, 65 insertions(+), 35 deletions(-) diff --git a/src/phpdoc-parser/transpiler/README.md b/src/phpdoc-parser/transpiler/README.md index dca606e0..1b49bf90 100644 --- a/src/phpdoc-parser/transpiler/README.md +++ b/src/phpdoc-parser/transpiler/README.md @@ -1,41 +1,62 @@ +# How to Use the PHPDoc Parser Transpiler + +This document provides a guide on how to use the PHPDoc Parser Transpiler to convert PHPDoc comments into TypeScript type annotations. We'll go through a example demonstrating how to set up and execute the transpilation process. + +## Setting Up the Environment + +Before you begin, ensure you have a TypeScript project setup where you can run the example code. Your project should include the necessary files and dependencies related to the PHPDoc Parser and the transpiler. + +## Example Code Overview + +The example provided demonstrates how to parse a PHPDoc comment, extract node information, and transpile it into a TypeScript node structure. The main steps are as follows: + +1. **Tokenization**: Convert a PHPDoc comment string into tokens. +2. **Parsing**: Transform the tokens into an Abstract Syntax Tree (AST) representing the PHPDoc structure. +3. **Transpilation**: Convert the PHPDoc AST nodes into TypeScript type nodes. +4. **Rendering**: Convert the TypeScript nodes into strings representing TypeScript type annotations. + +## Step 1: Import Necessary Classes and Types + ```TypeScript import { renderTsNodeToString } from './helpers'; -import { - type NameNodePathResolver, - PhpDocTypeNodeToTypescriptTypeNodeTranspiler, -} from './php-doc-to-typescript-type-transpiler'; -import type { ParamTagValueNode } from '../ast/php-doc/param-tag-value-node'; -import type { PropertyTagValueNode } from '../ast/php-doc/property-tag-value-node'; -import type { ReturnTagValueNode } from '../ast/php-doc/return-tag-value-node'; -import { Lexer } from '../lexer/lexer'; -import { ConstExprParser } from '../parser/const-expr-parser'; -import { PhpDocParser } from '../parser/php-doc-parser'; -import { TokenIterator } from '../parser/token-iterator'; -import { TypeParser } from '../parser/type-parser'; - -class ExtendedTranspiler extends PhpDocTypeNodeToTypescriptTypeNodeTranspiler { +import { PHPDocTypeNodeToTypescriptTypeNodeTranspiler } from './php-doc-to-typescript-type-transpiler'; +import type { ParamTagValueNode, PropertyTagValueNode, ReturnTagValueNode } from '../ast/php-doc'; +import { Lexer, ConstExprParser, PHPDocParser, TokenIterator, TypeParser } from '../lexer/parser'; +``` + +## Step 2: Define a Custom Transpiler Class + +```TypeScript +class ExtendedTranspiler extends PHPDocTypeNodeToTypescriptTypeNodeTranspiler { public isSnakeCase: boolean = true; constructor(public resolver: NameNodePathResolver) { - super( - (nodeParts: string[]) => - resolver.call(this, nodeParts) as { - path: string; - name: string; - isTypeOnly: boolean; - }, - ); + super((nodeParts: string[]) => resolver.call(this, nodeParts) as { + path: string; + name: string; + isTypeOnly: boolean; + }); } } +``` + +By extending the `PHPDocTypeNodeToTypescriptTypeNodeTranspiler` class to create a custom `ExtendedTranspiler` class, you gain the flexibility to add custom properties like `isSnakeCase`. This allows you to tailor the transpiler's behavior to your project's needs. For example, the `isSnakeCase` property can be used to determine how names are transformed or resolved within the `NameNodePathResolver`, catering to specific naming conventions with ease. + +## Step 3: Parse the PHPDoc Comment +```TypeScript const transpileCommentText = (commentText: string) => { + // Initialize the parser objects. const lexer = new Lexer(); const constExprParser = new ConstExprParser(); const typeParser = new TypeParser(constExprParser); - const phpDocParser = new PhpDocParser(typeParser, constExprParser); + const PHPDocParser = new PHPDocParser(typeParser, constExprParser); + // Tokenize and parse the PHPDoc comment to create the AST. const tokens = new TokenIterator(lexer.tokenize(commentText)); - const astRootNode = phpDocParser.parse(tokens); // PhpDocNode + const astRootNode = PHPDocParser.parse(tokens); // Produces a PHPDocNode + + // Extract property, return, or parameter nodes from the AST. const propertyTagValueNodes = astRootNode .getTags() .map((node) => node.value) as ( @@ -46,20 +67,22 @@ const transpileCommentText = (commentText: string) => { return propertyTagValueNodes; }; +``` -const shortText = `/** +## Step 4: Transpile PHPDoc Nodes to TypeScript and Render + +```TypeScript +const commentText = `/** * @property-read array|null $person */`; -const tsTypeNode = transpileCommentText(shortText); +// Parse the PHPDoc comment text to get node structures. +const tsTypeNode = transpileCommentText(commentText); +// Define a resolver function for path resolving in the transpiler. const nameNodePathResolver: NameNodePathResolver = - // eslint-disable-next-line func-names function (this: ExtendedTranspiler, nodeParts: string[]) { - console.log( - 'here ', - `${nodeParts.length} ${this.isSnakeCase ? 'yes' : 'no'}`, - ); + console.log(nodeParts, this.isSnakeCase); return { name: '', @@ -68,13 +91,20 @@ const nameNodePathResolver: NameNodePathResolver = }; }; +// Map through the nodes, transpile each, and render to TypeScript type strings. tsTypeNode.map((node) => { const transpiler = new ExtendedTranspiler(nameNodePathResolver); - transpiler.isSnakeCase = false; - transpiler.beforeTranspile(); - const transpiledNode = transpiler.transpile(node.type); + transpiler.isSnakeCase = false; // Set your configurations + transpiler.beforeTranspile(); // Initialize transpilation state + const transpiledNode = transpiler.transpile(node.type); // Transpile the node + // Render the TypeScript node to a string return renderTsNodeToString(transpiledNode); }); - ``` + +The `nameNodePathResolver` function is defined as a `NameNodePathResolver` for the `ExtendedTranspiler` class. Within this function, by using the `this` keyword typed as `ExtendedTranspiler`, it gains direct access to properties and methods of `ExtendedTranspiler`, including the custom property `isSnakeCase`. + +## Conclusion + +This guide presented a simplistic way to bridge PHPDoc comments and TypeScript type annotations using a transpiler. By parsing, transpiling, and rendering, you can automate the conversion of types from PHP to TypeScript, enhancing interoperability between the two languages in your project.