forked from nodejs/node
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathutils.js
More file actions
186 lines (164 loc) · 6.07 KB
/
Copy pathutils.js
File metadata and controls
186 lines (164 loc) · 6.07 KB
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
'use strict';
const acorn = require('internal/deps/acorn/acorn/dist/acorn');
const privateMethods =
require('internal/deps/acorn-plugins/acorn-private-methods/index');
const classFields =
require('internal/deps/acorn-plugins/acorn-class-fields/index');
const numericSeparator =
require('internal/deps/acorn-plugins/acorn-numeric-separator/index');
const staticClassFeatures =
require('internal/deps/acorn-plugins/acorn-static-class-features/index');
const { tokTypes: tt, Parser: AcornParser } = acorn;
const util = require('util');
const debug = require('internal/util/debuglog').debuglog('repl');
// If the error is that we've unexpectedly ended the input,
// then let the user try to recover by adding more input.
// Note: `e` (the original exception) is not used by the current implementation,
// but may be needed in the future.
function isRecoverableError(e, code) {
// For similar reasons as `defaultEval`, wrap expressions starting with a
// curly brace with parenthesis. Note: only the open parenthesis is added
// here as the point is to test for potentially valid but incomplete
// expressions.
if (/^\s*\{/.test(code) && isRecoverableError(e, `(${code}`)) return true;
let recoverable = false;
// Determine if the point of any error raised is at the end of the input.
// There are two cases to consider:
//
// 1. Any error raised after we have encountered the 'eof' token.
// This prevents us from declaring partial tokens (like '2e') as
// recoverable.
//
// 2. Three cases where tokens can legally span lines. This is
// template, comment, and strings with a backslash at the end of
// the line, indicating a continuation. Note that we need to look
// for the specific errors of 'unterminated' kind (not, for example,
// a syntax error in a ${} expression in a template), and the only
// way to do that currently is to look at the message. Should Acorn
// change these messages in the future, this will lead to a test
// failure, indicating that this code needs to be updated.
//
const RecoverableParser = AcornParser
.extend(
privateMethods,
classFields,
numericSeparator,
staticClassFeatures,
(Parser) => {
return class extends Parser {
nextToken() {
super.nextToken();
if (this.type === tt.eof)
recoverable = true;
}
raise(pos, message) {
switch (message) {
case 'Unterminated template':
case 'Unterminated comment':
recoverable = true;
break;
case 'Unterminated string constant':
const token = this.input.slice(this.lastTokStart, this.pos);
// See https://www.ecma-international.org/ecma-262/#sec-line-terminators
if (/\\(?:\r\n?|\n|\u2028|\u2029)$/.test(token)) {
recoverable = true;
}
}
super.raise(pos, message);
}
};
}
);
// Try to parse the code with acorn. If the parse fails, ignore the acorn
// error and return the recoverable status.
try {
RecoverableParser.parse(code, { ecmaVersion: 11 });
// Odd case: the underlying JS engine (V8, Chakra) rejected this input
// but Acorn detected no issue. Presume that additional text won't
// address this issue.
return false;
} catch {
return recoverable;
}
}
// Appends the preview of the result
// to the tty.
function appendPreview(repl, result, cursorTo, clearScreenDown) {
repl.previewResult = `\u001b[90m // ${result}\u001b[39m`;
const line = `${repl._prompt}${repl.line} //${result}`;
const columns = repl.output.columns;
const hasColors = repl.output.hasColors ? repl.output.hasColors() : false;
const s = hasColors ?
`${repl._prompt}${repl.line}${repl.previewResult}` : line;
// Cursor to left edge.
cursorTo(repl.output, 0);
clearScreenDown(repl.output);
if (columns !== undefined) {
repl.output.write(line.length < columns ?
s : `${s.slice(0, columns - 3)
.replace(/\r?\n|\r/g, '')}...\u001b[39m`);
} else {
repl.output.write(s);
}
// Move back the cursor to the original position
cursorTo(repl.output, repl.cursor + repl._prompt.length);
}
function clearPreview(repl) {
if (repl.previewResult !== '') {
repl._refreshLine();
repl.previewResult = '';
}
}
// Called whenever a line changes
// in repl and the eager eval will be
// executed against the line using v8 session
let readline;
function makePreview(repl, eagerSession, eagerEvalContextId, line) {
const lazyReadline = () => {
if (!readline) readline = require('readline');
return readline;
};
const { cursorTo, clearScreenDown } = lazyReadline();
clearPreview(repl);
eagerSession.post('Runtime.evaluate', {
expression: line.toString(),
generatePreview: true,
throwOnSideEffect: true,
timeout: 500,
executionContextId: eagerEvalContextId
}, (error, previewResult) => {
if (error) {
debug(`Error while generating preview ${error}`);
return;
}
if (undefined !== previewResult.result.value) {
const value = util.inspect(previewResult.result.value);
appendPreview(repl, value, cursorTo, clearScreenDown);
return;
}
// If there is no exception and we got
// objectId in the result, stringify it
// using inspect via Runtime.callFunctionOn
if (!previewResult.exceptionDetails && previewResult.result.objectId) {
eagerSession.post('Runtime.callFunctionOn', {
functionDeclaration:
'function(arg) { return util.inspect(arg) }',
arguments: [previewResult.result],
executionContextId: eagerEvalContextId,
returnByValue: true,
}, (err, result) => {
if (!err) {
appendPreview(repl, result.result.value,
cursorTo, clearScreenDown);
} else {
debug('eager eval error', err);
}
});
}
});
}
module.exports = {
isRecoverableError,
kStandaloneREPL: Symbol('kStandaloneREPL'),
makePreview
};