Skip to content

Commit

Permalink
fix: add more detailed documentation for the transpiler
Browse files Browse the repository at this point in the history
  • Loading branch information
yilun.sun committed Mar 6, 2024
1 parent afc7889 commit ee44ee3
Showing 1 changed file with 65 additions and 35 deletions.
100 changes: 65 additions & 35 deletions src/phpdoc-parser/transpiler/README.md
Original file line number Diff line number Diff line change
@@ -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<ExtendedTranspiler>) {
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 (
Expand All @@ -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<ExtendedTranspiler> =
// 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: '',
Expand All @@ -68,13 +91,20 @@ const nameNodePathResolver: NameNodePathResolver<ExtendedTranspiler> =
};
};

// 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.

0 comments on commit ee44ee3

Please sign in to comment.