Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support nikic/PHP-Parser v5.x #13

Merged
merged 5 commits into from
Jan 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ console.log(rootNodes);
// [
// {
// nodeType: "Stmt_Echo",
// attributes: { startLine: 2, startFilePos: 6, endLine: 2, endFilePos: 18 },
// attributes: { startLine: 2, startFilePos: 6, endLine: 2, endTokenPos: 4, endFilePos: 18 },
// exprs: [[Object]],
// },
// ];
Expand All @@ -76,7 +76,7 @@ const echoNode =
console.log(echoNode);
// {
// nodeType: 'Stmt_Echo',
// attributes: { startLine: 2, startFilePos: 6, endLine: 2, endFilePos: 18 },
// attributes: { startLine: 2, startFilePos: 6, endLine: 2, endTokenPos: 4, endFilePos: 18 },
// exprs: [
// { nodeType: 'Scalar_String', attributes: [Object], value: 'Hello' }
// ]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "major",
"comment": "feat: support `nikic/PHP-Parser` v5.x",
"packageName": "@rightcapital/php-parser",
"email": "i@rainx.cc",
"dependentChangeType": "patch"
}
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"require": {
"nikic/php-parser": "4.18.0"
"nikic/php-parser": "5.0.0"
}
}
144 changes: 73 additions & 71 deletions composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

53 changes: 41 additions & 12 deletions src/php-parser/generate-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ import {
mkdirSync,
readFileSync,
readdirSync,
renameSync,
rmSync,
statSync,
writeFileSync,
} from 'fs';
import * as os from 'os';
import { resolve } from 'path';
import * as path from 'path';
import * as _ from 'lodash';
Expand Down Expand Up @@ -58,6 +60,7 @@ export interface ICliContext {
allNodes: {
[nodeType: string]: IContextNodeItem;
};
temporaryNodeTypeRootPath: string;
}

