@novolobos/nodevm 3.10.5

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.
@@ -0,0 +1,198 @@
1
+
2
+ const {Parser: AcornParser, isNewLine: acornIsNewLine, getLineInfo: acornGetLineInfo} = require('acorn');
3
+ const {full: acornWalkFull} = require('acorn-walk');
4
+
5
+ const INTERNAL_STATE_NAME = 'VM2_INTERNAL_STATE_DO_NOT_USE_OR_PROGRAM_WILL_FAIL';
6
+
7
+ function assertType(node, type) {
8
+ if (!node) throw new Error(`None existent node expected '${type}'`);
9
+ if (node.type !== type) throw new Error(`Invalid node type '${node.type}' expected '${type}'`);
10
+ return node;
11
+ }
12
+
13
+ function makeNiceSyntaxError(message, code, filename, location, tokenizer) {
14
+ const loc = acornGetLineInfo(code, location);
15
+ let end = location;
16
+ while (end < code.length && !acornIsNewLine(code.charCodeAt(end))) {
17
+ end++;
18
+ }
19
+ let markerEnd = tokenizer.start === location ? tokenizer.end : location + 1;
20
+ if (!markerEnd || markerEnd > end) markerEnd = end;
21
+ let markerLen = markerEnd - location;
22
+ if (markerLen <= 0) markerLen = 1;
23
+ if (message === 'Unexpected token') {
24
+ const type = tokenizer.type;
25
+ if (type.label === 'name' || type.label === 'privateId') {
26
+ message = 'Unexpected identifier';
27
+ } else if (type.label === 'eof') {
28
+ message = 'Unexpected end of input';
29
+ } else if (type.label === 'num') {
30
+ message = 'Unexpected number';
31
+ } else if (type.label === 'string') {
32
+ message = 'Unexpected string';
33
+ } else if (type.label === 'regexp') {
34
+ message = 'Unexpected token \'/\'';
35
+ markerLen = 1;
36
+ } else {
37
+ const token = tokenizer.value || type.label;
38
+ message = `Unexpected token '${token}'`;
39
+ }
40
+ }
41
+ const error = new SyntaxError(message);
42
+ if (!filename) return error;
43
+ const line = code.slice(location - loc.column, end);
44
+ const marker = line.slice(0, loc.column).replace(/\S/g, ' ') + '^'.repeat(markerLen);
45
+ error.stack = `${filename}:${loc.line}\n${line}\n${marker}\n\n${error.stack}`;
46
+ return error;
47
+ }
48
+
49
+ function transformer(args, body, isAsync, isGenerator, filename) {
50
+ let code;
51
+ let argsOffset;
52
+ if (args === null) {
53
+ code = body;
54
+ // Note: Keywords are not allows to contain u escapes
55
+ if (!/\b(?:catch|import|async)\b/.test(code)) {
56
+ return {__proto__: null, code, hasAsync: false};
57
+ }
58
+ } else {
59
+ code = isAsync ? '(async function' : '(function';
60
+ if (isGenerator) code += '*';
61
+ code += ' anonymous(';
62
+ code += args;
63
+ argsOffset = code.length;
64
+ code += '\n) {\n';
65
+ code += body;
66
+ code += '\n})';
67
+ }
68
+
69
+ const parser = new AcornParser({
70
+ __proto__: null,
71
+ ecmaVersion: 2022,
72
+ allowAwaitOutsideFunction: args === null && isAsync,
73
+ allowReturnOutsideFunction: args === null
74
+ }, code);
75
+ let ast;
76
+ try {
77
+ ast = parser.parse();
78
+ } catch (e) {
79
+ // Try to generate a nicer error message.
80
+ if (e instanceof SyntaxError && e.pos !== undefined) {
81
+ let message = e.message;
82
+ const match = message.match(/^(.*) \(\d+:\d+\)$/);
83
+ if (match) message = match[1];
84
+ e = makeNiceSyntaxError(message, code, filename, e.pos, parser);
85
+ }
86
+ throw e;
87
+ }
88
+
89
+ if (args !== null) {
90
+ const pBody = assertType(ast, 'Program').body;
91
+ if (pBody.length !== 1) throw new SyntaxError('Single function literal required');
92
+ const expr = pBody[0];
93
+ if (expr.type !== 'ExpressionStatement') throw new SyntaxError('Single function literal required');
94
+ const func = expr.expression;
95
+ if (func.type !== 'FunctionExpression') throw new SyntaxError('Single function literal required');
96
+ if (func.body.start !== argsOffset + 3) throw new SyntaxError('Unexpected end of arg string');
97
+ }
98
+
99
+ const insertions = [];
100
+ let hasAsync = false;
101
+
102
+ const TO_LEFT = -100;
103
+ const TO_RIGHT = 100;
104
+
105
+ let internStateValiable = undefined;
106
+ let tmpname = 'VM2_INTERNAL_TMPNAME';
107
+
108
+ acornWalkFull(ast, (node, state, type) => {
109
+ if (type === 'Function') {
110
+ if (node.async) hasAsync = true;
111
+ }
112
+ const nodeType = node.type;
113
+ if (nodeType === 'CatchClause') {
114
+ const param = node.param;
115
+ if (param) {
116
+ if (param.type === 'Identifier') {
117
+ const name = assertType(param, 'Identifier').name;
118
+ const cBody = assertType(node.body, 'BlockStatement');
119
+ if (cBody.body.length > 0) {
120
+ insertions.push({
121
+ __proto__: null,
122
+ pos: cBody.body[0].start,
123
+ order: TO_LEFT,
124
+ coder: () => `${name}=${INTERNAL_STATE_NAME}.handleException(${name});`
125
+ });
126
+ }
127
+ } else {
128
+ insertions.push({
129
+ __proto__: null,
130
+ pos: node.start,
131
+ order: TO_RIGHT,
132
+ coder: () => `catch(${tmpname}){${tmpname}=${INTERNAL_STATE_NAME}.handleException(${tmpname});try{throw ${tmpname};}`
133
+ });
134
+ insertions.push({
135
+ __proto__: null,
136
+ pos: node.body.end,
137
+ order: TO_LEFT,
138
+ coder: () => `}`
139
+ });
140
+ }
141
+ }
142
+ } else if (nodeType === 'WithStatement') {
143
+ insertions.push({
144
+ __proto__: null,
145
+ pos: node.object.start,
146
+ order: TO_LEFT,
147
+ coder: () => INTERNAL_STATE_NAME + '.wrapWith('
148
+ });
149
+ insertions.push({
150
+ __proto__: null,
151
+ pos: node.object.end,
152
+ order: TO_RIGHT,
153
+ coder: () => ')'
154
+ });
155
+ } else if (nodeType === 'Identifier') {
156
+ if (node.name === INTERNAL_STATE_NAME) {
157
+ if (internStateValiable === undefined || internStateValiable.start > node.start) {
158
+ internStateValiable = node;
159
+ }
160
+ } else if (node.name.startsWith(tmpname)) {
161
+ tmpname = node.name + '_UNIQUE';
162
+ }
163
+ } else if (nodeType === 'ImportExpression') {
164
+ insertions.push({
165
+ __proto__: null,
166
+ pos: node.start,
167
+ order: TO_RIGHT,
168
+ coder: () => INTERNAL_STATE_NAME + '.'
169
+ });
170
+ }
171
+ });
172
+
173
+ if (internStateValiable) {
174
+ throw makeNiceSyntaxError('Use of internal vm2 state variable', code, filename, internStateValiable.start, {
175
+ __proto__: null,
176
+ start: internStateValiable.start,
177
+ end: internStateValiable.end
178
+ });
179
+ }
180
+
181
+ if (insertions.length === 0) return {__proto__: null, code, hasAsync};
182
+
183
+ insertions.sort((a, b) => (a.pos == b.pos ? a.order - b.order : a.pos - b.pos));
184
+
185
+ let ncode = '';
186
+ let curr = 0;
187
+ for (let i = 0; i < insertions.length; i++) {
188
+ const change = insertions[i];
189
+ ncode += code.substring(curr, change.pos) + change.coder();
190
+ curr = change.pos;
191
+ }
192
+ ncode += code.substring(curr);
193
+
194
+ return {__proto__: null, code: ncode, hasAsync};
195
+ }
196
+
197
+ exports.INTERNAL_STATE_NAME = INTERNAL_STATE_NAME;
198
+ exports.transformer = transformer;