Skip to content

RightCapitalHQ/phpdoc-parser

Repository files navigation

PHPDoc parser TypeScript version

made by RightCapital GitHub Workflow Status (with event) Conventional Commits RightCapital frontend style guide

Next-gen PHPDoc parser with support for intersection types and generics(TypeScript version)

What's that

This parser is inspired by the PHPStan's phpdoc-parser library: https://github.com/phpstan/phpdoc-parser

This library @rightcapital/phpdoc-parser represents PHPDocs with an AST (Abstract Syntax Tree). It supports parsing and modifying PHPDocs by using TypeScript/JavaScript.

For the complete list of supported PHPDoc features check out PHPStan documentation.

Installation

# pnpm
pnpm add @rightcapital/phpdoc-parser
# yarn
yarn add @rightcapital/phpdoc-parser
# npm
npm install --save @rightcapital/phpdoc-parser

Basic usage

import {
  ConstExprParser,
  Lexer,
  PhpDocParser,
  TokenIterator,
  TypeParser,
} from '@rightcapital/phpdoc-parser';

// basic setup

const lexer = new Lexer();
const constExprParser = new ConstExprParser();
const typeParser = new TypeParser(constExprParser);
const phpDocParser = new PhpDocParser(typeParser, constExprParser);

// parsing and reading a PHPDoc string

const tokens = new TokenIterator(lexer.tokenize('/** @param Lorem $a */'));
const phpDocNode = phpDocParser.parse(tokens); // PhpDocNode
const paramTags = phpDocNode.getParamTagValues(); // ParamTagValueNode[]
console.log(paramTags[0].parameterName); // '$a'
console.log(paramTags[0].type); // IdentifierTypeNode { attributes: {}, name: 'Lorem' }

Format-preserving printer

This component can be used to modify the AST and print it again as close as possible to the original.

It's heavily inspired by format-preserving printer component in nikic/PHP-Parser.

import {
  CloningVisitor,
  ConstExprParser,
  IdentifierTypeNode,
  Lexer,
  NodeTraverser,
  PhpDocNode,
  PhpDocParser,
  TokenIterator,
  TypeParser,
  Printer,
} from '@rightcapital/phpdoc-parser';

const usedAttributes = { lines: true, indexes: true };

const lexer = new Lexer();
const constExprParser = new ConstExprParser(true, true, usedAttributes);
const typeParser = new TypeParser(constExprParser, true, usedAttributes);
const phpDocParser = new PhpDocParser(
  typeParser,
  constExprParser,
  true,
  true,
  usedAttributes,
);

const tokens = new TokenIterator(lexer.tokenize('/** @param Lorem $a */'));
const phpDocNode = phpDocParser.parse(tokens); // PhpDocNode

const cloningTraverser = new NodeTraverser([new CloningVisitor()]);

const [newPhpDocNode] = cloningTraverser.traverse([phpDocNode]) as [PhpDocNode];

// change something in newPhpDocNode
newPhpDocNode.getParamTagValues()[0].type = new IdentifierTypeNode('Ipsum');

// print changed PHPDoc
const printer = new Printer();
const newPhpDoc = printer.print(newPhpDocNode);
console.log(newPhpDoc);
// --- result ---
// /**
//  * @param Ipsum $a
//  */

const newPhpDocWithFormatPreserving = printer.printFormatPreserving(
  newPhpDocNode,
  phpDocNode,
  tokens,
);
console.log(newPhpDocWithFormatPreserving); // '/** @param Ipsum $a */'

Welcome to contribute

We are stilling waiting for someones to contribute, especially for the following features.

  • Doctrine Annotations support
  • More tests
  • More docs
  • A script to monitor upstream updates and notify the author to catch up.

Please check out our Contribution guide

How did we create the initial version of this project.

We created most of our code by using ChatGPT as a tool to transform most code from https://github.com/phpstan/phpdoc-parser to TypeScript version.

Our PHP API haven't used Doctrine, so Doctrine support are removed.

License

MIT License © 2023-Present