class GenerateType {
Expand All @@ -67,15 +70,17 @@ class GenerateType {
private static cliContext: ICliContext = {
allNodeNames: [],
allNodes: {},
temporaryNodeTypeRootPath: resolve(os.tmpdir(), 'node'),
};

public static main(): void {
const typesRootPath = FilePathHelpers.getTypesRootPath();
const nodeTypeRootPath = resolve(typesRootPath, 'node');

// Remove and create a node root path first
rmSync(nodeTypeRootPath, { recursive: true, force: true });
mkdirSync(nodeTypeRootPath, { recursive: true });
mkdirSync(GenerateType.cliContext.temporaryNodeTypeRootPath, {
recursive: true,
});

GenerateType.walkSync(
PHP_PARSER_NODE_DIRECTORY_PATH,
Expand All @@ -84,13 +89,25 @@ class GenerateType {
);

const typesFileName = resolve(typesRootPath, 'types.ts');
const temporaryTypesFileName = resolve(typesRootPath, 'tmp-types.ts');
writeFileSync(
typesFileName,
temporaryTypesFileName,
TypeGenerationHelpers.generateCombinationTypesFromNodes(
GenerateType.cliContext,
),
{ encoding: 'utf-8' },
);

// Move temporarily generated files to correct path
// We need to remove the outdated files first
rmSync(nodeTypeRootPath, { recursive: true, force: true });
rmSync(typesFileName, { force: true });
// Move them
renameSync(
GenerateType.cliContext.temporaryNodeTypeRootPath,
nodeTypeRootPath,
);
renameSync(temporaryTypesFileName, typesFileName);
}

private static generateTypeForNodeByFile(filePath: string): void {
Expand Down Expand Up @@ -135,7 +152,7 @@ class GenerateType {
),
];
const parentNodeFilePath = FilePathHelpers.getFilePathFromNameNodeParts(
classNode.extends.parts,
NodeRetrieverHelpers.getPartsByName(classNode.extends.name),
classNode.extends.nodeType,
filePathParts,
uses,
Expand All @@ -144,7 +161,9 @@ class GenerateType {
const fullyQualifiedNodeName =
FilePathHelpers.getFullyQualifiedNodeNameByFilePath(fileRelativePath);

const parentNodeName = classNode.extends.parts.at(-1);
const parentNodeName = NodeRetrieverHelpers.getPartsByName(
classNode.extends.name,
).at(-1);

const fullyQualifiedParentNodeName =
FilePathHelpers.getFullyQualifiedParentNodeNameByFilePath(
Expand All @@ -160,7 +179,9 @@ class GenerateType {
fullyQualifiedNodeName,
fullyQualifiedParentNodeName,
nodeName: classNode.name.name,
parentNodeParts: classNode.extends.parts,
parentNodeParts: NodeRetrieverHelpers.getPartsByName(
classNode.extends.name,
),
parentNodeName,
parentNodeFilePath,
properties,
Expand All @@ -175,19 +196,27 @@ class GenerateType {
SRC_ROOT,
'templates/php-parser-node.mustache',
);
const typesRootPath = FilePathHelpers.getTypesRootPath();
const nodeTypeRootPath = resolve(typesRootPath, 'node');
const templateFileContent = readFileSync(templateFileName, 'utf-8');

try {
if (directoryRelativePath) {
mkdirSync(path.resolve(nodeTypeRootPath, directoryRelativePath), {
recursive: true,
});
mkdirSync(
path.resolve(
GenerateType.cliContext.temporaryNodeTypeRootPath,
directoryRelativePath,
),
{
recursive: true,
},
);
}
} finally {
writeFileSync(
resolve(nodeTypeRootPath, directoryRelativePath, `${fileName}.ts`),
resolve(
GenerateType.cliContext.temporaryNodeTypeRootPath,
directoryRelativePath,
`${fileName}.ts`,
),

Mustache.render(templateFileContent, nodeOutput),
);
Expand Down
6 changes: 5 additions & 1 deletion src/php-parser/helpers/cli-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,11 @@ export class CliHelpers {
): NodeTypeInheritingFromNodeAbstract[] {
const parserOutputString = execSync(
`${PHP_PARSER_BINARY} ${phpFilePath} -j`,
{ encoding: 'utf-8', maxBuffer: MAX_BUFFER_SIZE_FOR_PHP_BINARY_OUTPUT },
{
encoding: 'utf-8',
maxBuffer: MAX_BUFFER_SIZE_FOR_PHP_BINARY_OUTPUT,
stdio: ['pipe', 'pipe', 'ignore'],
},
);
return JSON.parse(
parserOutputString,
Expand Down
15 changes: 14 additions & 1 deletion src/php-parser/helpers/node-retriever-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,10 @@ export class NodeRetrieverHelpers {
if (namespaceNode?.stmts) {
return Object.fromEntries(
this.filterNodeByNodeType<Use_>(namespaceNode.stmts, NodeType.Stmt_Use)
.map((useNode) => useNode.uses[0].name.parts)
// https://github.com/nikic/PHP-Parser/blob/master/UPGRADE-5.0.md#changes-to-the-name-representation
.map((useNode) =>
NodeRetrieverHelpers.getPartsByName(useNode.uses[0].name.name),
)
.map((parts) => [parts.slice(-1), parts]),
) as IUses;
}
Expand Down Expand Up @@ -175,4 +178,14 @@ export class NodeRetrieverHelpers {
): T[] {
return nodes.filter((node) => node.nodeType === nodeType) as T[];
}

/**
* Get parts of name (split by the namespace separator).
*
* @param name the Full name with namespace separator
* @returns string[] Parts of name
*/
public static getPartsByName(name: string): string[] {
return name.split('\\');
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import type { Expr } from '../../node/expr'; // fullyQualifiedNodeName FullyQualifiedExpr
import type { NodeAbstract } from '../node'; // fullyQualifiedNodeName NodeAbstract

import type { NodeTypeInheritingFromFullyQualifiedExpr } from "../../types";
import type { NodeTypeInheritingFromFullyQualifiedExpr } from "../types";

// eslint-disable-next-line @typescript-eslint/naming-convention
export interface ArrayItem extends Omit<Expr, 'nodeType'> {
nodeType: 'Expr_ArrayItem';
export interface ArrayItem extends Omit<NodeAbstract, 'nodeType'> {
nodeType: 'ArrayItem';

["key"] : null | NodeTypeInheritingFromFullyQualifiedExpr;
["value"] : NodeTypeInheritingFromFullyQualifiedExpr;
Expand All @@ -15,4 +15,4 @@ export interface ArrayItem extends Omit<Expr, 'nodeType'> {
// We also need to export a symbol by using node type
// since the nodeName is possibly duplicated
// for the files need to import all nodes, we needs to use nodeType insteads
export type FullyQualifiedExprArrayItem = ArrayItem;
export type FullyQualifiedArrayItem = ArrayItem;
Loading