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

repl: refactor to use more primordials #36264

Closed
wants to merge 1 commit into from
Closed
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
15 changes: 10 additions & 5 deletions lib/internal/repl/await.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
'use strict';

const {
ArrayFrom,
ArrayPrototypeJoin,
ArrayPrototypePop,
ArrayPrototypePush,
FunctionPrototype,
ObjectKeys,
} = primordials;

Expand All @@ -19,7 +24,7 @@ const parser = acorn.Parser.extend(
staticClassFeatures
);

const noop = () => {};
const noop = FunctionPrototype;
const visitorsWithoutAncestors = {
ClassDeclaration(node, state, c) {
if (state.ancestors[state.ancestors.length - 2] === state.body) {
Expand Down Expand Up @@ -76,18 +81,18 @@ for (const nodeType of ObjectKeys(walk.base)) {
visitors[nodeType] = (node, state, c) => {
const isNew = node !== state.ancestors[state.ancestors.length - 1];
if (isNew) {
state.ancestors.push(node);
ArrayPrototypePush(state.ancestors, node);
}
callback(node, state, c);
if (isNew) {
state.ancestors.pop();
ArrayPrototypePop(state.ancestors);
}
};
}

function processTopLevelAwait(src) {
const wrapped = `(async () => { ${src} })()`;
const wrappedArray = wrapped.split('');
const wrappedArray = ArrayFrom(wrapped);
let root;
try {
root = parser.parse(wrapped, { ecmaVersion: 'latest' });
Expand Down Expand Up @@ -142,7 +147,7 @@ function processTopLevelAwait(src) {
state.append(last.expression, ')');
}

return wrappedArray.join('');
return ArrayPrototypeJoin(wrappedArray, '');
}

module.exports = {
Expand Down
14 changes: 10 additions & 4 deletions lib/internal/repl/history.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
'use strict';

const {
ArrayPrototypeJoin,
Boolean,
FunctionPrototype,
StringPrototypeSplit,
StringPrototypeTrim,
} = primordials;

const { Interface } = require('readline');
Expand All @@ -13,6 +17,8 @@ let debug = require('internal/util/debuglog').debuglog('repl', (fn) => {
});
const { clearTimeout, setTimeout } = require('timers');

const noop = FunctionPrototype;

// XXX(chrisdickinson): The 15ms debounce value is somewhat arbitrary.
// The debounce is to guard against code pasted into the REPL.
const kDebounceHistoryMS = 15;
Expand All @@ -27,7 +33,7 @@ function _writeToOutput(repl, message) {
function setupHistory(repl, historyPath, ready) {
// Empty string disables persistent history
if (typeof historyPath === 'string')
historyPath = historyPath.trim();
historyPath = StringPrototypeTrim(historyPath);

if (historyPath === '') {
repl._historyPrev = _replHistoryMessage;
Expand Down Expand Up @@ -84,7 +90,7 @@ function setupHistory(repl, historyPath, ready) {
}

if (data) {
repl.history = data.split(/[\n\r]+/, repl.historySize);
repl.history = StringPrototypeSplit(data, /[\n\r]+/, repl.historySize);
} else {
repl.history = [];
}
Expand Down Expand Up @@ -128,7 +134,7 @@ function setupHistory(repl, historyPath, ready) {
return;
}
writing = true;
const historyData = repl.history.join(os.EOL);
const historyData = ArrayPrototypeJoin(repl.history, os.EOL);
fs.write(repl._historyHandle, historyData, 0, 'utf8', onwritten);
}

Expand All @@ -151,7 +157,7 @@ function setupHistory(repl, historyPath, ready) {
return;
}
repl.off('line', online);
fs.close(repl._historyHandle, () => {});
fs.close(repl._historyHandle, noop);
}
}

Expand Down
72 changes: 48 additions & 24 deletions lib/internal/repl/utils.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,22 @@
'use strict';

const {
ArrayPrototypeFilter,
ArrayPrototypeIncludes,
ArrayPrototypeMap,
Boolean,
FunctionPrototypeBind,
MathMin,
Set,
RegExpPrototypeTest,
SafeSet,
StringPrototypeEndsWith,
StringPrototypeIndexOf,
StringPrototypeLastIndexOf,
StringPrototypeReplace,
StringPrototypeSlice,
StringPrototypeStartsWith,
StringPrototypeToLowerCase,
StringPrototypeTrim,
Symbol,
} = primordials;

Expand Down Expand Up @@ -59,7 +73,9 @@ function isRecoverableError(e, code) {
// 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;
if (RegExpPrototypeTest(/^\s*\{/, code) &&
isRecoverableError(e, `(${code}`))
return true;

let recoverable = false;

Expand Down Expand Up @@ -99,9 +115,11 @@ function isRecoverableError(e, code) {
break;

case 'Unterminated string constant':
const token = this.input.slice(this.lastTokStart, this.pos);
const token = StringPrototypeSlice(this.input,
this.lastTokStart, this.pos);
// See https://www.ecma-international.org/ecma-262/#sec-line-terminators
if (/\\(?:\r\n?|\n|\u2028|\u2029)$/.test(token)) {
if (RegExpPrototypeTest(/\\(?:\r\n?|\n|\u2028|\u2029)$/,
token)) {
recoverable = true;
}
}
Expand Down Expand Up @@ -235,15 +253,15 @@ function setupPreview(repl, contextSymbol, bufferSymbol, active) {
hasCompletions = true;

// If there is a common prefix to all matches, then apply that portion.
const completions = rawCompletions.filter((e) => e);
const completions = ArrayPrototypeFilter(rawCompletions, Boolean);
const prefix = commonPrefix(completions);

// No common prefix found.
if (prefix.length <= completeOn.length) {
return;
}

const suffix = prefix.slice(completeOn.length);
const suffix = StringPrototypeSlice(prefix, completeOn.length);

if (insertPreview) {
repl._insertString(suffix);
Expand Down Expand Up @@ -271,16 +289,22 @@ function setupPreview(repl, contextSymbol, bufferSymbol, active) {
}

function isInStrictMode(repl) {
return repl.replMode === REPL_MODE_STRICT || process.execArgv
.map((e) => e.toLowerCase().replace(/_/g, '-'))
.includes('--use-strict');
return repl.replMode === REPL_MODE_STRICT || ArrayPrototypeIncludes(
ArrayPrototypeMap(process.execArgv,
(e) => StringPrototypeReplace(
StringPrototypeToLowerCase(e),
/_/g,
'-'
)),
'--use-strict');
}

// This returns a code preview for arbitrary input code.
function getInputPreview(input, callback) {
// For similar reasons as `defaultEval`, wrap expressions starting with a
// curly brace with parenthesis.
if (input.startsWith('{') && !input.endsWith(';') && !wrapped) {
if (StringPrototypeStartsWith(input, '{') &&
!StringPrototypeEndsWith(input, ';') && !wrapped) {
input = `(${input})`;
wrapped = true;
}
Expand Down Expand Up @@ -346,7 +370,7 @@ function setupPreview(repl, contextSymbol, bufferSymbol, active) {
return;
}

const line = repl.line.trim();
const line = StringPrototypeTrim(repl.line);

// Do not preview in case the line only contains whitespace.
if (line === '') {
Expand Down Expand Up @@ -412,9 +436,9 @@ function setupPreview(repl, contextSymbol, bufferSymbol, active) {

// Line breaks are very rare and probably only occur in case of error
// messages with line breaks.
const lineBreakPos = inspected.indexOf('\n');
const lineBreakPos = StringPrototypeIndexOf(inspected, '\n');
if (lineBreakPos !== -1) {
inspected = `${inspected.slice(0, lineBreakPos)}`;
inspected = `${StringPrototypeSlice(inspected, 0, lineBreakPos)}`;
}

const result = repl.useColors ?
Expand Down Expand Up @@ -452,7 +476,7 @@ function setupPreview(repl, contextSymbol, bufferSymbol, active) {
// Refresh prints the whole screen again and the preview will be removed
// during that procedure. Print the preview again. This also makes sure
// the preview is always correct after resizing the terminal window.
const originalRefresh = repl._refreshLine.bind(repl);
const originalRefresh = FunctionPrototypeBind(repl._refreshLine, repl);
repl._refreshLine = () => {
inputPreview = null;
originalRefresh();
Expand All @@ -462,7 +486,7 @@ function setupPreview(repl, contextSymbol, bufferSymbol, active) {
let insertCompletionPreview = true;
// Insert the longest common suffix of the current input in case the user
// moves to the right while already being at the current input end.
const originalMoveCursor = repl._moveCursor.bind(repl);
const originalMoveCursor = FunctionPrototypeBind(repl._moveCursor, repl);
repl._moveCursor = (dx) => {
const currentCursor = repl.cursor;
originalMoveCursor(dx);
Expand All @@ -476,7 +500,7 @@ function setupPreview(repl, contextSymbol, bufferSymbol, active) {

// This is the only function that interferes with the completion insertion.
// Monkey patch it to prevent inserting the completion when it shouldn't be.
const originalClearLine = repl.clearLine.bind(repl);
const originalClearLine = FunctionPrototypeBind(repl.clearLine, repl);
repl.clearLine = () => {
insertCompletionPreview = false;
originalClearLine();
Expand All @@ -492,7 +516,7 @@ function setupReverseSearch(repl) {
return { reverseSearch() { return false; } };
}

const alreadyMatched = new Set();
const alreadyMatched = new SafeSet();
const labels = {
r: 'bck-i-search: ',
s: 'fwd-i-search: '
Expand Down Expand Up @@ -556,18 +580,18 @@ function setupReverseSearch(repl) {
if (cursor === -1) {
cursor = entry.length;
}
cursor = entry.lastIndexOf(input, cursor - 1);
cursor = StringPrototypeLastIndexOf(entry, input, cursor - 1);
} else {
cursor = entry.indexOf(input, cursor + 1);
cursor = StringPrototypeIndexOf(entry, input, cursor + 1);
}
// Match not found.
if (cursor === -1) {
goToNextHistoryIndex();
// Match found.
} else {
if (repl.useColors) {
const start = entry.slice(0, cursor);
const end = entry.slice(cursor + input.length);
const start = StringPrototypeSlice(entry, 0, cursor);
const end = StringPrototypeSlice(entry, cursor + input.length);
entry = `${start}\x1B[4m${input}\x1B[24m${end}`;
}
print(entry, `${labels[dir]}${input}_`, cursor);
Expand Down Expand Up @@ -610,7 +634,7 @@ function setupReverseSearch(repl) {
// tick end instead of after each operation.
let rows = 0;
if (lastMatch !== -1) {
const line = repl.history[lastMatch].slice(0, lastCursor);
const line = StringPrototypeSlice(repl.history[lastMatch], 0, lastCursor);
rows = repl._getDisplayPos(`${repl.getPrompt()}${line}`).rows;
cursorTo(repl.output, promptPos.cols);
} else if (isInReverseSearch && repl.line !== '') {
Expand All @@ -632,7 +656,7 @@ function setupReverseSearch(repl) {
// To know exactly how many rows we have to move the cursor back we need the
// cursor rows, the output rows and the input rows.
const prompt = repl.getPrompt();
const cursorLine = `${prompt}${outputLine.slice(0, cursor)}`;
const cursorLine = prompt + StringPrototypeSlice(outputLine, 0, cursor);
const cursorPos = repl._getDisplayPos(cursorLine);
const outputPos = repl._getDisplayPos(`${prompt}${outputLine}`);
const inputPos = repl._getDisplayPos(inputLine);
Expand Down Expand Up @@ -690,7 +714,7 @@ function setupReverseSearch(repl) {
search();
} else if (key.name === 'backspace' ||
(key.ctrl && (key.name === 'h' || key.name === 'w'))) {
reset(input.slice(0, input.length - 1));
reset(StringPrototypeSlice(input, 0, input.length - 1));
search();
// Special handle <ctrl> + c and escape. Those should only cancel the
// reverse search. The original line is visible afterwards again.
Expand Down
Loading