-
Notifications
You must be signed in to change notification settings - Fork 72
/
Copy pathindex.js
239 lines (223 loc) · 6.19 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
/**
* Copyright (C) 2020 Glayzzle (BSD3 License)
* @authors https://github.com/glayzzle/php-parser/graphs/contributors
* @url http://glayzzle.com
*/
"use strict";
const lexer = require("./lexer");
const parser = require("./parser");
const tokens = require("./tokens");
const AST = require("./ast");
/**
* @private
*/
function combine(src, to) {
const keys = Object.keys(src);
let i = keys.length;
while (i--) {
const k = keys[i];
const val = src[k];
if (val === null) {
delete to[k];
} else if (typeof val === "function") {
to[k] = val.bind(to);
} else if (Array.isArray(val)) {
to[k] = Array.isArray(to[k]) ? to[k].concat(val) : val;
} else if (typeof val === "object") {
to[k] = typeof to[k] === "object" ? combine(val, to[k]) : val;
} else {
to[k] = val;
}
}
return to;
}
/**
* Initialise a new parser instance with the specified options
*
* @class
* @memberOf module:php-parser
* @tutorial Engine
* @example
* var parser = require('php-parser');
* var instance = new parser({
* parser: {
* extractDoc: true,
* suppressErrors: true,
* version: 704 // or '7.4'
* },
* ast: {
* withPositions: true
* },
* lexer: {
* short_tags: true,
* asp_tags: true
* }
* });
*
* var evalAST = instance.parseEval('some php code');
* var codeAST = instance.parseCode('<?php some php code', 'foo.php');
* var tokens = instance.tokenGetAll('<?php some php code');
*
* @param {Object} options - List of options
* @property {Lexer} lexer
* @property {Parser} parser
* @property {AST} ast
* @property {Object} tokens
*/
const Engine = function (options) {
if (typeof this === "function") {
return new this(options);
}
this.tokens = tokens;
this.lexer = new lexer(this);
this.ast = new AST();
this.parser = new parser(this.lexer, this.ast);
if (options && typeof options === "object") {
// disable php7 from lexer if already disabled from parser
if (options.parser) {
if (!options.lexer) {
options.lexer = {};
}
if (options.parser.version) {
if (typeof options.parser.version === "string") {
let version = options.parser.version.split(".");
version = parseInt(version[0]) * 100 + parseInt(version[1]);
if (isNaN(version)) {
throw new Error("Bad version number : " + options.parser.version);
} else {
options.parser.version = version;
}
} else if (typeof options.parser.version !== "number") {
throw new Error("Expecting a number for version");
}
if (options.parser.version < 500 || options.parser.version > 900) {
throw new Error("Can only handle versions between 5.x to 8.x");
}
}
}
combine(options, this);
// same version flags based on parser options
this.lexer.version = this.parser.version;
}
};
/**
* Check if the inpyt is a buffer or a string
* @private
* @param {Buffer|String} buffer Input value that can be either a buffer or a string
* @return {String} Returns the string from input
*/
const getStringBuffer = function (buffer) {
return typeof buffer.write === "function" ? buffer.toString() : buffer;
};
/**
* Creates a new instance (Helper)
* @param {Object} options
* @return {Engine}
* @private
*/
Engine.create = function (options) {
return new Engine(options);
};
/**
* Evaluate the buffer
* @private
*/
Engine.parseEval = function (buffer, options) {
const self = new Engine(options);
return self.parseEval(buffer);
};
/**
* Parse an evaluating mode string (no need to open php tags)
* @param {String} buffer
* @return {Program}
*/
Engine.prototype.parseEval = function (buffer) {
this.lexer.mode_eval = true;
this.lexer.all_tokens = false;
buffer = getStringBuffer(buffer);
return this.parser.parse(buffer, "eval");
};
/**
* Static function that parse a php code with open/close tags
* @private
*/
Engine.parseCode = function (buffer, filename, options) {
if (typeof filename === "object" && !options) {
// retro-compatibility
options = filename;
filename = "unknown";
}
const self = new Engine(options);
return self.parseCode(buffer, filename);
};
/**
* Function that parse a php code with open/close tags
*
* Sample code :
* ```php
* <?php $x = 1;
* ```
*
* Usage :
* ```js
* var parser = require('php-parser');
* var phpParser = new parser({
* // some options
* });
* var ast = phpParser.parseCode('...php code...', 'foo.php');
* ```
* @param {String} buffer - The code to be parsed
* @param {String} filename - Filename
* @return {Program}
*/
Engine.prototype.parseCode = function (buffer, filename) {
this.lexer.mode_eval = false;
this.lexer.all_tokens = false;
buffer = getStringBuffer(buffer);
return this.parser.parse(buffer, filename);
};
/**
* Split the buffer into tokens
* @private
*/
Engine.tokenGetAll = function (buffer, options) {
const self = new Engine(options);
return self.tokenGetAll(buffer);
};
/**
* Extract tokens from the specified buffer.
* > Note that the output tokens are *STRICLY* similar to PHP function `token_get_all`
* @param {string} buffer
* @return {Array<string|string[]>} - Each item can be a string or an array with following informations [token_name, text, line_number]
*/
Engine.prototype.tokenGetAll = function (buffer) {
this.lexer.mode_eval = false;
this.lexer.all_tokens = true;
buffer = getStringBuffer(buffer);
const EOF = this.lexer.EOF;
const names = this.tokens.values;
this.lexer.setInput(buffer);
let token = this.lexer.lex() || EOF;
const result = [];
while (token != EOF) {
let entry = this.lexer.yytext;
if (Object.prototype.hasOwnProperty.call(names, token)) {
entry = [names[token], entry, this.lexer.yylloc.first_line];
}
result.push(entry);
token = this.lexer.lex() || EOF;
}
return result;
};
/** @module php-parser */
// exports the function
module.exports = Engine;
// makes libraries public
module.exports.tokens = tokens;
module.exports.lexer = lexer;
module.exports.AST = AST;
module.exports.parser = parser;
module.exports.combine = combine;
module.exports.Engine = Engine;
// allow the default export in index.d.ts
module.exports.default = Engine;