php-parser-py 1.0.0__tar.gz → 1.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {php_parser_py-1.0.0 → php_parser_py-1.1.0}/PKG-INFO +15 -13
- {php_parser_py-1.0.0 → php_parser_py-1.1.0}/README.md +14 -12
- {php_parser_py-1.0.0 → php_parser_py-1.1.0}/pyproject.toml +1 -1
- {php_parser_py-1.0.0 → php_parser_py-1.1.0}/src/php_parser_py/_ast.py +2 -2
- {php_parser_py-1.0.0 → php_parser_py-1.1.0}/src/php_parser_py/_parser.py +1 -1
- {php_parser_py-1.0.0 → php_parser_py-1.1.0}/src/php_parser_py/_printer.py +40 -8
- {php_parser_py-1.0.0 → php_parser_py-1.1.0}/src/php_parser_py/__init__.py +0 -0
- {php_parser_py-1.0.0 → php_parser_py-1.1.0}/src/php_parser_py/_edge.py +0 -0
- {php_parser_py-1.0.0 → php_parser_py-1.1.0}/src/php_parser_py/_node.py +0 -0
- {php_parser_py-1.0.0 → php_parser_py-1.1.0}/src/php_parser_py/_resources.py +0 -0
- {php_parser_py-1.0.0 → php_parser_py-1.1.0}/src/php_parser_py/_runner.py +0 -0
- {php_parser_py-1.0.0 → php_parser_py-1.1.0}/src/php_parser_py/exceptions.py +0 -0
- {php_parser_py-1.0.0 → php_parser_py-1.1.0}/src/php_parser_py/resources/php-parser-4.19.4.zip +0 -0
- {php_parser_py-1.0.0 → php_parser_py-1.1.0}/src/php_parser_py/vendor/.extracted +0 -0
- {php_parser_py-1.0.0 → php_parser_py-1.1.0}/src/php_parser_py/vendor/LICENSE.txt +0 -0
- {php_parser_py-1.0.0 → php_parser_py-1.1.0}/src/php_parser_py/vendor/php-parser.phar +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: php-parser-py
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.1.0
|
|
4
4
|
Summary: Python wrapper for PHP-Parser using cpg2py
|
|
5
5
|
Author: samhsu-dev
|
|
6
6
|
Author-email: samhsu-dev <yxu166@jh.edu>
|
|
@@ -52,7 +52,7 @@ nodes = parse_code(code)
|
|
|
52
52
|
# Returns list of Node instances (no project/file structure)
|
|
53
53
|
|
|
54
54
|
for node in nodes:
|
|
55
|
-
print(f"Node type: {node.
|
|
55
|
+
print(f"Node type: {node.node_type}")
|
|
56
56
|
```
|
|
57
57
|
|
|
58
58
|
### Parse PHP File (With Project Structure)
|
|
@@ -69,7 +69,7 @@ files = ast.files()
|
|
|
69
69
|
print(f"Project has {len(files)} file(s)")
|
|
70
70
|
|
|
71
71
|
# Get file containing a specific node
|
|
72
|
-
stmt_node = ast.first_node(lambda n: n.
|
|
72
|
+
stmt_node = ast.first_node(lambda n: n.node_type == "Stmt_Function")
|
|
73
73
|
file_node = ast.get_file(stmt_node.id)
|
|
74
74
|
print(f"Function is in file: {file_node.get_property('filePath')}")
|
|
75
75
|
```
|
|
@@ -86,8 +86,8 @@ ast = parse_project(["file1.php", "file2.php", "file3.php"])
|
|
|
86
86
|
for file_node in ast.files():
|
|
87
87
|
print(f"File: {file_node.get_property('filePath')}")
|
|
88
88
|
# Get statements in this file
|
|
89
|
-
for stmt in ast.
|
|
90
|
-
print(f" Statement: {stmt.
|
|
89
|
+
for stmt in ast.succ(file_node):
|
|
90
|
+
print(f" Statement: {stmt.node_type}")
|
|
91
91
|
|
|
92
92
|
# Access project and file paths
|
|
93
93
|
ast = parse_project(["file1.php", "subdir/file2.php"])
|
|
@@ -107,19 +107,19 @@ from php_parser_py import parse_file
|
|
|
107
107
|
ast = parse_file("example.php")
|
|
108
108
|
|
|
109
109
|
# Find all echo statements
|
|
110
|
-
for echo in ast.nodes(lambda n: n.
|
|
111
|
-
print(f"Echo at line {echo.
|
|
110
|
+
for echo in ast.nodes(lambda n: n.node_type == "Stmt_Echo"):
|
|
111
|
+
print(f"Echo at line {echo.start_line}")
|
|
112
112
|
|
|
113
113
|
# Get children of a node (via PARENT_OF edges)
|
|
114
114
|
for child in ast.succ(some_node):
|
|
115
|
-
print(f"Child type: {child.
|
|
115
|
+
print(f"Child type: {child.node_type}")
|
|
116
116
|
|
|
117
117
|
# Get all descendants
|
|
118
118
|
for descendant in ast.descendants(some_node):
|
|
119
|
-
print(f"Descendant: {descendant.
|
|
119
|
+
print(f"Descendant: {descendant.node_type}")
|
|
120
120
|
|
|
121
121
|
# Get file containing a node
|
|
122
|
-
stmt_node = ast.first_node(lambda n: n.
|
|
122
|
+
stmt_node = ast.first_node(lambda n: n.node_type == "Stmt_Function")
|
|
123
123
|
file_node = ast.get_file(stmt_node.id)
|
|
124
124
|
if file_node:
|
|
125
125
|
print(f"Function is in: {file_node.get_property('filePath')}")
|
|
@@ -200,10 +200,12 @@ ast = parser.parse("<?php echo 'hello';")
|
|
|
200
200
|
|
|
201
201
|
- **`Node`**: Wraps a single AST node
|
|
202
202
|
- `id`: Node identifier
|
|
203
|
-
- `
|
|
204
|
-
- `
|
|
205
|
-
- `properties`: All node properties
|
|
203
|
+
- `node_type`: Node type (e.g., "Stmt_Function") - returns `nodeType` property
|
|
204
|
+
- `all_properties`: All node properties as dict
|
|
206
205
|
- `get_property(*names)`: Get property value
|
|
206
|
+
- `start_line`, `end_line`: Line number properties
|
|
207
|
+
- `__getitem__(key)`: Dict-like access (e.g., `node["name"]`)
|
|
208
|
+
- `get(key, default)`: Get property with default value
|
|
207
209
|
|
|
208
210
|
- **`Parser`**: Parses PHP code
|
|
209
211
|
- `__init__(php_binary_path=None, php_binary_url=None)`: Initialize parser
|
|
@@ -41,7 +41,7 @@ nodes = parse_code(code)
|
|
|
41
41
|
# Returns list of Node instances (no project/file structure)
|
|
42
42
|
|
|
43
43
|
for node in nodes:
|
|
44
|
-
print(f"Node type: {node.
|
|
44
|
+
print(f"Node type: {node.node_type}")
|
|
45
45
|
```
|
|
46
46
|
|
|
47
47
|
### Parse PHP File (With Project Structure)
|
|
@@ -58,7 +58,7 @@ files = ast.files()
|
|
|
58
58
|
print(f"Project has {len(files)} file(s)")
|
|
59
59
|
|
|
60
60
|
# Get file containing a specific node
|
|
61
|
-
stmt_node = ast.first_node(lambda n: n.
|
|
61
|
+
stmt_node = ast.first_node(lambda n: n.node_type == "Stmt_Function")
|
|
62
62
|
file_node = ast.get_file(stmt_node.id)
|
|
63
63
|
print(f"Function is in file: {file_node.get_property('filePath')}")
|
|
64
64
|
```
|
|
@@ -75,8 +75,8 @@ ast = parse_project(["file1.php", "file2.php", "file3.php"])
|
|
|
75
75
|
for file_node in ast.files():
|
|
76
76
|
print(f"File: {file_node.get_property('filePath')}")
|
|
77
77
|
# Get statements in this file
|
|
78
|
-
for stmt in ast.
|
|
79
|
-
print(f" Statement: {stmt.
|
|
78
|
+
for stmt in ast.succ(file_node):
|
|
79
|
+
print(f" Statement: {stmt.node_type}")
|
|
80
80
|
|
|
81
81
|
# Access project and file paths
|
|
82
82
|
ast = parse_project(["file1.php", "subdir/file2.php"])
|
|
@@ -96,19 +96,19 @@ from php_parser_py import parse_file
|
|
|
96
96
|
ast = parse_file("example.php")
|
|
97
97
|
|
|
98
98
|
# Find all echo statements
|
|
99
|
-
for echo in ast.nodes(lambda n: n.
|
|
100
|
-
print(f"Echo at line {echo.
|
|
99
|
+
for echo in ast.nodes(lambda n: n.node_type == "Stmt_Echo"):
|
|
100
|
+
print(f"Echo at line {echo.start_line}")
|
|
101
101
|
|
|
102
102
|
# Get children of a node (via PARENT_OF edges)
|
|
103
103
|
for child in ast.succ(some_node):
|
|
104
|
-
print(f"Child type: {child.
|
|
104
|
+
print(f"Child type: {child.node_type}")
|
|
105
105
|
|
|
106
106
|
# Get all descendants
|
|
107
107
|
for descendant in ast.descendants(some_node):
|
|
108
|
-
print(f"Descendant: {descendant.
|
|
108
|
+
print(f"Descendant: {descendant.node_type}")
|
|
109
109
|
|
|
110
110
|
# Get file containing a node
|
|
111
|
-
stmt_node = ast.first_node(lambda n: n.
|
|
111
|
+
stmt_node = ast.first_node(lambda n: n.node_type == "Stmt_Function")
|
|
112
112
|
file_node = ast.get_file(stmt_node.id)
|
|
113
113
|
if file_node:
|
|
114
114
|
print(f"Function is in: {file_node.get_property('filePath')}")
|
|
@@ -189,10 +189,12 @@ ast = parser.parse("<?php echo 'hello';")
|
|
|
189
189
|
|
|
190
190
|
- **`Node`**: Wraps a single AST node
|
|
191
191
|
- `id`: Node identifier
|
|
192
|
-
- `
|
|
193
|
-
- `
|
|
194
|
-
- `properties`: All node properties
|
|
192
|
+
- `node_type`: Node type (e.g., "Stmt_Function") - returns `nodeType` property
|
|
193
|
+
- `all_properties`: All node properties as dict
|
|
195
194
|
- `get_property(*names)`: Get property value
|
|
195
|
+
- `start_line`, `end_line`: Line number properties
|
|
196
|
+
- `__getitem__(key)`: Dict-like access (e.g., `node["name"]`)
|
|
197
|
+
- `get(key, default)`: Get property with default value
|
|
196
198
|
|
|
197
199
|
- **`Parser`**: Parses PHP code
|
|
198
200
|
- `__init__(php_binary_path=None, php_binary_url=None)`: Initialize parser
|
|
@@ -213,12 +213,12 @@ class AST(AbcGraphQuerier[Node, Edge]):
|
|
|
213
213
|
# Exclude project node if it exists
|
|
214
214
|
all_nodes = set(self._storage.get_nodes())
|
|
215
215
|
nodes_with_parents = set()
|
|
216
|
-
|
|
216
|
+
|
|
217
217
|
for edge_id in self._storage.get_edges():
|
|
218
218
|
from_id, to_id, edge_type = edge_id
|
|
219
219
|
if edge_type == "PARENT_OF":
|
|
220
220
|
nodes_with_parents.add(to_id)
|
|
221
|
-
|
|
221
|
+
|
|
222
222
|
root_nodes = all_nodes - nodes_with_parents
|
|
223
223
|
# Exclude project node if present
|
|
224
224
|
root_nodes.discard(self._root_node_id)
|
|
@@ -44,34 +44,66 @@ class PrettyPrinter:
|
|
|
44
44
|
|
|
45
45
|
Returns:
|
|
46
46
|
Dictionary mapping file paths to generated PHP source code strings.
|
|
47
|
-
If AST has no file structure, returns a single entry with key "
|
|
48
|
-
|
|
47
|
+
If AST has no file structure, returns a single entry with key ""
|
|
48
|
+
as the filename.
|
|
49
49
|
|
|
50
50
|
Raises:
|
|
51
51
|
RunnerError: If PHP-Parser execution fails.
|
|
52
52
|
"""
|
|
53
53
|
file_nodes = ast.files()
|
|
54
|
-
|
|
54
|
+
|
|
55
55
|
if not file_nodes:
|
|
56
56
|
# No file structure - export all statements as a single code block
|
|
57
57
|
json_str = ast.to_json()
|
|
58
58
|
code = self._runner.print(json_str)
|
|
59
59
|
return {"": code}
|
|
60
|
-
|
|
60
|
+
|
|
61
61
|
# Generate code for each file
|
|
62
62
|
result: dict[str, str] = {}
|
|
63
63
|
for file_node in file_nodes:
|
|
64
64
|
file_path = file_node.get_property("filePath", "")
|
|
65
65
|
file_hash = file_node.id
|
|
66
|
-
|
|
66
|
+
|
|
67
67
|
# Get JSON for this file only
|
|
68
68
|
json_str = ast.to_json(file_hash=file_hash)
|
|
69
|
-
|
|
69
|
+
|
|
70
70
|
# Generate code
|
|
71
71
|
code = self._runner.print(json_str)
|
|
72
|
-
|
|
72
|
+
|
|
73
73
|
# Use file path as key, or file hash if path not available
|
|
74
74
|
key = file_path if file_path else file_hash
|
|
75
75
|
result[key] = code
|
|
76
|
-
|
|
76
|
+
|
|
77
77
|
return result
|
|
78
|
+
|
|
79
|
+
def print_file(self, ast: AST, relative_path: str) -> str:
|
|
80
|
+
"""Generate PHP code string for a single file selected by relative path.
|
|
81
|
+
|
|
82
|
+
This method looks up the file node whose ``path`` property matches the
|
|
83
|
+
given relative path (as stored on file nodes), reconstructs JSON for
|
|
84
|
+
that file only, and returns the generated PHP source code string.
|
|
85
|
+
|
|
86
|
+
Args:
|
|
87
|
+
ast: AST instance containing project and file nodes.
|
|
88
|
+
relative_path: Relative file path stored in the ``path`` property
|
|
89
|
+
of the target file node (for example, ``"src/file.php"`` or
|
|
90
|
+
just ``"file.php"`` for single-file projects).
|
|
91
|
+
|
|
92
|
+
Returns:
|
|
93
|
+
Generated PHP source code string for the specified file.
|
|
94
|
+
|
|
95
|
+
Raises:
|
|
96
|
+
KeyError: If no file node with the given relative path exists
|
|
97
|
+
in the AST.
|
|
98
|
+
RunnerError: If PHP-Parser execution fails.
|
|
99
|
+
"""
|
|
100
|
+
# Find file node by its relative path property
|
|
101
|
+
for file_node in ast.files():
|
|
102
|
+
if file_node.get_property("path") == relative_path:
|
|
103
|
+
file_hash = file_node.id
|
|
104
|
+
json_str = ast.to_json(file_hash=file_hash)
|
|
105
|
+
return self._runner.print(json_str)
|
|
106
|
+
|
|
107
|
+
raise KeyError(
|
|
108
|
+
f"File with relative path '{relative_path}' not found in AST."
|
|
109
|
+
)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{php_parser_py-1.0.0 → php_parser_py-1.1.0}/src/php_parser_py/resources/php-parser-4.19.4.zip
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|