From 3431b3c0b3173d5f9d68cbb2fd66f62e2b7d10a5 Mon Sep 17 00:00:00 2001 From: Snehil Shah <130062020+Snehil-Shah@users.noreply.github.com> Date: Sun, 3 Mar 2024 23:25:59 +0000 Subject: [PATCH 01/93] feat: add auto-closing brackets & quotations in REPL Signed-off-by: Snehil Shah <130062020+Snehil-Shah@users.noreply.github.com> --- lib/node_modules/@stdlib/repl/lib/defaults.js | 3 +- lib/node_modules/@stdlib/repl/lib/main.js | 34 ++++++++++++++++++- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/lib/node_modules/@stdlib/repl/lib/defaults.js b/lib/node_modules/@stdlib/repl/lib/defaults.js index d42e673d124..4a4066c49de 100644 --- a/lib/node_modules/@stdlib/repl/lib/defaults.js +++ b/lib/node_modules/@stdlib/repl/lib/defaults.js @@ -51,7 +51,8 @@ function defaults() { 'save': '', 'load': '', 'log': '', - 'quiet': false + 'quiet': false, + 'autoClose': true }; } diff --git a/lib/node_modules/@stdlib/repl/lib/main.js b/lib/node_modules/@stdlib/repl/lib/main.js index 53b133d586e..aee21b55d2a 100644 --- a/lib/node_modules/@stdlib/repl/lib/main.js +++ b/lib/node_modules/@stdlib/repl/lib/main.js @@ -140,7 +140,8 @@ function REPL( options ) { 'load': opts.load, 'save': opts.save, 'log': opts.log, - 'quiet': opts.quiet + 'quiet': opts.quiet, + 'autoClose': opts.autoClose })); // Call the parent constructor: @@ -158,6 +159,7 @@ function REPL( options ) { setNonEnumerableReadOnly( this, '_isTTY', opts.isTTY ); setNonEnumerableReadOnly( this, '_sandbox', opts.sandbox ); setNonEnumerable( this, '_quiet', opts.quiet ); // allow this to be internally toggled + setNonEnumerable( this, '_autoClose', opts.autoClose ); // Initialize an internal data store: setNonEnumerableReadOnly( this, '_internal', {} ); @@ -235,6 +237,7 @@ function REPL( options ) { this._rli.on( 'close', onClose ); this._rli.on( 'line', onLine ); this._rli.on( 'SIGINT', onSIGINT ); + this._rli.input.on( 'keypress', onKeypress ); // Add listener for "command" events: this.on( 'command', onCommand ); @@ -268,6 +271,35 @@ function REPL( options ) { } } + /** + * Callback invoked upon a readline interface "keypress" event. + * + * @private + * @param {string} chunk - character pressed by the user + * @param {Object} key - keypress event information + */ + function onKeypress( chunk, key ) { + var brackets = { + '{': '}', + '[': ']', + '(': ')', + '\'': '\'', + '"': '"', + '`': '`' + }; + + // For ALT+ENTER keypress, add a new line in multi-line mode: + if ( key && key.name === 'return' && key.meta ) { + self._rli._insertString( '\n' ); + } + + // For a bracket/quotation input, append corresponding closing symbol + if ( self._autoClose && brackets[chunk] ) { + self._rli._insertString( brackets[chunk] ); + self._rli._moveCursor( -1 ); + } + } + /** * Callback invoked upon a readline interface "close" event. * From 81d3b7d48441838ff2a975e2971530ac688a2baa Mon Sep 17 00:00:00 2001 From: Snehil Shah <130062020+Snehil-Shah@users.noreply.github.com> Date: Sun, 3 Mar 2024 23:27:48 +0000 Subject: [PATCH 02/93] feat: add option to toggle auto-closing behavior Signed-off-by: Snehil Shah <130062020+Snehil-Shah@users.noreply.github.com> --- lib/node_modules/@stdlib/repl/lib/commands.js | 2 + .../repl/lib/commands/toggle_auto_close.js | 52 +++++++++++++++++++ .../@stdlib/repl/lib/help_text.js | 2 + 3 files changed, 56 insertions(+) create mode 100644 lib/node_modules/@stdlib/repl/lib/commands/toggle_auto_close.js diff --git a/lib/node_modules/@stdlib/repl/lib/commands.js b/lib/node_modules/@stdlib/repl/lib/commands.js index 7c279e49802..cf38123481a 100644 --- a/lib/node_modules/@stdlib/repl/lib/commands.js +++ b/lib/node_modules/@stdlib/repl/lib/commands.js @@ -61,6 +61,7 @@ var onVars = require( './commands/vars.js' ); var onVarsWorkspace = require( './commands/vars_workspace.js' ); var onWorkspace = require( './commands/workspace.js' ); var onWorkspaces = require( './commands/workspaces.js' ); +var onToggleAutoClose = require( './commands/toggle_auto_close.js' ); // MAIN // @@ -122,6 +123,7 @@ function commands( repl ) { cmds.push( [ 'rerequire', onRerequire( repl ), false ] ); cmds.push( [ 'rerun', onRerun( repl ), false ] ); cmds.push( [ 'reset', onReset( repl ), false ] ); + cmds.push( [ 'toggleAutoClose', onToggleAutoClose( repl ), false ] ); cmds.push( [ 'tutorial', onTutorial( repl ), false ] ); cmds.push( [ 'userDoc', onUserDoc( repl ), false ] ); cmds.push( [ 'vars', onVars( repl ), false ] ); diff --git a/lib/node_modules/@stdlib/repl/lib/commands/toggle_auto_close.js b/lib/node_modules/@stdlib/repl/lib/commands/toggle_auto_close.js new file mode 100644 index 00000000000..49408fe4504 --- /dev/null +++ b/lib/node_modules/@stdlib/repl/lib/commands/toggle_auto_close.js @@ -0,0 +1,52 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2024 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +/* eslint-disable no-underscore-dangle */ + +'use strict'; + +// MAIN // + +/** +* Returns a callback to be invoked upon calling the `toggleAutoClose` command. +* +* @private +* @param {REPL} repl - REPL instance +* @returns {Function} callback +*/ +function command( repl ) { + return onCommand; + + /** + * Toggles auto-closing of brackets and quotations. + * + * @private + */ + function onCommand() { + var newState = !repl._autoClose; + var message = ( newState ) ? '\nEnabled auto-closing of brackets and quotations.\n\n' : '\nDisabled auto-closing of brackets and quotations.\n\n'; + + repl._autoClose = newState; + repl._ostream.write( message ); + } +} + + +// EXPORTS // + +module.exports = command; diff --git a/lib/node_modules/@stdlib/repl/lib/help_text.js b/lib/node_modules/@stdlib/repl/lib/help_text.js index 26979f561a1..f139fb289ac 100644 --- a/lib/node_modules/@stdlib/repl/lib/help_text.js +++ b/lib/node_modules/@stdlib/repl/lib/help_text.js @@ -56,6 +56,8 @@ var MSG = [ '', ' rerun() Rerun previous commands.', '', + ' toggleAutoClose() Toggle auto-closing of brackets and quotations.', + '', ' require() Import a module, JSON, or local file.', ' rerequire() Re-import a module, JSON, or local file.', ' deeprerequire() Re-import a module and its dependencies.', From 3fbdd4ef210741ad0bde59a61eaa592cd825bd6d Mon Sep 17 00:00:00 2001 From: Snehil Shah <130062020+Snehil-Shah@users.noreply.github.com> Date: Tue, 5 Mar 2024 06:38:45 +0000 Subject: [PATCH 03/93] refactor: prevent use of private readline methods Signed-off-by: Snehil Shah <130062020+Snehil-Shah@users.noreply.github.com> --- lib/node_modules/@stdlib/repl/lib/main.js | 21 +++++++++++++------ .../@stdlib/repl/lib/process_line.js | 8 +++++++ 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/lib/node_modules/@stdlib/repl/lib/main.js b/lib/node_modules/@stdlib/repl/lib/main.js index aee21b55d2a..78ad361a371 100644 --- a/lib/node_modules/@stdlib/repl/lib/main.js +++ b/lib/node_modules/@stdlib/repl/lib/main.js @@ -207,6 +207,9 @@ function REPL( options ) { // Initialize an internal flag indicating whether a user is entering a multi-line command: setNonEnumerable( this, '_multiline_mode', false ); + // Initialize an internal flag indicating whether ALT+ENTER was pressed to trigger a multi-line command: + setNonEnumerable( this, '_trigger_multiline', false ); + // Initialize an internal flag indicating whether the REPL has been closed: setNonEnumerable( this, '_closed', false ); @@ -279,7 +282,7 @@ function REPL( options ) { * @param {Object} key - keypress event information */ function onKeypress( chunk, key ) { - var brackets = { + var symbols = { '{': '}', '[': ']', '(': ')', @@ -288,15 +291,21 @@ function REPL( options ) { '`': '`' }; - // For ALT+ENTER keypress, add a new line in multi-line mode: + // For ALT+ENTER keypress, manually enter multi-line mode: if ( key && key.name === 'return' && key.meta ) { - self._rli._insertString( '\n' ); + self._trigger_multiline = true; + self._rli.write( null, { + 'name': 'return' + }); } // For a bracket/quotation input, append corresponding closing symbol - if ( self._autoClose && brackets[chunk] ) { - self._rli._insertString( brackets[chunk] ); - self._rli._moveCursor( -1 ); + if ( self._autoClose && symbols[chunk] ) { + self._rli.write( symbols[chunk] ); + self._rli.write( null, { + 'ctrl': true, + 'name': 'b' + }); } } diff --git a/lib/node_modules/@stdlib/repl/lib/process_line.js b/lib/node_modules/@stdlib/repl/lib/process_line.js index fc97f0f127b..d720304adc9 100644 --- a/lib/node_modules/@stdlib/repl/lib/process_line.js +++ b/lib/node_modules/@stdlib/repl/lib/process_line.js @@ -65,6 +65,14 @@ function processLine( repl, line ) { repl._multiline_mode = false; // false until proven otherwise cmd = repl._cmd.join( '\n' ) + line; + if ( repl._trigger_multiline ) { + debug( 'Detected multi-line input via modifier-key. Waiting for additional lines...' ); + repl._cmd.push( line ); + repl._multiline_mode = true; + repl._trigger_multiline = false; + displayPrompt( repl, false ); + return; + } if ( RE_WHITESPACE.test( cmd ) ) { displayPrompt( repl, false ); return; From 3f5f68581eebad62814b5ed2cf6c910a35b99bb6 Mon Sep 17 00:00:00 2001 From: Snehil Shah <130062020+Snehil-Shah@users.noreply.github.com> Date: Tue, 5 Mar 2024 08:56:31 +0000 Subject: [PATCH 04/93] feat: add generic `settings` command to manage all settings Signed-off-by: Snehil Shah <130062020+Snehil-Shah@users.noreply.github.com> --- lib/node_modules/@stdlib/repl/lib/commands.js | 4 +- .../@stdlib/repl/lib/commands/settings.js | 136 ++++++++++++++++++ .../repl/lib/commands/toggle_auto_close.js | 52 ------- .../@stdlib/repl/lib/help_text.js | 6 +- lib/node_modules/@stdlib/repl/lib/main.js | 7 +- 5 files changed, 147 insertions(+), 58 deletions(-) create mode 100644 lib/node_modules/@stdlib/repl/lib/commands/settings.js delete mode 100644 lib/node_modules/@stdlib/repl/lib/commands/toggle_auto_close.js diff --git a/lib/node_modules/@stdlib/repl/lib/commands.js b/lib/node_modules/@stdlib/repl/lib/commands.js index cf38123481a..766abd0bdb6 100644 --- a/lib/node_modules/@stdlib/repl/lib/commands.js +++ b/lib/node_modules/@stdlib/repl/lib/commands.js @@ -61,7 +61,7 @@ var onVars = require( './commands/vars.js' ); var onVarsWorkspace = require( './commands/vars_workspace.js' ); var onWorkspace = require( './commands/workspace.js' ); var onWorkspaces = require( './commands/workspaces.js' ); -var onToggleAutoClose = require( './commands/toggle_auto_close.js' ); +var onSettings = require( './commands/settings.js' ); // MAIN // @@ -123,7 +123,7 @@ function commands( repl ) { cmds.push( [ 'rerequire', onRerequire( repl ), false ] ); cmds.push( [ 'rerun', onRerun( repl ), false ] ); cmds.push( [ 'reset', onReset( repl ), false ] ); - cmds.push( [ 'toggleAutoClose', onToggleAutoClose( repl ), false ] ); + cmds.push( [ 'settings', onSettings( repl ), false ] ); cmds.push( [ 'tutorial', onTutorial( repl ), false ] ); cmds.push( [ 'userDoc', onUserDoc( repl ), false ] ); cmds.push( [ 'vars', onVars( repl ), false ] ); diff --git a/lib/node_modules/@stdlib/repl/lib/commands/settings.js b/lib/node_modules/@stdlib/repl/lib/commands/settings.js new file mode 100644 index 00000000000..17e70fc1016 --- /dev/null +++ b/lib/node_modules/@stdlib/repl/lib/commands/settings.js @@ -0,0 +1,136 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2024 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +/* eslint-disable no-underscore-dangle */ + +'use strict'; + +// MODULES // + +var logger = require( 'debug' ); +var isString = require( '@stdlib/assert/is-string' ).isPrimitive; +var isBoolean = require( '@stdlib/assert/is-boolean' ); +var hasOwnProp = require( '@stdlib/assert/has-own-property' ); +var objectKeys = require( '@stdlib/utils/keys' ); +var format = require( '@stdlib/string/format' ); + + +// VARIABLES // + +var debug = logger( 'repl:command:settings' ); +var SETTINGS = { + 'autoCloseSymbols': { + 'desc': 'Auto-close brackets and quotations.' + } +}; + + +// FUNCTIONS // + +/** +* Returns settings help text. +* +* @private +* @returns {string} settings help text +*/ +function help() { + var HELP_TEXT; + var names; + var o; + var i; + + names = objectKeys( SETTINGS ); + HELP_TEXT = '\n'; + for ( i = 0; i < names.length; i++ ) { + o = SETTINGS[ names[ i ] ]; + HELP_TEXT += names[ i ] + '\n'; + HELP_TEXT += ' '; + if ( o.desc ) { + HELP_TEXT += SETTINGS[ names[ i ] ].desc; + } else { + HELP_TEXT += '(no description available)'; + } + HELP_TEXT += '\n\n'; + } + return HELP_TEXT; +} + + +// MAIN // + +/** +* Returns a callback to be invoked upon calling the `settings` command. +* +* @private +* @param {REPL} repl - REPL instance +* @returns {Function} callback +*/ +function command( repl ) { + return onCommand; + + /** + * Manages REPL settings. + * + * If no arguments are given, it prints all settings with their description. + * If one argument is given, it fetches the value of the setting with the given name and prints it. + * If two arguments are given, it updates the value of the given setting name to the given value. + * + * @private + * @param {string} [name] - Setting name + * @param {boolean} [value] - New setting value + * @throws {TypeError} First argument must be a string + * @throws {Error} Must recognize setting name + * @throws {TypeError} Second argument must be a boolean + */ + function onCommand( name, value ) { + var err; + if ( arguments.length === 0 ) { + repl._ostream.write( help() ); + return; + } + if ( !isString( name ) ) { + err = new TypeError( format( 'invalid argument. First argument must be a string. Value: `%s`.', name ) ); + debug( 'Error: %s', err.message ); + repl._ostream.write( format( 'Error: `%s`\n.', err.message ) ); + return; + } + if ( !hasOwnProp( SETTINGS, name ) ) { + err = new Error( format( 'invalid argument. Unrecognized setting. Value: `%s`.', name ) ); + debug( 'Error: %s', err.message ); + repl._ostream.write( format( 'Error: `%s`\n.', err.message ) ); + return; + } + if (arguments.length === 1) { + repl._ostream.write('\n'+repl._settings[name]+'\n\n'); + return; + } + if ( !isBoolean(value) ) { + err = new TypeError( format( 'invalid argument. Second argument must be a boolean. Value: `%s`.', name ) ); + debug( 'Error: %s', err.message ); + repl._ostream.write( format( 'Error: `%s`\n.', err.message ) ); + return; + } + repl._settings[name] = value; + repl._ostream.write( format( '\nUpdated setting %s to %s.\n\n', name, ( value ) ? 'true' : 'false' ) ); + } +} + + +// EXPORTS // + +module.exports = command; diff --git a/lib/node_modules/@stdlib/repl/lib/commands/toggle_auto_close.js b/lib/node_modules/@stdlib/repl/lib/commands/toggle_auto_close.js deleted file mode 100644 index 49408fe4504..00000000000 --- a/lib/node_modules/@stdlib/repl/lib/commands/toggle_auto_close.js +++ /dev/null @@ -1,52 +0,0 @@ -/** -* @license Apache-2.0 -* -* Copyright (c) 2024 The Stdlib Authors. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -/* eslint-disable no-underscore-dangle */ - -'use strict'; - -// MAIN // - -/** -* Returns a callback to be invoked upon calling the `toggleAutoClose` command. -* -* @private -* @param {REPL} repl - REPL instance -* @returns {Function} callback -*/ -function command( repl ) { - return onCommand; - - /** - * Toggles auto-closing of brackets and quotations. - * - * @private - */ - function onCommand() { - var newState = !repl._autoClose; - var message = ( newState ) ? '\nEnabled auto-closing of brackets and quotations.\n\n' : '\nDisabled auto-closing of brackets and quotations.\n\n'; - - repl._autoClose = newState; - repl._ostream.write( message ); - } -} - - -// EXPORTS // - -module.exports = command; diff --git a/lib/node_modules/@stdlib/repl/lib/help_text.js b/lib/node_modules/@stdlib/repl/lib/help_text.js index f139fb289ac..b0bf3ffdb04 100644 --- a/lib/node_modules/@stdlib/repl/lib/help_text.js +++ b/lib/node_modules/@stdlib/repl/lib/help_text.js @@ -56,8 +56,6 @@ var MSG = [ '', ' rerun() Rerun previous commands.', '', - ' toggleAutoClose() Toggle auto-closing of brackets and quotations.', - '', ' require() Import a module, JSON, or local file.', ' rerequire() Re-import a module, JSON, or local file.', ' deeprerequire() Re-import a module and its dependencies.', @@ -73,6 +71,10 @@ var MSG = [ ' userDoc() Add user-defined documentation.', ' clearUserDocs() Clear user-defined documentation.', '', + ' settings() List REPL settings.', + ' settings(name) Get setting\'s value.', + ' settings(name,value) Update setting with the new value.', + '', ' clearHistory() Clear the REPL history.', '', ' clear() Clear the entire REPL screen and scrollback history.', diff --git a/lib/node_modules/@stdlib/repl/lib/main.js b/lib/node_modules/@stdlib/repl/lib/main.js index 78ad361a371..a49e02dd066 100644 --- a/lib/node_modules/@stdlib/repl/lib/main.js +++ b/lib/node_modules/@stdlib/repl/lib/main.js @@ -159,7 +159,6 @@ function REPL( options ) { setNonEnumerableReadOnly( this, '_isTTY', opts.isTTY ); setNonEnumerableReadOnly( this, '_sandbox', opts.sandbox ); setNonEnumerable( this, '_quiet', opts.quiet ); // allow this to be internally toggled - setNonEnumerable( this, '_autoClose', opts.autoClose ); // Initialize an internal data store: setNonEnumerableReadOnly( this, '_internal', {} ); @@ -204,6 +203,10 @@ function REPL( options ) { // Define the current workspace: setNonEnumerable( this, '_currentWorkspace', 'base' ); + // Initialize an internal object storing user settings: + setNonEnumerable( this, '_settings', {} ); + setNonEnumerable( this._settings, 'autoCloseSymbols', true ); + // Initialize an internal flag indicating whether a user is entering a multi-line command: setNonEnumerable( this, '_multiline_mode', false ); @@ -300,7 +303,7 @@ function REPL( options ) { } // For a bracket/quotation input, append corresponding closing symbol - if ( self._autoClose && symbols[chunk] ) { + if ( self._settings.autoCloseSymbols && symbols[chunk] ) { self._rli.write( symbols[chunk] ); self._rli.write( null, { 'ctrl': true, From a6bc4e20cce260d5ddcdae0abf856018b962cba9 Mon Sep 17 00:00:00 2001 From: Snehil Shah <130062020+Snehil-Shah@users.noreply.github.com> Date: Tue, 5 Mar 2024 09:08:42 +0000 Subject: [PATCH 05/93] fix: remove autoClose from defaults Signed-off-by: Snehil Shah <130062020+Snehil-Shah@users.noreply.github.com> --- lib/node_modules/@stdlib/repl/lib/defaults.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/node_modules/@stdlib/repl/lib/defaults.js b/lib/node_modules/@stdlib/repl/lib/defaults.js index 4a4066c49de..d42e673d124 100644 --- a/lib/node_modules/@stdlib/repl/lib/defaults.js +++ b/lib/node_modules/@stdlib/repl/lib/defaults.js @@ -51,8 +51,7 @@ function defaults() { 'save': '', 'load': '', 'log': '', - 'quiet': false, - 'autoClose': true + 'quiet': false }; } From d8716d75fea3eee69d2207b54376e1ebd423f702 Mon Sep 17 00:00:00 2001 From: Snehil Shah <130062020+Snehil-Shah@users.noreply.github.com> Date: Tue, 5 Mar 2024 09:10:42 +0000 Subject: [PATCH 06/93] fix: remove `autoClose` from REPL opts Signed-off-by: Snehil Shah <130062020+Snehil-Shah@users.noreply.github.com> --- lib/node_modules/@stdlib/repl/lib/main.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/node_modules/@stdlib/repl/lib/main.js b/lib/node_modules/@stdlib/repl/lib/main.js index a49e02dd066..418702d033e 100644 --- a/lib/node_modules/@stdlib/repl/lib/main.js +++ b/lib/node_modules/@stdlib/repl/lib/main.js @@ -140,8 +140,7 @@ function REPL( options ) { 'load': opts.load, 'save': opts.save, 'log': opts.log, - 'quiet': opts.quiet, - 'autoClose': opts.autoClose + 'quiet': opts.quiet })); // Call the parent constructor: From 3ed9effb8ae1683185a4c4a68f54879a00872ffb Mon Sep 17 00:00:00 2001 From: Snehil Shah <130062020+Snehil-Shah@users.noreply.github.com> Date: Tue, 5 Mar 2024 09:18:03 +0000 Subject: [PATCH 07/93] fix: error messages Signed-off-by: Snehil Shah <130062020+Snehil-Shah@users.noreply.github.com> --- lib/node_modules/@stdlib/repl/lib/commands/settings.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/node_modules/@stdlib/repl/lib/commands/settings.js b/lib/node_modules/@stdlib/repl/lib/commands/settings.js index 17e70fc1016..87524b3bb5b 100644 --- a/lib/node_modules/@stdlib/repl/lib/commands/settings.js +++ b/lib/node_modules/@stdlib/repl/lib/commands/settings.js @@ -106,13 +106,13 @@ function command( repl ) { if ( !isString( name ) ) { err = new TypeError( format( 'invalid argument. First argument must be a string. Value: `%s`.', name ) ); debug( 'Error: %s', err.message ); - repl._ostream.write( format( 'Error: `%s`\n.', err.message ) ); + repl._ostream.write( format( 'Error: %s\n.', err.message ) ); return; } if ( !hasOwnProp( SETTINGS, name ) ) { err = new Error( format( 'invalid argument. Unrecognized setting. Value: `%s`.', name ) ); debug( 'Error: %s', err.message ); - repl._ostream.write( format( 'Error: `%s`\n.', err.message ) ); + repl._ostream.write( format( 'Error: %s\n.', err.message ) ); return; } if (arguments.length === 1) { @@ -122,7 +122,7 @@ function command( repl ) { if ( !isBoolean(value) ) { err = new TypeError( format( 'invalid argument. Second argument must be a boolean. Value: `%s`.', name ) ); debug( 'Error: %s', err.message ); - repl._ostream.write( format( 'Error: `%s`\n.', err.message ) ); + repl._ostream.write( format( 'Error: %s\n.', err.message ) ); return; } repl._settings[name] = value; From 7b7009b26fd659f00d2b88dbf8bf71856af0b1cc Mon Sep 17 00:00:00 2001 From: Snehil Shah <130062020+Snehil-Shah@users.noreply.github.com> Date: Fri, 8 Mar 2024 21:14:47 +0000 Subject: [PATCH 08/93] feat: manual multiline mode from cursor position Signed-off-by: Snehil Shah <130062020+Snehil-Shah@users.noreply.github.com> --- lib/node_modules/@stdlib/repl/lib/main.js | 23 ++++++++++++++++--- .../@stdlib/repl/lib/process_line.js | 17 +++++++++----- 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/lib/node_modules/@stdlib/repl/lib/main.js b/lib/node_modules/@stdlib/repl/lib/main.js index 418702d033e..f14d1b978fc 100644 --- a/lib/node_modules/@stdlib/repl/lib/main.js +++ b/lib/node_modules/@stdlib/repl/lib/main.js @@ -37,6 +37,7 @@ var setReadOnly = require( '@stdlib/utils/define-read-only-property' ); var properties = require( '@stdlib/utils/properties' ); var append = require( '@stdlib/utils/append' ); var format = require( '@stdlib/string/format' ); +var repeat = require( '@stdlib/string/repeat' ); var Boolean = require( '@stdlib/boolean/ctor' ); var cwd = require( '@stdlib/process/cwd' ); var readFileSync = require( '@stdlib/fs/read-file' ).sync; @@ -206,8 +207,11 @@ function REPL( options ) { setNonEnumerable( this, '_settings', {} ); setNonEnumerable( this._settings, 'autoCloseSymbols', true ); - // Initialize an internal flag indicating whether a user is entering a multi-line command: - setNonEnumerable( this, '_multiline_mode', false ); + // Initialize an internal status object for controlling multi-line mode: + setNonEnumerable( this, '_multiline_mode', {} ); + setNonEnumerable( this._multiline_mode, 'status', false ); + setNonEnumerable( this._multiline_mode, 'manual', false ); + setNonEnumerable( this._multiline_mode, 'buffer', '' ); // Initialize an internal flag indicating whether ALT+ENTER was pressed to trigger a multi-line command: setNonEnumerable( this, '_trigger_multiline', false ); @@ -284,6 +288,8 @@ function REPL( options ) { * @param {Object} key - keypress event information */ function onKeypress( chunk, key ) { + var charsAfterCursor; + var codeAfterCursor; var symbols = { '{': '}', '[': ']', @@ -295,7 +301,18 @@ function REPL( options ) { // For ALT+ENTER keypress, manually enter multi-line mode: if ( key && key.name === 'return' && key.meta ) { - self._trigger_multiline = true; + charsAfterCursor = self._rli.line.length - self._rli.cursor; + codeAfterCursor = self._rli.line.substring( self._rli.cursor ); + + // Update flag + self._multiline_mode.manual = true; + + // Store code after cursor in buffer for next line + self._multiline_mode.buffer = codeAfterCursor; + self._ostream.write( repeat( '\x1b[C', charsAfterCursor ) + repeat( '\b \b', charsAfterCursor ) ); + self._rli.line = self._rli.line.substring( 0, self._rli.cursor ); + + // Simulate `line` event self._rli.write( null, { 'name': 'return' }); diff --git a/lib/node_modules/@stdlib/repl/lib/process_line.js b/lib/node_modules/@stdlib/repl/lib/process_line.js index d720304adc9..81c85b1238c 100644 --- a/lib/node_modules/@stdlib/repl/lib/process_line.js +++ b/lib/node_modules/@stdlib/repl/lib/process_line.js @@ -25,6 +25,7 @@ var logger = require( 'debug' ); var Parser = require( 'acorn' ).Parser; var parseLoose = require( 'acorn-loose' ).parse; +var repeat = require( '@stdlib/string/repeat' ); var displayPrompt = require( './display_prompt.js' ); var drain = require( './drain.js' ); var multilinePlugin = require( './acorn_detect_multiline_input.js' ); @@ -62,15 +63,19 @@ function processLine( repl, line ) { var tmp; debug( 'Line: %s', line ); - repl._multiline_mode = false; // false until proven otherwise + repl._multiline_mode.status = false; // false until proven otherwise cmd = repl._cmd.join( '\n' ) + line; - if ( repl._trigger_multiline ) { + if ( repl._multiline_mode.manual ) { debug( 'Detected multi-line input via modifier-key. Waiting for additional lines...' ); repl._cmd.push( line ); - repl._multiline_mode = true; - repl._trigger_multiline = false; + repl._multiline_mode.status = true; + repl._multiline_mode.manual = false; displayPrompt( repl, false ); + repl._ostream.write( repl._multiline_mode.buffer ); + repl._ostream.write(repeat('\x1b[D', repl._multiline_mode.buffer.length)); + repl._rli.line = repl._multiline_mode.buffer; + repl._multiline_mode.buffer = ''; // empty buffer return; } if ( RE_WHITESPACE.test( cmd ) ) { @@ -91,7 +96,7 @@ function processLine( repl, line ) { if ( hasMultilineError( cmd, AOPTS ) ) { debug( 'Detected multi-line input. Waiting for additional lines...' ); repl._cmd.push( line ); - repl._multiline_mode = true; + repl._multiline_mode.status = true; displayPrompt( repl, false ); return; } @@ -105,7 +110,7 @@ function processLine( repl, line ) { if ( hasMultilineError( tmp, AOPTS ) ) { debug( 'Detected multi-line input. Waiting for additional lines...' ); repl._cmd.push( line ); - repl._multiline_mode = true; + repl._multiline_mode.status = true; displayPrompt( repl, false ); return; } From d0c66c615ac40f30018e7486d29251fe3601b06c Mon Sep 17 00:00:00 2001 From: Snehil Shah <130062020+Snehil-Shah@users.noreply.github.com> Date: Sat, 9 Mar 2024 22:59:45 +0530 Subject: [PATCH 09/93] remove unused flag Signed-off-by: Snehil Shah <130062020+Snehil-Shah@users.noreply.github.com> --- lib/node_modules/@stdlib/repl/lib/main.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/node_modules/@stdlib/repl/lib/main.js b/lib/node_modules/@stdlib/repl/lib/main.js index f14d1b978fc..8181ff73ead 100644 --- a/lib/node_modules/@stdlib/repl/lib/main.js +++ b/lib/node_modules/@stdlib/repl/lib/main.js @@ -213,9 +213,6 @@ function REPL( options ) { setNonEnumerable( this._multiline_mode, 'manual', false ); setNonEnumerable( this._multiline_mode, 'buffer', '' ); - // Initialize an internal flag indicating whether ALT+ENTER was pressed to trigger a multi-line command: - setNonEnumerable( this, '_trigger_multiline', false ); - // Initialize an internal flag indicating whether the REPL has been closed: setNonEnumerable( this, '_closed', false ); From 8278728231edad992d911a0288c7149d78734355 Mon Sep 17 00:00:00 2001 From: Snehil Shah <130062020+Snehil-Shah@users.noreply.github.com> Date: Wed, 13 Mar 2024 01:28:05 +0000 Subject: [PATCH 10/93] feat: handle instinctive closing symbols for improved ergonomics Signed-off-by: Snehil Shah <130062020+Snehil-Shah@users.noreply.github.com> --- lib/node_modules/@stdlib/repl/lib/main.js | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/lib/node_modules/@stdlib/repl/lib/main.js b/lib/node_modules/@stdlib/repl/lib/main.js index 8181ff73ead..7092a8d5872 100644 --- a/lib/node_modules/@stdlib/repl/lib/main.js +++ b/lib/node_modules/@stdlib/repl/lib/main.js @@ -213,6 +213,9 @@ function REPL( options ) { setNonEnumerable( this._multiline_mode, 'manual', false ); setNonEnumerable( this._multiline_mode, 'buffer', '' ); + // Initialize an internal flag indicating whether auto closing symbols is in progress + setNonEnumerable( this, '_auto_close_status', false ); + // Initialize an internal flag indicating whether the REPL has been closed: setNonEnumerable( this, '_closed', false ); @@ -321,7 +324,25 @@ function REPL( options ) { self._rli.write( null, { 'ctrl': true, 'name': 'b' - }); + } ); + self._auto_close_status = true; + return; + } + + // Handle instinctive closing symbols + if ( self._auto_close_status ) { + if ( + typeof chunk !== 'undefined' && + symbols[ self._rli.line[ self._rli.cursor - 2 ] ] === chunk + ) { + self._rli.write( null, { + 'name': 'backspace' + } ); + self._rli.write( null, { + 'name': 'right' + } ); + } + self._auto_close_status = false; } } From e4884e597697ef3a7852b99af690e865346cd76c Mon Sep 17 00:00:00 2001 From: Snehil Shah <130062020+Snehil-Shah@users.noreply.github.com> Date: Tue, 19 Mar 2024 20:20:48 +0000 Subject: [PATCH 11/93] refactor: suggestions Signed-off-by: Snehil Shah <130062020+Snehil-Shah@users.noreply.github.com> --- .../@stdlib/repl/lib/auto_match_symbols.js | 87 +++++++++++++++++++ lib/node_modules/@stdlib/repl/lib/commands.js | 2 +- .../@stdlib/repl/lib/commands/settings.js | 59 +++++++------ .../repl/lib/handle_manual_multiline.js | 74 ++++++++++++++++ .../@stdlib/repl/lib/help_text.js | 4 +- lib/node_modules/@stdlib/repl/lib/main.js | 75 +++------------- .../@stdlib/repl/lib/process_line.js | 20 ++--- 7 files changed, 217 insertions(+), 104 deletions(-) create mode 100644 lib/node_modules/@stdlib/repl/lib/auto_match_symbols.js create mode 100644 lib/node_modules/@stdlib/repl/lib/handle_manual_multiline.js diff --git a/lib/node_modules/@stdlib/repl/lib/auto_match_symbols.js b/lib/node_modules/@stdlib/repl/lib/auto_match_symbols.js new file mode 100644 index 00000000000..c54173604c9 --- /dev/null +++ b/lib/node_modules/@stdlib/repl/lib/auto_match_symbols.js @@ -0,0 +1,87 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2024 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +/* eslint-disable no-underscore-dangle */ + +'use strict'; + +// VARIABLES // + +var SYMBOLS = { + '{': '}', + '[': ']', + '(': ')', + '\'': '\'', + '"': '"', + '`': '`' +}; + + +// MAIN // + +/** +* Returns a callback that handles auto matching symbols. +* +* @private +* @param {REPL} repl - REPL instance +* @returns {Function} callback +*/ +function autoMatch( repl ) { + return onKeypress; + + /** + * Callback invoked upon a readline interface "keypress" event. + * + * @private + * @param {string} chunk - character pressed by the user + */ + function onKeypress( chunk ) { + if ( repl._settings.autoMatch && chunk ) { + // For a bracket/quotation input, append corresponding closing symbol + if ( SYMBOLS[chunk] ) { + repl._rli.write( SYMBOLS[chunk] ); + repl._rli.write( null, { + 'ctrl': true, + 'name': 'b' + } ); + repl._auto_match_status = true; + return; + } + + // Handle instinctive closing symbols + if ( repl._auto_match_status ) { + if ( + SYMBOLS[ repl._rli.line[ repl._rli.cursor - 2 ] ] === chunk + ) { + repl._rli.write( null, { + 'name': 'backspace' + } ); + repl._rli.write( null, { + 'name': 'right' + } ); + } + repl._auto_match_status = false; + } + } + } +} + + +// EXPORTS // + +module.exports = autoMatch; diff --git a/lib/node_modules/@stdlib/repl/lib/commands.js b/lib/node_modules/@stdlib/repl/lib/commands.js index 766abd0bdb6..e065d0d0d86 100644 --- a/lib/node_modules/@stdlib/repl/lib/commands.js +++ b/lib/node_modules/@stdlib/repl/lib/commands.js @@ -55,13 +55,13 @@ var onRenameWorkspace = require( './commands/rename_workspace.js' ); var onRerequire = require( './commands/rerequire.js' ); var onRerun = require( './commands/rerun.js' ); var onReset = require( './commands/reset.js' ); +var onSettings = require( './commands/settings.js' ); var onTutorial = require( './commands/tutorial.js' ); var onUserDoc = require( './commands/user_doc.js' ); var onVars = require( './commands/vars.js' ); var onVarsWorkspace = require( './commands/vars_workspace.js' ); var onWorkspace = require( './commands/workspace.js' ); var onWorkspaces = require( './commands/workspaces.js' ); -var onSettings = require( './commands/settings.js' ); // MAIN // diff --git a/lib/node_modules/@stdlib/repl/lib/commands/settings.js b/lib/node_modules/@stdlib/repl/lib/commands/settings.js index 87524b3bb5b..49dc9b8dd00 100644 --- a/lib/node_modules/@stdlib/repl/lib/commands/settings.js +++ b/lib/node_modules/@stdlib/repl/lib/commands/settings.js @@ -24,7 +24,7 @@ var logger = require( 'debug' ); var isString = require( '@stdlib/assert/is-string' ).isPrimitive; -var isBoolean = require( '@stdlib/assert/is-boolean' ); +var isBoolean = require( '@stdlib/assert/is-boolean' ).isPrimitive; var hasOwnProp = require( '@stdlib/assert/has-own-property' ); var objectKeys = require( '@stdlib/utils/keys' ); var format = require( '@stdlib/string/format' ); @@ -34,10 +34,15 @@ var format = require( '@stdlib/string/format' ); var debug = logger( 'repl:command:settings' ); var SETTINGS = { - 'autoCloseSymbols': { - 'desc': 'Auto-close brackets and quotations.' + 'autoMatch': { + 'desc': 'Automatically insert matching brackets, parentheses, and quotes.', + 'default': true, + 'type': 'boolean' } }; +var VALIDATORS = { + 'boolean': isBoolean +}; // FUNCTIONS // @@ -46,9 +51,10 @@ var SETTINGS = { * Returns settings help text. * * @private +* @param {REPL} repl - REPL instance * @returns {string} settings help text */ -function help() { +function help( repl ) { var HELP_TEXT; var names; var o; @@ -65,6 +71,7 @@ function help() { } else { HELP_TEXT += '(no description available)'; } + HELP_TEXT += format( ' Value: %s', repl._settings[names[ i ]] ); HELP_TEXT += '\n\n'; } return HELP_TEXT; @@ -84,49 +91,49 @@ function command( repl ) { return onCommand; /** - * Manages REPL settings. - * - * If no arguments are given, it prints all settings with their description. - * If one argument is given, it fetches the value of the setting with the given name and prints it. - * If two arguments are given, it updates the value of the given setting name to the given value. - * - * @private - * @param {string} [name] - Setting name - * @param {boolean} [value] - New setting value - * @throws {TypeError} First argument must be a string - * @throws {Error} Must recognize setting name - * @throws {TypeError} Second argument must be a boolean - */ + * Manages REPL settings. + * + * If no arguments are given, it prints all settings with their description. + * If one argument is given, it fetches the value of the setting with the given name and prints it. + * If two arguments are given, it updates the value of the given setting name to the given value. + * + * @private + * @param {string} [name] - setting name + * @param {*} [value] - new setting value + */ function onCommand( name, value ) { + var validator; var err; if ( arguments.length === 0 ) { - repl._ostream.write( help() ); + repl._ostream.write( help( repl ) ); return; } if ( !isString( name ) ) { err = new TypeError( format( 'invalid argument. First argument must be a string. Value: `%s`.', name ) ); debug( 'Error: %s', err.message ); - repl._ostream.write( format( 'Error: %s\n.', err.message ) ); + repl._ostream.write( format( 'Error: %s\n', err.message ) ); return; } if ( !hasOwnProp( SETTINGS, name ) ) { err = new Error( format( 'invalid argument. Unrecognized setting. Value: `%s`.', name ) ); debug( 'Error: %s', err.message ); - repl._ostream.write( format( 'Error: %s\n.', err.message ) ); + repl._ostream.write( format( 'Error: %s\n', err.message ) ); return; } - if (arguments.length === 1) { - repl._ostream.write('\n'+repl._settings[name]+'\n\n'); + if ( arguments.length === 1 ) { + // repl._ostream.write( '\n'+repl._settings[name]+'\n\n' ); + repl._ostream.write( format( '\n%s\n\n', repl._settings[name] ) ); return; } - if ( !isBoolean(value) ) { - err = new TypeError( format( 'invalid argument. Second argument must be a boolean. Value: `%s`.', name ) ); + validator = VALIDATORS[ SETTINGS[name].type ]; + if ( !validator(value) ) { + err = new TypeError( format( 'invalid argument. Second argument must be a %s. Value: `%s`.', SETTINGS[name].type, name ) ); debug( 'Error: %s', err.message ); - repl._ostream.write( format( 'Error: %s\n.', err.message ) ); + repl._ostream.write( format( 'Error: %s\n', err.message ) ); return; } repl._settings[name] = value; - repl._ostream.write( format( '\nUpdated setting %s to %s.\n\n', name, ( value ) ? 'true' : 'false' ) ); + repl._ostream.write( format( '\nUpdated setting %s to %s.\n\n', name, String(value) ) ); } } diff --git a/lib/node_modules/@stdlib/repl/lib/handle_manual_multiline.js b/lib/node_modules/@stdlib/repl/lib/handle_manual_multiline.js new file mode 100644 index 00000000000..0a53e860708 --- /dev/null +++ b/lib/node_modules/@stdlib/repl/lib/handle_manual_multiline.js @@ -0,0 +1,74 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2024 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +/* eslint-disable no-underscore-dangle */ + +'use strict'; + +// MODULES // + +var repeat = require( '@stdlib/string/repeat' ); + + +// MAIN // + +/** +* Returns a callback that handles multiline editing using a modifier key. +* +* @private +* @param {REPL} repl - REPL instance +* @returns {Function} callback +*/ +function manualMultiline( repl ) { + return onKeypress; + + /** + * Callback invoked upon a readline interface "keypress" event. + * + * @private + * @param {string} key - key pressed by the user + */ + function onKeypress( key ) { + var charsAfterCursor; + var codeAfterCursor; + + // For ALT+ENTER keypress, manually enter multi-line mode: + if ( key && key.name === 'return' && key.meta ) { + charsAfterCursor = repl._rli.line.length - repl._rli.cursor; + codeAfterCursor = repl._rli.line.substring( repl._rli.cursor ); + + // Update flag + repl._multiline.mode = 'modifier'; + + // Store code after cursor in buffer for next line + repl._multiline.buffer = codeAfterCursor; + repl._ostream.write( repeat( '\x1b[C', charsAfterCursor ) + repeat( '\b \b', charsAfterCursor ) ); + repl._rli.line = repl._rli.line.substring( 0, repl._rli.cursor ); + + // Simulate `line` event + repl._rli.write( null, { + 'name': 'return' + }); + } + } +} + + +// EXPORTS // + +module.exports = manualMultiline; diff --git a/lib/node_modules/@stdlib/repl/lib/help_text.js b/lib/node_modules/@stdlib/repl/lib/help_text.js index b0bf3ffdb04..5a3b2368182 100644 --- a/lib/node_modules/@stdlib/repl/lib/help_text.js +++ b/lib/node_modules/@stdlib/repl/lib/help_text.js @@ -71,9 +71,7 @@ var MSG = [ ' userDoc() Add user-defined documentation.', ' clearUserDocs() Clear user-defined documentation.', '', - ' settings() List REPL settings.', - ' settings(name) Get setting\'s value.', - ' settings(name,value) Update setting with the new value.', + ' settings() View and update settings.', '', ' clearHistory() Clear the REPL history.', '', diff --git a/lib/node_modules/@stdlib/repl/lib/main.js b/lib/node_modules/@stdlib/repl/lib/main.js index 7092a8d5872..1043cf571b5 100644 --- a/lib/node_modules/@stdlib/repl/lib/main.js +++ b/lib/node_modules/@stdlib/repl/lib/main.js @@ -37,7 +37,6 @@ var setReadOnly = require( '@stdlib/utils/define-read-only-property' ); var properties = require( '@stdlib/utils/properties' ); var append = require( '@stdlib/utils/append' ); var format = require( '@stdlib/string/format' ); -var repeat = require( '@stdlib/string/repeat' ); var Boolean = require( '@stdlib/boolean/ctor' ); var cwd = require( '@stdlib/process/cwd' ); var readFileSync = require( '@stdlib/fs/read-file' ).sync; @@ -57,6 +56,8 @@ var displayPrompt = require( './display_prompt.js' ); var inputPrompt = require( './input_prompt.js' ); var processLine = require( './process_line.js' ); var completer = require( './completer.js' ); +var autoMatch = require( './auto_match_symbols.js' ); +var manualMultiline = require( './handle_manual_multiline.js' ); var ALIAS_OVERRIDES = require( './alias_overrides.js' ); @@ -205,16 +206,16 @@ function REPL( options ) { // Initialize an internal object storing user settings: setNonEnumerable( this, '_settings', {} ); - setNonEnumerable( this._settings, 'autoCloseSymbols', true ); + setNonEnumerable( this._settings, 'autoMatch', true ); // Initialize an internal status object for controlling multi-line mode: - setNonEnumerable( this, '_multiline_mode', {} ); - setNonEnumerable( this._multiline_mode, 'status', false ); - setNonEnumerable( this._multiline_mode, 'manual', false ); - setNonEnumerable( this._multiline_mode, 'buffer', '' ); + setNonEnumerable( this, '_multiline', {} ); + setNonEnumerable( this._multiline, 'active', false ); + setNonEnumerable( this._multiline, 'mode', 'incomplete_expression' ); + setNonEnumerable( this._multiline, 'buffer', '' ); - // Initialize an internal flag indicating whether auto closing symbols is in progress - setNonEnumerable( this, '_auto_close_status', false ); + // Initialize an internal flag indicating whether auto closing symbols is in progress: + setNonEnumerable( this, '_auto_match_status', false ); // Initialize an internal flag indicating whether the REPL has been closed: setNonEnumerable( this, '_closed', false ); @@ -288,62 +289,8 @@ function REPL( options ) { * @param {Object} key - keypress event information */ function onKeypress( chunk, key ) { - var charsAfterCursor; - var codeAfterCursor; - var symbols = { - '{': '}', - '[': ']', - '(': ')', - '\'': '\'', - '"': '"', - '`': '`' - }; - - // For ALT+ENTER keypress, manually enter multi-line mode: - if ( key && key.name === 'return' && key.meta ) { - charsAfterCursor = self._rli.line.length - self._rli.cursor; - codeAfterCursor = self._rli.line.substring( self._rli.cursor ); - - // Update flag - self._multiline_mode.manual = true; - - // Store code after cursor in buffer for next line - self._multiline_mode.buffer = codeAfterCursor; - self._ostream.write( repeat( '\x1b[C', charsAfterCursor ) + repeat( '\b \b', charsAfterCursor ) ); - self._rli.line = self._rli.line.substring( 0, self._rli.cursor ); - - // Simulate `line` event - self._rli.write( null, { - 'name': 'return' - }); - } - - // For a bracket/quotation input, append corresponding closing symbol - if ( self._settings.autoCloseSymbols && symbols[chunk] ) { - self._rli.write( symbols[chunk] ); - self._rli.write( null, { - 'ctrl': true, - 'name': 'b' - } ); - self._auto_close_status = true; - return; - } - - // Handle instinctive closing symbols - if ( self._auto_close_status ) { - if ( - typeof chunk !== 'undefined' && - symbols[ self._rli.line[ self._rli.cursor - 2 ] ] === chunk - ) { - self._rli.write( null, { - 'name': 'backspace' - } ); - self._rli.write( null, { - 'name': 'right' - } ); - } - self._auto_close_status = false; - } + autoMatch( self )( chunk ); + manualMultiline( self )( key ); } /** diff --git a/lib/node_modules/@stdlib/repl/lib/process_line.js b/lib/node_modules/@stdlib/repl/lib/process_line.js index 81c85b1238c..d851c06bda6 100644 --- a/lib/node_modules/@stdlib/repl/lib/process_line.js +++ b/lib/node_modules/@stdlib/repl/lib/process_line.js @@ -63,19 +63,19 @@ function processLine( repl, line ) { var tmp; debug( 'Line: %s', line ); - repl._multiline_mode.status = false; // false until proven otherwise + repl._multiline.active = false; // false until proven otherwise cmd = repl._cmd.join( '\n' ) + line; - if ( repl._multiline_mode.manual ) { + if ( repl._multiline.mode === 'modifier' ) { debug( 'Detected multi-line input via modifier-key. Waiting for additional lines...' ); repl._cmd.push( line ); - repl._multiline_mode.status = true; - repl._multiline_mode.manual = false; + repl._multiline.active = true; + repl._multiline.mode = 'incomplete_expression'; displayPrompt( repl, false ); - repl._ostream.write( repl._multiline_mode.buffer ); - repl._ostream.write(repeat('\x1b[D', repl._multiline_mode.buffer.length)); - repl._rli.line = repl._multiline_mode.buffer; - repl._multiline_mode.buffer = ''; // empty buffer + repl._ostream.write( repl._multiline.buffer ); + repl._ostream.write(repeat('\x1b[D', repl._multiline.buffer.length)); + repl._rli.line = repl._multiline.buffer; + repl._multiline.buffer = ''; // empty buffer return; } if ( RE_WHITESPACE.test( cmd ) ) { @@ -96,7 +96,7 @@ function processLine( repl, line ) { if ( hasMultilineError( cmd, AOPTS ) ) { debug( 'Detected multi-line input. Waiting for additional lines...' ); repl._cmd.push( line ); - repl._multiline_mode.status = true; + repl._multiline.active = true; displayPrompt( repl, false ); return; } @@ -110,7 +110,7 @@ function processLine( repl, line ) { if ( hasMultilineError( tmp, AOPTS ) ) { debug( 'Detected multi-line input. Waiting for additional lines...' ); repl._cmd.push( line ); - repl._multiline_mode.status = true; + repl._multiline.active = true; displayPrompt( repl, false ); return; } From 1202732a55a2722a0e6597f8cb507c4ae4b1c916 Mon Sep 17 00:00:00 2001 From: Snehil Shah <130062020+Snehil-Shah@users.noreply.github.com> Date: Tue, 19 Mar 2024 21:42:15 +0000 Subject: [PATCH 12/93] feat: add auto indentation Signed-off-by: Snehil Shah <130062020+Snehil-Shah@users.noreply.github.com> --- lib/node_modules/@stdlib/repl/lib/process_line.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/node_modules/@stdlib/repl/lib/process_line.js b/lib/node_modules/@stdlib/repl/lib/process_line.js index d851c06bda6..3fa76a267f4 100644 --- a/lib/node_modules/@stdlib/repl/lib/process_line.js +++ b/lib/node_modules/@stdlib/repl/lib/process_line.js @@ -72,9 +72,12 @@ function processLine( repl, line ) { repl._multiline.active = true; repl._multiline.mode = 'incomplete_expression'; displayPrompt( repl, false ); + if ( /\{\s*$|\[\s*$|\(\s*$/.test( line ) ) { + repl._rli.write(' '); + } repl._ostream.write( repl._multiline.buffer ); repl._ostream.write(repeat('\x1b[D', repl._multiline.buffer.length)); - repl._rli.line = repl._multiline.buffer; + repl._rli.line += repl._multiline.buffer; repl._multiline.buffer = ''; // empty buffer return; } @@ -98,6 +101,9 @@ function processLine( repl, line ) { repl._cmd.push( line ); repl._multiline.active = true; displayPrompt( repl, false ); + if ( /\{\s*$|\[\s*$|\(\s*$/.test( line ) ) { + repl._rli.write(' '); + } return; } // Still possible that a user is attempting to enter an object literal across multiple lines... From db500417d709873e22f0c362c6e8e006db835dfe Mon Sep 17 00:00:00 2001 From: Snehil Shah <130062020+Snehil-Shah@users.noreply.github.com> Date: Wed, 20 Mar 2024 04:20:56 +0000 Subject: [PATCH 13/93] feat: handle special cases to improve ergonomics Signed-off-by: Snehil Shah <130062020+Snehil-Shah@users.noreply.github.com> --- .../@stdlib/repl/lib/auto_match_symbols.js | 57 ++++++++++++++----- .../repl/lib/handle_manual_multiline.js | 2 +- lib/node_modules/@stdlib/repl/lib/main.js | 2 +- .../@stdlib/repl/lib/process_line.js | 4 +- 4 files changed, 47 insertions(+), 18 deletions(-) diff --git a/lib/node_modules/@stdlib/repl/lib/auto_match_symbols.js b/lib/node_modules/@stdlib/repl/lib/auto_match_symbols.js index c54173604c9..7707bbeb336 100644 --- a/lib/node_modules/@stdlib/repl/lib/auto_match_symbols.js +++ b/lib/node_modules/@stdlib/repl/lib/auto_match_symbols.js @@ -49,23 +49,28 @@ function autoMatch( repl ) { * * @private * @param {string} chunk - character pressed by the user + * @param {Object} key - keypress event information */ - function onKeypress( chunk ) { - if ( repl._settings.autoMatch && chunk ) { - // For a bracket/quotation input, append corresponding closing symbol - if ( SYMBOLS[chunk] ) { - repl._rli.write( SYMBOLS[chunk] ); - repl._rli.write( null, { - 'ctrl': true, - 'name': 'b' - } ); - repl._auto_match_status = true; - return; - } - - // Handle instinctive closing symbols + function onKeypress( chunk, key ) { + if ( repl._settings.autoMatch ) { + // Handle edge cases if ( repl._auto_match_status ) { + // Auto delete appended symbol when deleting input + if ( + key.name === 'backspace' + ) { + repl._rli.write( null, { + 'name': 'right' + } ); + repl._rli.write( null, { + 'name': 'backspace' + } ); + return; + } + // Discard instinctive closing symbols if ( + typeof chunk !== 'undefined' && + repl._rli.line[ repl._rli.cursor ] === chunk && SYMBOLS[ repl._rli.line[ repl._rli.cursor - 2 ] ] === chunk ) { repl._rli.write( null, { @@ -74,9 +79,33 @@ function autoMatch( repl ) { repl._rli.write( null, { 'name': 'right' } ); + repl._auto_match_status = false; + return; } repl._auto_match_status = false; } + + // For a bracket/quotation input, append corresponding closing symbol + if ( SYMBOLS[chunk] ) { + if ( + ( + SYMBOLS[chunk] === '\'' || SYMBOLS[chunk] === '"' + ) && + ( + /^[a-zA-Z0-9"'/\\]$/.test(repl._rli.line[repl._rli.cursor - 2 ]) || + /^[a-zA-Z0-9"'/\\]$/.test(repl._rli.line[repl._rli.cursor ]) + ) + ) { + // Don't auto-complete quotations around text + return; + } + repl._rli.write( SYMBOLS[chunk] ); + repl._rli.write( null, { + 'ctrl': true, + 'name': 'b' + } ); + repl._auto_match_status = true; + } } } } diff --git a/lib/node_modules/@stdlib/repl/lib/handle_manual_multiline.js b/lib/node_modules/@stdlib/repl/lib/handle_manual_multiline.js index 0a53e860708..336f3178d4a 100644 --- a/lib/node_modules/@stdlib/repl/lib/handle_manual_multiline.js +++ b/lib/node_modules/@stdlib/repl/lib/handle_manual_multiline.js @@ -41,7 +41,7 @@ function manualMultiline( repl ) { * Callback invoked upon a readline interface "keypress" event. * * @private - * @param {string} key - key pressed by the user + * @param {string} key - key event information */ function onKeypress( key ) { var charsAfterCursor; diff --git a/lib/node_modules/@stdlib/repl/lib/main.js b/lib/node_modules/@stdlib/repl/lib/main.js index 1043cf571b5..c5ad6b09d71 100644 --- a/lib/node_modules/@stdlib/repl/lib/main.js +++ b/lib/node_modules/@stdlib/repl/lib/main.js @@ -289,7 +289,7 @@ function REPL( options ) { * @param {Object} key - keypress event information */ function onKeypress( chunk, key ) { - autoMatch( self )( chunk ); + autoMatch( self )( chunk, key ); manualMultiline( self )( key ); } diff --git a/lib/node_modules/@stdlib/repl/lib/process_line.js b/lib/node_modules/@stdlib/repl/lib/process_line.js index 3fa76a267f4..08adb975f28 100644 --- a/lib/node_modules/@stdlib/repl/lib/process_line.js +++ b/lib/node_modules/@stdlib/repl/lib/process_line.js @@ -73,7 +73,7 @@ function processLine( repl, line ) { repl._multiline.mode = 'incomplete_expression'; displayPrompt( repl, false ); if ( /\{\s*$|\[\s*$|\(\s*$/.test( line ) ) { - repl._rli.write(' '); + repl._rli.write(' '); // auto-indentation } repl._ostream.write( repl._multiline.buffer ); repl._ostream.write(repeat('\x1b[D', repl._multiline.buffer.length)); @@ -102,7 +102,7 @@ function processLine( repl, line ) { repl._multiline.active = true; displayPrompt( repl, false ); if ( /\{\s*$|\[\s*$|\(\s*$/.test( line ) ) { - repl._rli.write(' '); + repl._rli.write(' '); // auto-indentation } return; } From db29963b942c37f10bbc09c3ae53010d174c448e Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Wed, 27 Mar 2024 12:33:53 -0700 Subject: [PATCH 14/93] fix: consolidate keypress listeners --- lib/node_modules/@stdlib/repl/lib/main.js | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/lib/node_modules/@stdlib/repl/lib/main.js b/lib/node_modules/@stdlib/repl/lib/main.js index 5d036209946..1dbe9924d8f 100644 --- a/lib/node_modules/@stdlib/repl/lib/main.js +++ b/lib/node_modules/@stdlib/repl/lib/main.js @@ -255,7 +255,6 @@ function REPL( options ) { this._rli.on( 'close', onClose ); this._rli.on( 'line', onLine ); this._rli.on( 'SIGINT', onSIGINT ); - this._rli.input.on( 'keypress', onKeypress ); // Add listener for "command" events: this.on( 'command', onCommand ); @@ -315,6 +314,8 @@ function REPL( options ) { */ function onKeypress( data, key ) { previewCompleter.onKeypress( data, key ); + autoMatch( self )( data, key ); + manualMultiline( self )( key ); } /** @@ -330,18 +331,6 @@ function REPL( options ) { } } - /** - * Callback invoked upon a readline interface "keypress" event. - * - * @private - * @param {string} chunk - character pressed by the user - * @param {Object} key - keypress event information - */ - function onKeypress( chunk, key ) { - autoMatch( self )( chunk, key ); - manualMultiline( self )( key ); - } - /** * Callback invoked upon a readline interface "close" event. * From 19ef85b3f4b66cf855ea0bc38bff2e7ef91013bb Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Wed, 27 Mar 2024 12:35:55 -0700 Subject: [PATCH 15/93] refactor: always attach a keypress listener --- lib/node_modules/@stdlib/repl/lib/main.js | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/lib/node_modules/@stdlib/repl/lib/main.js b/lib/node_modules/@stdlib/repl/lib/main.js index 1dbe9924d8f..f039783a5df 100644 --- a/lib/node_modules/@stdlib/repl/lib/main.js +++ b/lib/node_modules/@stdlib/repl/lib/main.js @@ -259,17 +259,17 @@ function REPL( options ) { // Add listener for "command" events: this.on( 'command', onCommand ); + // Instruct the input stream to begin emitting "keypress" events: + readline.emitKeypressEvents( this._istream, this._rli ); + + // Add a listener for "keypress" events: + this._istream.on( 'keypress', onKeypress ); + // If operating in "terminal" mode, initialize a preview completer... if ( this._isTTY ) { // Create a new preview completer: previewCompleter = new PreviewCompleter( this._rli, completer, this._ostream ); - // Instruct the input stream to begin emitting "keypress" events: - readline.emitKeypressEvents( this._istream, this._rli ); - - // Add a listener for "keypress" events: - this._istream.on( 'keypress', onKeypress ); - // Cache a reference to the private readline interface `ttyWrite` to allow calling the method when wanting default behavior: ttyWrite = this._rli._ttyWrite; @@ -313,7 +313,9 @@ function REPL( options ) { * @param {Object} key - key object */ function onKeypress( data, key ) { - previewCompleter.onKeypress( data, key ); + if ( previewCompleter ) { + previewCompleter.onKeypress( data, key ); + } autoMatch( self )( data, key ); manualMultiline( self )( key ); } From 6b865c920f1c77d51a517087808ae340d16eaeeb Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Wed, 27 Mar 2024 12:50:25 -0700 Subject: [PATCH 16/93] refactor: document `settings` command signatures --- lib/node_modules/@stdlib/repl/lib/help_text.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/node_modules/@stdlib/repl/lib/help_text.js b/lib/node_modules/@stdlib/repl/lib/help_text.js index 5a3b2368182..2daf600c19b 100644 --- a/lib/node_modules/@stdlib/repl/lib/help_text.js +++ b/lib/node_modules/@stdlib/repl/lib/help_text.js @@ -35,6 +35,10 @@ var MSG = [ ' tutorial() List tutorials.', ' tutorial(name) Run a specified tutorial.', '', + ' settings() List settings.', + ' settings(name) Return setting value.', + ' settings(name,value) Set a specified setting value.', + '', ' ans Return the result of the last executed command.', ' vars() List current workspace variable names.', ' clearVars() Delete current workspace variables.', @@ -71,8 +75,6 @@ var MSG = [ ' userDoc() Add user-defined documentation.', ' clearUserDocs() Clear user-defined documentation.', '', - ' settings() View and update settings.', - '', ' clearHistory() Clear the REPL history.', '', ' clear() Clear the entire REPL screen and scrollback history.', From 35ec9b7cb18928cda0a5881e723fb1a1c609ab54 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Wed, 27 Mar 2024 13:05:39 -0700 Subject: [PATCH 17/93] refactor: document defaults and add settings object --- lib/node_modules/@stdlib/repl/lib/defaults.js | 36 ++++++++++++++++++- lib/node_modules/@stdlib/repl/lib/main.js | 3 +- 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/lib/node_modules/@stdlib/repl/lib/defaults.js b/lib/node_modules/@stdlib/repl/lib/defaults.js index d42e673d124..9892d619c23 100644 --- a/lib/node_modules/@stdlib/repl/lib/defaults.js +++ b/lib/node_modules/@stdlib/repl/lib/defaults.js @@ -39,19 +39,53 @@ var WELCOME = require( './welcome_text.js' ); */ function defaults() { return { + // Default input stream: 'input': stdin, + + // Default output stream: 'output': stdout, + + // Input prompt: 'inputPrompt': 'In [%d]: ', + + // Output prompt: 'outputPrompt': 'Out[%d]: ', + + // Number of empty lines between successive commands: 'padding': 1, + + // Flag indicating whether the input and output streams should be treated like a TTY (terminal) and whether the REPL should use ANSI/VT100 escape codes when writing to the output stream: 'isTTY': void 0, + + // Number of milliseconds to execute a command before terminating execution: 'timeout': 4294967295, + + // Flag indicating whether to run a REPL in a sandboxed context: 'sandbox': true, + + // Welcome message: 'welcome': WELCOME, + + // File path specifying where to save REPL command history: 'save': '', + + // File path specifying a JavaScript file to load and evaluate line-by-line (e.g., a previous REPL history file): 'load': '', + + // File path specifying where to save REPL commands and printed output: 'log': '', - 'quiet': false + + // Flag indicating whether log information, confirmation messages, and other possible REPL diagnostics should be silenced: + 'quiet': false, + + // User settings: + 'settings': { + // Flag indicating whether to auto-match brackets, braces, and quotes: + 'autoMatch': true, + + // Flag indicating whether to enable the display of completion previews for auto-completion: + 'completionPreviews': true + } }; } diff --git a/lib/node_modules/@stdlib/repl/lib/main.js b/lib/node_modules/@stdlib/repl/lib/main.js index f039783a5df..e8cbed19c7b 100644 --- a/lib/node_modules/@stdlib/repl/lib/main.js +++ b/lib/node_modules/@stdlib/repl/lib/main.js @@ -146,7 +146,8 @@ function REPL( options ) { 'load': opts.load, 'save': opts.save, 'log': opts.log, - 'quiet': opts.quiet + 'quiet': opts.quiet, + 'settings': opts.settings })); // Call the parent constructor: From 357431a5de487a5e17a2b0b33de3c3adf1fd7732 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Wed, 27 Mar 2024 13:41:51 -0700 Subject: [PATCH 18/93] refactor: add module exposing settings validators --- .../@stdlib/repl/lib/settings_validators.js | 112 ++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 lib/node_modules/@stdlib/repl/lib/settings_validators.js diff --git a/lib/node_modules/@stdlib/repl/lib/settings_validators.js b/lib/node_modules/@stdlib/repl/lib/settings_validators.js new file mode 100644 index 00000000000..76445506d80 --- /dev/null +++ b/lib/node_modules/@stdlib/repl/lib/settings_validators.js @@ -0,0 +1,112 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2024 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +// MODULES // + +var isBoolean = require( '@stdlib/assert/is-boolean' ).isPrimitive; +var isString = require( '@stdlib/assert/is-string' ).isPrimitive; +var isNumber = require( '@stdlib/assert/is-number' ).isPrimitive; +var isInteger = require( '@stdlib/assert/is-integer' ).isPrimitive; +var format = require( '@stdlib/string/format' ); + + +// FUNCTIONS // + +/** +* Returns a formatted error message for a value is not a boolean. +* +* @private +* @param {string} name - setting name +* @param {*} value - invalid value +* @returns {string} formatted error message +*/ +function booleanErrMsg( name, value ) { + return format( '`%s` setting must be a boolean. Value: `%s`.', value ); +} + +/** +* Returns a formatted error message for a value is not an integer. +* +* @private +* @param {string} name - setting name +* @param {*} value - invalid value +* @returns {string} formatted error message +*/ +function integerErrMsg( name, value ) { + return format( '`%s` setting must be an integer. Value: `%s`.', value ); +} + +/** +* Returns a formatted error message for a value is not a number. +* +* @private +* @param {string} name - setting name +* @param {*} value - invalid value +* @returns {string} formatted error message +*/ +function numberErrMsg( name, value ) { + return format( '`%s` setting must be a number. Value: `%s`.', value ); +} + +/** +* Returns a formatted error message for a value is not a string. +* +* @private +* @param {string} name - setting name +* @param {*} value - invalid value +* @returns {string} formatted error message +*/ +function stringErrMsg( name, value ) { + return format( '`%s` setting must be a string. Value: `%s`.', value ); +} + + +// MAIN // + +/** +* Mapping from data types to validation functions. +* +* @private +* @name VALIDATORS +* @type {Object} +*/ +var VALIDATORS = { // eslint-disable-line vars-on-top + 'boolean': { + 'assert': isBoolean, + 'msg': booleanErrMsg + }, + 'integer': { + 'assert': isInteger, + 'msg': integerErrMsg + }, + 'number': { + 'assert': isNumber, + 'msg': numberErrMsg + }, + 'string': { + 'assert': isString, + 'msg': stringErrMsg + } +}; + + +// EXPORTS // + +module.exports = VALIDATORS; From 6e75e672c98c67fc53a93767198be7654dc1fb64 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Wed, 27 Mar 2024 13:43:21 -0700 Subject: [PATCH 19/93] refactor: add module to validate a settings object --- .../@stdlib/repl/lib/validate_settings.js | 85 +++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 lib/node_modules/@stdlib/repl/lib/validate_settings.js diff --git a/lib/node_modules/@stdlib/repl/lib/validate_settings.js b/lib/node_modules/@stdlib/repl/lib/validate_settings.js new file mode 100644 index 00000000000..59e2a9bfc3d --- /dev/null +++ b/lib/node_modules/@stdlib/repl/lib/validate_settings.js @@ -0,0 +1,85 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2024 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +// MODULES // + +var isPlainObject = require( '@stdlib/assert/is-plain-object' ); +var hasOwnProp = require( '@stdlib/assert/has-own-property' ); +var objectKeys = require( '@stdlib/utils/keys' ); +var format = require( '@stdlib/string/format' ); +var SETTINGS = require( './settings.js' ); +var VALIDATORS = require( './settings_validators.js' ); + + +// VARIABLES // + +var SETTINGS_NAMES = objectKeys( SETTINGS ); + + +// MAIN // + +/** +* Validates settings. +* +* @private +* @param {Object} opts - destination object +* @param {Object} options - settings options +* @param {boolean} [options.autoMatch] - boolean indicating whether to enable auto-match +* @param {boolean} [options.completionPreviews] - boolean indicating whether to enable completion previews +* @returns {(Error|null)} error or null +* +* @example +* var options = { +* 'autoMatch': true +* }; +* var opts = {}; +* var err = validate( opts, options ); +* if ( err ) { +* throw err; +* } +*/ +function validate( opts, options ) { + var name; + var o; + var f; + var v; + var i; + if ( !isPlainObject( options ) ) { + return new TypeError( format( 'invalid argument. Options argument must be an object. Value: `%s`.', options ) ); + } + for ( i = 0; i < SETTINGS_NAMES.length; i++ ) { + name = SETTINGS_NAMES[ i ]; + if ( hasOwnProp( options, name ) ) { + v = options[ name ]; + o = SETTINGS[ name ]; + f = VALIDATORS[ o.type ]; + if ( !f.assert( v ) ) { + return new TypeError( f.msg( name, v ) ); + } + opts[ name ] = v; + } + } + return null; +} + + +// EXPORTS // + +module.exports = validate; From 85687d302433207e88db58af983ee811eea7acf4 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Wed, 27 Mar 2024 13:45:23 -0700 Subject: [PATCH 20/93] fix: update error messages --- lib/node_modules/@stdlib/repl/lib/settings_validators.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/node_modules/@stdlib/repl/lib/settings_validators.js b/lib/node_modules/@stdlib/repl/lib/settings_validators.js index 76445506d80..a0f1b46d82d 100644 --- a/lib/node_modules/@stdlib/repl/lib/settings_validators.js +++ b/lib/node_modules/@stdlib/repl/lib/settings_validators.js @@ -38,7 +38,7 @@ var format = require( '@stdlib/string/format' ); * @returns {string} formatted error message */ function booleanErrMsg( name, value ) { - return format( '`%s` setting must be a boolean. Value: `%s`.', value ); + return format( 'invalid setting. `%s` setting must be a boolean. Value: `%s`.', value ); } /** @@ -50,7 +50,7 @@ function booleanErrMsg( name, value ) { * @returns {string} formatted error message */ function integerErrMsg( name, value ) { - return format( '`%s` setting must be an integer. Value: `%s`.', value ); + return format( 'invalid setting. `%s` setting must be an integer. Value: `%s`.', value ); } /** @@ -62,7 +62,7 @@ function integerErrMsg( name, value ) { * @returns {string} formatted error message */ function numberErrMsg( name, value ) { - return format( '`%s` setting must be a number. Value: `%s`.', value ); + return format( 'invalid setting. `%s` setting must be a number. Value: `%s`.', value ); } /** @@ -74,7 +74,7 @@ function numberErrMsg( name, value ) { * @returns {string} formatted error message */ function stringErrMsg( name, value ) { - return format( '`%s` setting must be a string. Value: `%s`.', value ); + return format( 'invalid setting. `%s` setting must be a string. Value: `%s`.', value ); } From 89f980270a4b6ea449030131bb034c6a400479a5 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Wed, 27 Mar 2024 13:48:25 -0700 Subject: [PATCH 21/93] fix: add missing settings file --- lib/node_modules/@stdlib/repl/lib/settings.js | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 lib/node_modules/@stdlib/repl/lib/settings.js diff --git a/lib/node_modules/@stdlib/repl/lib/settings.js b/lib/node_modules/@stdlib/repl/lib/settings.js new file mode 100644 index 00000000000..61e4a1c39c2 --- /dev/null +++ b/lib/node_modules/@stdlib/repl/lib/settings.js @@ -0,0 +1,44 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2024 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +// MAIN // + +/** +* REPL settings. +* +* @private +* @name SETTINGS +* @type {Object} +*/ +var SETTINGS = { + 'autoMatch': { + 'desc': 'Automatically insert matching brackets, parentheses, and quotes.', + 'type': 'boolean' + }, + 'completionPreviews': { + 'desc': 'Enable the display of completion previews for auto-completion.', + 'type': 'boolean' + } +}; + + +// EXPORTS // + +module.exports = SETTINGS; From e70d3db49923bd2dc2e93073b1c9e101eadd19ea Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Wed, 27 Mar 2024 13:49:17 -0700 Subject: [PATCH 22/93] docs: update comment --- lib/node_modules/@stdlib/repl/lib/defaults.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/node_modules/@stdlib/repl/lib/defaults.js b/lib/node_modules/@stdlib/repl/lib/defaults.js index 9892d619c23..8edbd9bd784 100644 --- a/lib/node_modules/@stdlib/repl/lib/defaults.js +++ b/lib/node_modules/@stdlib/repl/lib/defaults.js @@ -80,7 +80,7 @@ function defaults() { // User settings: 'settings': { - // Flag indicating whether to auto-match brackets, braces, and quotes: + // Flag indicating whether to automatically insert matching brackets, parentheses, and quotes: 'autoMatch': true, // Flag indicating whether to enable the display of completion previews for auto-completion: From 8c5f3cd2dd09c990a88dffc34c5c90d184fd9270 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Wed, 27 Mar 2024 13:49:35 -0700 Subject: [PATCH 23/93] refactor: add support for validating a settings object --- lib/node_modules/@stdlib/repl/lib/validate.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/node_modules/@stdlib/repl/lib/validate.js b/lib/node_modules/@stdlib/repl/lib/validate.js index 9ce9eeac16c..adaeee1a68f 100644 --- a/lib/node_modules/@stdlib/repl/lib/validate.js +++ b/lib/node_modules/@stdlib/repl/lib/validate.js @@ -29,6 +29,7 @@ var isBoolean = require( '@stdlib/assert/is-boolean' ).isPrimitive; var isPositiveInteger = require( '@stdlib/assert/is-positive-integer' ).isPrimitive; var isNonNegativeInteger = require( '@stdlib/assert/is-nonnegative-integer' ).isPrimitive; var format = require( '@stdlib/string/format' ); +var validateSettings = require( './validate_settings.js' ); // MAIN // @@ -52,7 +53,7 @@ var format = require( '@stdlib/string/format' ); * @param {string} [options.save] - file path specifying where to save REPL command history * @param {string} [options.log] - file path specifying where to save REPL commands and printed output * @param {string} [options.quiet] - boolean indicating whether log information, confirmation messages, and other possible REPL diagnostics should be silenced -* @throws {Error} must provide valid options +* @param {Object} [options.settings] - REPL settings * @returns {(Error|null)} error or null * * @example @@ -66,6 +67,7 @@ var format = require( '@stdlib/string/format' ); * } */ function validate( opts, options ) { + var err; if ( !isPlainObject( options ) ) { return new TypeError( format( 'invalid argument. Options argument must be an object. Value: `%s`.', options ) ); } @@ -147,6 +149,12 @@ function validate( opts, options ) { return new TypeError( format( 'invalid option. `%s` option must be a boolean. Option: `%s`.', 'quiet', options.quiet ) ); } } + if ( hasOwnProp( options, 'settings' ) ) { + err = validateSettings( opts.settings, options.settings ); + if ( err ) { + return err; + } + } return null; } From 6021d0f319a7a14440617e041a899ed055b872f4 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Wed, 27 Mar 2024 13:53:09 -0700 Subject: [PATCH 24/93] refactor: remove duplicate option setting and document settings --- lib/node_modules/@stdlib/repl/lib/main.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/node_modules/@stdlib/repl/lib/main.js b/lib/node_modules/@stdlib/repl/lib/main.js index e8cbed19c7b..fa213c57b45 100644 --- a/lib/node_modules/@stdlib/repl/lib/main.js +++ b/lib/node_modules/@stdlib/repl/lib/main.js @@ -87,6 +87,9 @@ var debug = logger( 'repl' ); * @param {string} [options.save] - file path specifying where to save REPL command history * @param {string} [options.log] - file path specifying where to save REPL commands and printed output * @param {string} [options.quiet=false] - boolean indicating whether log information, confirmation messages, and other possible REPL diagnostics should be silenced +* @param {Object} [options.settings] - REPL settings +* @param {boolean} [options.settings.autoMatch=true] - boolean indicating whether to automatically insert matching brackets, parentheses, and quotes +* @param {boolean} [options.settings.completionPreviews=true] - boolean indicating whether to enable completion previews for auto-completion * @throws {Error} must provide valid options * @returns {REPL} REPL instance * @@ -164,6 +167,7 @@ function REPL( options ) { setNonEnumerableReadOnly( this, '_timeout', opts.timeout ); setNonEnumerableReadOnly( this, '_isTTY', opts.isTTY ); setNonEnumerableReadOnly( this, '_sandbox', opts.sandbox ); + setNonEnumerableReadOnly( this, '_settings', opts.settings ); setNonEnumerable( this, '_quiet', opts.quiet ); // allow this to be internally toggled // Initialize an internal data store: @@ -209,10 +213,6 @@ function REPL( options ) { // Define the current workspace: setNonEnumerable( this, '_currentWorkspace', 'base' ); - // Initialize an internal object storing user settings: - setNonEnumerable( this, '_settings', {} ); - setNonEnumerable( this._settings, 'autoMatch', true ); - // Initialize an internal status object for controlling multi-line mode: setNonEnumerable( this, '_multiline', {} ); setNonEnumerable( this._multiline, 'active', false ); From 4ea8a03d6d6f10ee280d51afb53cb479ee9a3210 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Wed, 27 Mar 2024 14:02:28 -0700 Subject: [PATCH 25/93] refactor: make the default dependent on whether TTY --- lib/node_modules/@stdlib/repl/lib/defaults.js | 4 ++-- lib/node_modules/@stdlib/repl/lib/main.js | 7 ++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/node_modules/@stdlib/repl/lib/defaults.js b/lib/node_modules/@stdlib/repl/lib/defaults.js index 8edbd9bd784..f3ff9448b5e 100644 --- a/lib/node_modules/@stdlib/repl/lib/defaults.js +++ b/lib/node_modules/@stdlib/repl/lib/defaults.js @@ -83,8 +83,8 @@ function defaults() { // Flag indicating whether to automatically insert matching brackets, parentheses, and quotes: 'autoMatch': true, - // Flag indicating whether to enable the display of completion previews for auto-completion: - 'completionPreviews': true + // Flag indicating whether to enable the display of completion previews for auto-completion (note: default depends on whether TTY): + 'completionPreviews': void 0 } }; } diff --git a/lib/node_modules/@stdlib/repl/lib/main.js b/lib/node_modules/@stdlib/repl/lib/main.js index fa213c57b45..c5bb459c802 100644 --- a/lib/node_modules/@stdlib/repl/lib/main.js +++ b/lib/node_modules/@stdlib/repl/lib/main.js @@ -89,7 +89,7 @@ var debug = logger( 'repl' ); * @param {string} [options.quiet=false] - boolean indicating whether log information, confirmation messages, and other possible REPL diagnostics should be silenced * @param {Object} [options.settings] - REPL settings * @param {boolean} [options.settings.autoMatch=true] - boolean indicating whether to automatically insert matching brackets, parentheses, and quotes -* @param {boolean} [options.settings.completionPreviews=true] - boolean indicating whether to enable completion previews for auto-completion +* @param {boolean} [options.settings.completionPreviews] - boolean indicating whether to enable completion previews for auto-completion * @throws {Error} must provide valid options * @returns {REPL} REPL instance * @@ -135,6 +135,7 @@ function REPL( options ) { } } opts.isTTY = ( opts.isTTY === void 0 ) ? opts.output.isTTY : opts.isTTY; + opts.settings.completionPreviews = ( opts.settings.completionPreviews === void 0 ) ? opts.isTTY : opts.settings.completionPreviews; debug( 'Options: %s', JSON.stringify({ 'input': '', @@ -266,8 +267,8 @@ function REPL( options ) { // Add a listener for "keypress" events: this._istream.on( 'keypress', onKeypress ); - // If operating in "terminal" mode, initialize a preview completer... - if ( this._isTTY ) { + // Check whether we can initialize a preview completer... + if ( this._settings.completionPreviews ) { // Create a new preview completer: previewCompleter = new PreviewCompleter( this._rli, completer, this._ostream ); From 5786c14f77d065cb743ba6bce85db5c3ec8a8522 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Wed, 27 Mar 2024 14:03:16 -0700 Subject: [PATCH 26/93] style: disable lint rules --- lib/node_modules/@stdlib/repl/lib/main.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/node_modules/@stdlib/repl/lib/main.js b/lib/node_modules/@stdlib/repl/lib/main.js index c5bb459c802..d2b12b126d5 100644 --- a/lib/node_modules/@stdlib/repl/lib/main.js +++ b/lib/node_modules/@stdlib/repl/lib/main.js @@ -135,7 +135,7 @@ function REPL( options ) { } } opts.isTTY = ( opts.isTTY === void 0 ) ? opts.output.isTTY : opts.isTTY; - opts.settings.completionPreviews = ( opts.settings.completionPreviews === void 0 ) ? opts.isTTY : opts.settings.completionPreviews; + opts.settings.completionPreviews = ( opts.settings.completionPreviews === void 0 ) ? opts.isTTY : opts.settings.completionPreviews; // eslint-disable-line max-len debug( 'Options: %s', JSON.stringify({ 'input': '', @@ -270,7 +270,7 @@ function REPL( options ) { // Check whether we can initialize a preview completer... if ( this._settings.completionPreviews ) { // Create a new preview completer: - previewCompleter = new PreviewCompleter( this._rli, completer, this._ostream ); + previewCompleter = new PreviewCompleter( this._rli, completer, this._ostream ); // eslint-disable-line max-len // Cache a reference to the private readline interface `ttyWrite` to allow calling the method when wanting default behavior: ttyWrite = this._rli._ttyWrite; From 3747888a2279966c743d48cbd81f2e97d5a1c345 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Wed, 27 Mar 2024 14:03:46 -0700 Subject: [PATCH 27/93] docs: document settings --- lib/node_modules/@stdlib/repl/README.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/node_modules/@stdlib/repl/README.md b/lib/node_modules/@stdlib/repl/README.md index 78c9846b312..c0c2df1bbe1 100644 --- a/lib/node_modules/@stdlib/repl/README.md +++ b/lib/node_modules/@stdlib/repl/README.md @@ -64,9 +64,9 @@ The function accepts the following `options`: - **input**: input (readable) stream. Default: [`stdin`][@stdlib/streams/node/stdin]. - **output**: output (writable) stream. Default: [`stdout`][@stdlib/streams/node/stdout]. -- **sandbox**: `boolean` indicating whether to run a REPL in a sandboxed context. Default: `false`. +- **sandbox**: boolean indicating whether to run a REPL in a sandboxed context. Default: `false`. - **timeout**: number of milliseconds to execute a command before terminating execution. Default: `4294967295`. -- **isTTY**: `boolean` indicating whether the input and output streams should be treated like a TTY (terminal) and whether the REPL should use ANSI/VT100 escape codes when writing to the output stream. +- **isTTY**: boolean indicating whether the input and output streams should be treated like a TTY (terminal) and whether the REPL should use ANSI/VT100 escape codes when writing to the output stream. - **inputPrompt**: input prompt. If the input prompt includes the character sequence `%d`, the input prompt includes line numbers. Default: `'In [%d]: '`. - **outputPrompt**: output prompt. If the output prompt includes the character sequence `%d`, the output prompt includes line numbers. Default: `'Out[%d]: '`. - **welcome**: welcome message. @@ -74,7 +74,13 @@ The function accepts the following `options`: - **load**: file path specifying a JavaScript file to load and evaluate line-by-line (e.g., a previous REPL history file). - **save**: file path specifying where to save REPL command history. - **log**: file path specifying where to save REPL commands and printed output. -- **quiet**: `boolean` indicating whether log information, confirmation messages, and other possible REPL diagnostics should be silenced. Default: `false`. +- **quiet**: boolean indicating whether log information, confirmation messages, and other possible REPL diagnostics should be silenced. Default: `false`. +- **settings**: object specifying REPL settings. + +The function supports specifying the following settings: + +- **autoMatch**: boolean indicating whether to automatically insert matching brackets, parentheses, and quotes. Default: `true`. +- **completionPreviews**: boolean indicating whether to display completion previews for auto-completion. When streams are TTY, the default is `true`; otherwise, the default is `false`. #### REPL.prototype.createContext() From 159569775bdb66c112711478e73967c946166642 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Wed, 27 Mar 2024 14:15:23 -0700 Subject: [PATCH 28/93] refactor: add module exporting a list of settings names --- .../@stdlib/repl/lib/settings_names.js | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 lib/node_modules/@stdlib/repl/lib/settings_names.js diff --git a/lib/node_modules/@stdlib/repl/lib/settings_names.js b/lib/node_modules/@stdlib/repl/lib/settings_names.js new file mode 100644 index 00000000000..fb750e4b566 --- /dev/null +++ b/lib/node_modules/@stdlib/repl/lib/settings_names.js @@ -0,0 +1,41 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2024 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +// MODULES // + +var objectKeys = require( '@stdlib/utils/keys' ); +var SETTINGS = require( './settings.js' ); + + +// MAIN // + +/** +* List of settings names. +* +* @private +* @name SETTINGS_NAMES +* @type {Array} +*/ +var SETTINGS_NAMES = objectKeys( SETTINGS ); + + +// EXPORTS // + +module.exports = SETTINGS_NAMES; From 5e54ec5141435463466c041603eafe9e62214054 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Wed, 27 Mar 2024 14:16:01 -0700 Subject: [PATCH 29/93] refactor: use module to get list of settings names --- lib/node_modules/@stdlib/repl/lib/validate_settings.js | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/lib/node_modules/@stdlib/repl/lib/validate_settings.js b/lib/node_modules/@stdlib/repl/lib/validate_settings.js index 59e2a9bfc3d..371c476df74 100644 --- a/lib/node_modules/@stdlib/repl/lib/validate_settings.js +++ b/lib/node_modules/@stdlib/repl/lib/validate_settings.js @@ -22,17 +22,12 @@ var isPlainObject = require( '@stdlib/assert/is-plain-object' ); var hasOwnProp = require( '@stdlib/assert/has-own-property' ); -var objectKeys = require( '@stdlib/utils/keys' ); var format = require( '@stdlib/string/format' ); var SETTINGS = require( './settings.js' ); +var SETTINGS_NAMES = require( './settings_names.js' ); var VALIDATORS = require( './settings_validators.js' ); -// VARIABLES // - -var SETTINGS_NAMES = objectKeys( SETTINGS ); - - // MAIN // /** From 3de8ec537ce76187cb458b5a7313073542e45b36 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Wed, 27 Mar 2024 14:25:54 -0700 Subject: [PATCH 30/93] refactor: update help text generation --- .../@stdlib/repl/lib/commands/settings.js | 34 ++++++------------- 1 file changed, 10 insertions(+), 24 deletions(-) diff --git a/lib/node_modules/@stdlib/repl/lib/commands/settings.js b/lib/node_modules/@stdlib/repl/lib/commands/settings.js index 49dc9b8dd00..aacf83f38fd 100644 --- a/lib/node_modules/@stdlib/repl/lib/commands/settings.js +++ b/lib/node_modules/@stdlib/repl/lib/commands/settings.js @@ -24,25 +24,16 @@ var logger = require( 'debug' ); var isString = require( '@stdlib/assert/is-string' ).isPrimitive; -var isBoolean = require( '@stdlib/assert/is-boolean' ).isPrimitive; var hasOwnProp = require( '@stdlib/assert/has-own-property' ); -var objectKeys = require( '@stdlib/utils/keys' ); var format = require( '@stdlib/string/format' ); +var VALIDATORS = require( './../settings_validators.js' ); +var SETTINGS = require( './../settings.js' ); +var SETTINGS_NAMES = require( './../settings_names.js' ); // VARIABLES // var debug = logger( 'repl:command:settings' ); -var SETTINGS = { - 'autoMatch': { - 'desc': 'Automatically insert matching brackets, parentheses, and quotes.', - 'default': true, - 'type': 'boolean' - } -}; -var VALIDATORS = { - 'boolean': isBoolean -}; // FUNCTIONS // @@ -56,22 +47,18 @@ var VALIDATORS = { */ function help( repl ) { var HELP_TEXT; - var names; + var name; var o; var i; - names = objectKeys( SETTINGS ); HELP_TEXT = '\n'; - for ( i = 0; i < names.length; i++ ) { - o = SETTINGS[ names[ i ] ]; - HELP_TEXT += names[ i ] + '\n'; + for ( i = 0; i < SETTINGS_NAMES.length; i++ ) { + name = SETTINGS_NAMES[ i ]; + o = SETTINGS[ name ]; + HELP_TEXT += name + '\n'; HELP_TEXT += ' '; - if ( o.desc ) { - HELP_TEXT += SETTINGS[ names[ i ] ].desc; - } else { - HELP_TEXT += '(no description available)'; - } - HELP_TEXT += format( ' Value: %s', repl._settings[names[ i ]] ); + HELP_TEXT += o.desc; // TODO: auto-wrap descriptions + HELP_TEXT += format( ' Value: %s.', repl._settings[ name ] ); HELP_TEXT += '\n\n'; } return HELP_TEXT; @@ -121,7 +108,6 @@ function command( repl ) { return; } if ( arguments.length === 1 ) { - // repl._ostream.write( '\n'+repl._settings[name]+'\n\n' ); repl._ostream.write( format( '\n%s\n\n', repl._settings[name] ) ); return; } From fd3b2a96e9b8649b94104659bb1eb0d693d346ab Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Wed, 27 Mar 2024 14:28:02 -0700 Subject: [PATCH 31/93] refactor: only pass down settings object --- lib/node_modules/@stdlib/repl/lib/commands/settings.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/node_modules/@stdlib/repl/lib/commands/settings.js b/lib/node_modules/@stdlib/repl/lib/commands/settings.js index aacf83f38fd..7f6097e7822 100644 --- a/lib/node_modules/@stdlib/repl/lib/commands/settings.js +++ b/lib/node_modules/@stdlib/repl/lib/commands/settings.js @@ -42,10 +42,10 @@ var debug = logger( 'repl:command:settings' ); * Returns settings help text. * * @private -* @param {REPL} repl - REPL instance +* @param {Object} settings - REPL settings * @returns {string} settings help text */ -function help( repl ) { +function help( settings ) { var HELP_TEXT; var name; var o; @@ -57,8 +57,8 @@ function help( repl ) { o = SETTINGS[ name ]; HELP_TEXT += name + '\n'; HELP_TEXT += ' '; - HELP_TEXT += o.desc; // TODO: auto-wrap descriptions - HELP_TEXT += format( ' Value: %s.', repl._settings[ name ] ); + HELP_TEXT += o.desc; // TODO: auto-wrap description + HELP_TEXT += format( ' Value: %s.', settings[ name ] ); HELP_TEXT += '\n\n'; } return HELP_TEXT; @@ -92,7 +92,7 @@ function command( repl ) { var validator; var err; if ( arguments.length === 0 ) { - repl._ostream.write( help( repl ) ); + repl._ostream.write( help( repl._settings ) ); return; } if ( !isString( name ) ) { From 02fad6910615ffc8d9d296123dc8ea75aa859144 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Wed, 27 Mar 2024 16:31:55 -0700 Subject: [PATCH 32/93] fix: use setting name when constructing error message --- lib/node_modules/@stdlib/repl/lib/settings_validators.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/node_modules/@stdlib/repl/lib/settings_validators.js b/lib/node_modules/@stdlib/repl/lib/settings_validators.js index a0f1b46d82d..17548299be9 100644 --- a/lib/node_modules/@stdlib/repl/lib/settings_validators.js +++ b/lib/node_modules/@stdlib/repl/lib/settings_validators.js @@ -38,7 +38,7 @@ var format = require( '@stdlib/string/format' ); * @returns {string} formatted error message */ function booleanErrMsg( name, value ) { - return format( 'invalid setting. `%s` setting must be a boolean. Value: `%s`.', value ); + return format( 'invalid setting. `%s` setting must be a boolean. Value: `%s`.', name, value ); } /** @@ -50,7 +50,7 @@ function booleanErrMsg( name, value ) { * @returns {string} formatted error message */ function integerErrMsg( name, value ) { - return format( 'invalid setting. `%s` setting must be an integer. Value: `%s`.', value ); + return format( 'invalid setting. `%s` setting must be an integer. Value: `%s`.', name, value ); } /** @@ -62,7 +62,7 @@ function integerErrMsg( name, value ) { * @returns {string} formatted error message */ function numberErrMsg( name, value ) { - return format( 'invalid setting. `%s` setting must be a number. Value: `%s`.', value ); + return format( 'invalid setting. `%s` setting must be a number. Value: `%s`.', name, value ); } /** @@ -74,7 +74,7 @@ function numberErrMsg( name, value ) { * @returns {string} formatted error message */ function stringErrMsg( name, value ) { - return format( 'invalid setting. `%s` setting must be a string. Value: `%s`.', value ); + return format( 'invalid setting. `%s` setting must be a string. Value: `%s`.', name, value ); } From 9dfa13c637c50fc9e960a4322229a12b66e77ec5 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Wed, 27 Mar 2024 18:12:13 -0700 Subject: [PATCH 33/93] refactor: add module to test if a value is a setting name --- .../@stdlib/repl/lib/is_setting_name.js | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 lib/node_modules/@stdlib/repl/lib/is_setting_name.js diff --git a/lib/node_modules/@stdlib/repl/lib/is_setting_name.js b/lib/node_modules/@stdlib/repl/lib/is_setting_name.js new file mode 100644 index 00000000000..5e74a88cf50 --- /dev/null +++ b/lib/node_modules/@stdlib/repl/lib/is_setting_name.js @@ -0,0 +1,47 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2024 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +// MODULES // + +var contains = require( '@stdlib/array/base/assert/contains' ).factory; +var SETTINGS_NAMES = require( './settings_names.js' ); + + +// MAIN // + +/** +* Returns a boolean indicating whether a provided value is a recognized settings name. +* +* @private +* @name isSettingName +* @type {Function} +* @param {*} value - input value +* @returns {boolean} boolean indicating whether a provided value is a recognized settings name +* +* @example +* var out = isSettingName( 'beep_boop_foo_bar' ); +* // returns false +*/ +var isSettingName = contains( SETTINGS_NAMES ); + + +// EXPORTS // + +module.exports = isSettingName; From 0d8d3a9b7c3e8a2c6afd1f55ba43cdc9d97e4c26 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Wed, 27 Mar 2024 18:12:45 -0700 Subject: [PATCH 34/93] refactor: update error messages --- lib/node_modules/@stdlib/repl/lib/settings_validators.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/node_modules/@stdlib/repl/lib/settings_validators.js b/lib/node_modules/@stdlib/repl/lib/settings_validators.js index 17548299be9..345b07acaa4 100644 --- a/lib/node_modules/@stdlib/repl/lib/settings_validators.js +++ b/lib/node_modules/@stdlib/repl/lib/settings_validators.js @@ -38,7 +38,7 @@ var format = require( '@stdlib/string/format' ); * @returns {string} formatted error message */ function booleanErrMsg( name, value ) { - return format( 'invalid setting. `%s` setting must be a boolean. Value: `%s`.', name, value ); + return format( 'invalid argument. `%s` setting must be a boolean. Value: `%s`.', name, value ); } /** @@ -50,7 +50,7 @@ function booleanErrMsg( name, value ) { * @returns {string} formatted error message */ function integerErrMsg( name, value ) { - return format( 'invalid setting. `%s` setting must be an integer. Value: `%s`.', name, value ); + return format( 'invalid argument. `%s` setting must be an integer. Value: `%s`.', name, value ); } /** @@ -62,7 +62,7 @@ function integerErrMsg( name, value ) { * @returns {string} formatted error message */ function numberErrMsg( name, value ) { - return format( 'invalid setting. `%s` setting must be a number. Value: `%s`.', name, value ); + return format( 'invalid argument. `%s` setting must be a number. Value: `%s`.', name, value ); } /** @@ -74,7 +74,7 @@ function numberErrMsg( name, value ) { * @returns {string} formatted error message */ function stringErrMsg( name, value ) { - return format( 'invalid setting. `%s` setting must be a string. Value: `%s`.', name, value ); + return format( 'invalid argument. `%s` setting must be a string. Value: `%s`.', name, value ); } From 22aba0c65527a900abd4988e08678666a9012772 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Wed, 27 Mar 2024 18:39:13 -0700 Subject: [PATCH 35/93] feat: add `settings` method for getting and setting REPL settings --- lib/node_modules/@stdlib/repl/lib/main.js | 73 ++++++++++++++++++++++- 1 file changed, 72 insertions(+), 1 deletion(-) diff --git a/lib/node_modules/@stdlib/repl/lib/main.js b/lib/node_modules/@stdlib/repl/lib/main.js index d2b12b126d5..69b16574a03 100644 --- a/lib/node_modules/@stdlib/repl/lib/main.js +++ b/lib/node_modules/@stdlib/repl/lib/main.js @@ -43,8 +43,10 @@ var readFileSync = require( '@stdlib/fs/read-file' ).sync; var RE_EOL = require( '@stdlib/regexp/eol' ).REGEXP; var fifo = require( '@stdlib/utils/fifo' ); var nextTick = require( '@stdlib/utils/next-tick' ); +var assign = require( '@stdlib/object/assign' ); var validate = require( './validate.js' ); var defaults = require( './defaults.js' ); +var isSettingName = require( './is_setting_name.js' ); var setAliases = require( './set_aliases.js' ); var setAliasesGlobal = require( './set_aliases_global.js' ); var setCommands = require( './set_commands.js' ); @@ -60,6 +62,8 @@ var PreviewCompleter = require( './completer_preview.js' ); var autoMatch = require( './auto_match_symbols.js' ); var manualMultiline = require( './handle_manual_multiline.js' ); var ALIAS_OVERRIDES = require( './alias_overrides.js' ); +var SETTINGS = require( './settings.js' ); +var SETTINGS_VALIDATORS = require( './settings_validators.js' ); // VARIABLES // @@ -834,7 +838,7 @@ setNonEnumerableReadOnly( REPL.prototype, 'clear', function onClear() { * @name clearLine * @memberof REPL.prototype * @type {Function} -* @throws {Error} cannot clear the current line a closed REPL +* @throws {Error} cannot clear the current line of a closed REPL * @returns {REPL} REPL instance * * @example @@ -987,6 +991,73 @@ setNonEnumerableReadOnly( REPL.prototype, 'close', function close() { } }); +/** +* Gets (and sets) REPL settings. +* +* @name settings +* @memberof REPL.prototype +* @type {Function} +* @param {string} [name] - setting name +* @param {*} [value] - new setting value +* @throws {TypeError} first argument must be a string +* @throws {TypeError} first argument must be a recognized setting +* @throws {TypeError} second argument must be a valid setting value +* @throws {Error} cannot access settings for a closed REPL +* @returns {(*|Object|REPL)} settings or a REPL instance +* +* @example +* var debug = require( '@stdlib/streams/node/debug-sink' ); +* +* // Create a new REPL: +* var repl = new REPL({ +* 'output': debug() +* }); +* +* // ... +* +* // Retrieve the current REPL settings: +* var o = repl.settings(); +* +* // ... +* +* // Close the REPL: +* repl.close(); +*/ +setNonEnumerableReadOnly( REPL.prototype, 'settings', function settings() { + var nargs; + var value; + var name; + var f; + + if ( this._closed ) { + throw new Error( 'invalid operation. Cannot access settings for a REPL which has already closed.' ); + } + nargs = arguments.length; + if ( nargs === 0 ) { + return assign( {}, this._settings ); + } + name = arguments[ 0 ]; + if ( !isString( name ) ) { + throw new TypeError( format( 'invalid argument. First argument must be a string. Value: `%s`.', name ) ); + } + if ( !isSettingName( name ) ) { + throw new Error( format( 'invalid argument. First argument must be a recognized setting. Value: `%s`.', name ) ); + } + if ( nargs === 1 ) { + return this._settings[ name ]; // TODO: we should consider returning a deep copy if settings are allowed to be objects, not just primitives, in order to avoid unintentional mutation + } + value = arguments[ 1 ]; + f = SETTINGS_VALIDATORS[ SETTINGS[ name ].type ]; + if ( !f.assert( value ) ) { + throw new TypeError( f.msg( name, value ) ); + } + debug( 'Updating setting `%s` to `%s`...', name, JSON.stringify( value ) ); + this._settings[ name ] = value; + debug( 'Successfully updated setting: `%s`.', name ); + + return this; +}); + // EXPORTS // From 2dff629aebfaed7d424607fc250096c59bc1f2a2 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Wed, 27 Mar 2024 18:39:49 -0700 Subject: [PATCH 36/93] refactor: delegate to `settings` method to validate arguments --- .../@stdlib/repl/lib/commands/settings.js | 52 ++++++++----------- 1 file changed, 21 insertions(+), 31 deletions(-) diff --git a/lib/node_modules/@stdlib/repl/lib/commands/settings.js b/lib/node_modules/@stdlib/repl/lib/commands/settings.js index 7f6097e7822..0f317bb2d96 100644 --- a/lib/node_modules/@stdlib/repl/lib/commands/settings.js +++ b/lib/node_modules/@stdlib/repl/lib/commands/settings.js @@ -23,10 +23,7 @@ // MODULES // var logger = require( 'debug' ); -var isString = require( '@stdlib/assert/is-string' ).isPrimitive; -var hasOwnProp = require( '@stdlib/assert/has-own-property' ); var format = require( '@stdlib/string/format' ); -var VALIDATORS = require( './../settings_validators.js' ); var SETTINGS = require( './../settings.js' ); var SETTINGS_NAMES = require( './../settings_names.js' ); @@ -78,48 +75,41 @@ function command( repl ) { return onCommand; /** - * Manages REPL settings. - * - * If no arguments are given, it prints all settings with their description. - * If one argument is given, it fetches the value of the setting with the given name and prints it. - * If two arguments are given, it updates the value of the given setting name to the given value. + * Setter and getter for REPL settings. * * @private * @param {string} [name] - setting name * @param {*} [value] - new setting value + * @returns {void} */ - function onCommand( name, value ) { - var validator; - var err; - if ( arguments.length === 0 ) { + function onCommand() { + var nargs; + var v; + + nargs = arguments.length; + if ( nargs === 0 ) { repl._ostream.write( help( repl._settings ) ); return; } - if ( !isString( name ) ) { - err = new TypeError( format( 'invalid argument. First argument must be a string. Value: `%s`.', name ) ); - debug( 'Error: %s', err.message ); - repl._ostream.write( format( 'Error: %s\n', err.message ) ); - return; - } - if ( !hasOwnProp( SETTINGS, name ) ) { - err = new Error( format( 'invalid argument. Unrecognized setting. Value: `%s`.', name ) ); - debug( 'Error: %s', err.message ); - repl._ostream.write( format( 'Error: %s\n', err.message ) ); - return; - } - if ( arguments.length === 1 ) { - repl._ostream.write( format( '\n%s\n\n', repl._settings[name] ) ); + if ( nargs === 1 ) { + try { + v = repl.settings( arguments[ 0 ] ); + } catch ( err ) { + debug( 'Error: %s', err.message ); + repl._ostream.write( format( 'Error: %s\n', err.message ) ); + return; + } + repl._ostream.write( format( '\n%s\n\n', JSON.stringify( v ) ) ); return; } - validator = VALIDATORS[ SETTINGS[name].type ]; - if ( !validator(value) ) { - err = new TypeError( format( 'invalid argument. Second argument must be a %s. Value: `%s`.', SETTINGS[name].type, name ) ); + try { + repl.settings( arguments[ 0 ], arguments[ 1 ] ); + } catch ( err ) { debug( 'Error: %s', err.message ); repl._ostream.write( format( 'Error: %s\n', err.message ) ); return; } - repl._settings[name] = value; - repl._ostream.write( format( '\nUpdated setting %s to %s.\n\n', name, String(value) ) ); + repl._ostream.write( format( '\nUpdated setting `%s` to `%s`.\n\n', arguments[ 0 ], JSON.stringify( arguments[ 1 ] ) ) ); } } From 9f35dff15de46e602dce4e483cafd6fc8fc170a1 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Wed, 27 Mar 2024 18:44:44 -0700 Subject: [PATCH 37/93] docs: document `settings` method --- lib/node_modules/@stdlib/repl/README.md | 65 +++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/lib/node_modules/@stdlib/repl/README.md b/lib/node_modules/@stdlib/repl/README.md index c0c2df1bbe1..bbb145f9950 100644 --- a/lib/node_modules/@stdlib/repl/README.md +++ b/lib/node_modules/@stdlib/repl/README.md @@ -295,6 +295,71 @@ repl.clearCommand(); repl.close(); ``` +#### REPL.prototype.settings( \[name\[, value]] ) + +Gets (and sets) REPL settings. + +```javascript +var debug = require( '@stdlib/streams/node/debug-sink' ); + +// Create a new REPL: +var repl = new REPL({ + 'output': debug() +}); + +// ... + +// Retrieve REPL settings: +var o = repl.settings(); + +// ... + +// Close the REPL: +repl.close(); +``` + +To retrieve the current setting value for a specific setting, provide a `name` argument. + +```javascript +var debug = require( '@stdlib/streams/node/debug-sink' ); + +// Create a new REPL: +var repl = new REPL({ + 'output': debug() +}); + +// ... + +// Retrieve current setting value: +var v = repl.settings( 'autoMatch' ); + +// ... + +// Close the REPL: +repl.close(); +``` + +To update a specific setting, provide a `value` argument. + +```javascript +var debug = require( '@stdlib/streams/node/debug-sink' ); + +// Create a new REPL: +var repl = new REPL({ + 'output': debug() +}); + +// ... + +// Update setting value: +repl.settings( 'autoMatch', false ); + +// ... + +// Close the REPL: +repl.close(); +``` + #### REPL.prototype.close() Closes a REPL. From d8da17a8e8e0bd147de48101ce4551234ec17887 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Wed, 27 Mar 2024 18:54:13 -0700 Subject: [PATCH 38/93] refactor: handle returning setting value as would normal command --- lib/node_modules/@stdlib/repl/lib/commands/settings.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/node_modules/@stdlib/repl/lib/commands/settings.js b/lib/node_modules/@stdlib/repl/lib/commands/settings.js index 0f317bb2d96..ab7e1c17789 100644 --- a/lib/node_modules/@stdlib/repl/lib/commands/settings.js +++ b/lib/node_modules/@stdlib/repl/lib/commands/settings.js @@ -80,7 +80,7 @@ function command( repl ) { * @private * @param {string} [name] - setting name * @param {*} [value] - new setting value - * @returns {void} + * @returns {(void|*)} setting value or undefined */ function onCommand() { var nargs; @@ -99,8 +99,7 @@ function command( repl ) { repl._ostream.write( format( 'Error: %s\n', err.message ) ); return; } - repl._ostream.write( format( '\n%s\n\n', JSON.stringify( v ) ) ); - return; + return v; } try { repl.settings( arguments[ 0 ], arguments[ 1 ] ); From 336d7a089e226f7ae150a1f89320d5323ca77739 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Wed, 27 Mar 2024 18:56:49 -0700 Subject: [PATCH 39/93] refactor: update confirmation message --- lib/node_modules/@stdlib/repl/lib/commands/settings.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/node_modules/@stdlib/repl/lib/commands/settings.js b/lib/node_modules/@stdlib/repl/lib/commands/settings.js index ab7e1c17789..eceb7cf01af 100644 --- a/lib/node_modules/@stdlib/repl/lib/commands/settings.js +++ b/lib/node_modules/@stdlib/repl/lib/commands/settings.js @@ -108,7 +108,7 @@ function command( repl ) { repl._ostream.write( format( 'Error: %s\n', err.message ) ); return; } - repl._ostream.write( format( '\nUpdated setting `%s` to `%s`.\n\n', arguments[ 0 ], JSON.stringify( arguments[ 1 ] ) ) ); + repl._ostream.write( '\nSuccessfully updated setting.\n' ); } } From d00958e85ec6908ee042dca7d4746ecdaef58339 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Wed, 27 Mar 2024 18:57:24 -0700 Subject: [PATCH 40/93] docs: update description --- lib/node_modules/@stdlib/repl/lib/commands/settings.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/node_modules/@stdlib/repl/lib/commands/settings.js b/lib/node_modules/@stdlib/repl/lib/commands/settings.js index eceb7cf01af..bc6af22145d 100644 --- a/lib/node_modules/@stdlib/repl/lib/commands/settings.js +++ b/lib/node_modules/@stdlib/repl/lib/commands/settings.js @@ -75,7 +75,7 @@ function command( repl ) { return onCommand; /** - * Setter and getter for REPL settings. + * Gets (and sets) REPL settings. * * @private * @param {string} [name] - setting name From 7e8f592e036331ebe9a6ddad9344d294d1a8c625 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Wed, 27 Mar 2024 23:33:38 -0700 Subject: [PATCH 41/93] refactor: remove support for manually entering multi-line editing Modifiers were generally not recognized on my Macbook Pro. In general, we should rethink multi-line editing and, once we do some more R&D, add support in a follow-up PR. Ref: https://github.com/stdlib-js/stdlib/issues/2060 --- .../repl/lib/handle_manual_multiline.js | 74 ------------------- lib/node_modules/@stdlib/repl/lib/main.js | 3 - .../@stdlib/repl/lib/process_line.js | 19 ----- 3 files changed, 96 deletions(-) delete mode 100644 lib/node_modules/@stdlib/repl/lib/handle_manual_multiline.js diff --git a/lib/node_modules/@stdlib/repl/lib/handle_manual_multiline.js b/lib/node_modules/@stdlib/repl/lib/handle_manual_multiline.js deleted file mode 100644 index 336f3178d4a..00000000000 --- a/lib/node_modules/@stdlib/repl/lib/handle_manual_multiline.js +++ /dev/null @@ -1,74 +0,0 @@ -/** -* @license Apache-2.0 -* -* Copyright (c) 2024 The Stdlib Authors. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -/* eslint-disable no-underscore-dangle */ - -'use strict'; - -// MODULES // - -var repeat = require( '@stdlib/string/repeat' ); - - -// MAIN // - -/** -* Returns a callback that handles multiline editing using a modifier key. -* -* @private -* @param {REPL} repl - REPL instance -* @returns {Function} callback -*/ -function manualMultiline( repl ) { - return onKeypress; - - /** - * Callback invoked upon a readline interface "keypress" event. - * - * @private - * @param {string} key - key event information - */ - function onKeypress( key ) { - var charsAfterCursor; - var codeAfterCursor; - - // For ALT+ENTER keypress, manually enter multi-line mode: - if ( key && key.name === 'return' && key.meta ) { - charsAfterCursor = repl._rli.line.length - repl._rli.cursor; - codeAfterCursor = repl._rli.line.substring( repl._rli.cursor ); - - // Update flag - repl._multiline.mode = 'modifier'; - - // Store code after cursor in buffer for next line - repl._multiline.buffer = codeAfterCursor; - repl._ostream.write( repeat( '\x1b[C', charsAfterCursor ) + repeat( '\b \b', charsAfterCursor ) ); - repl._rli.line = repl._rli.line.substring( 0, repl._rli.cursor ); - - // Simulate `line` event - repl._rli.write( null, { - 'name': 'return' - }); - } - } -} - - -// EXPORTS // - -module.exports = manualMultiline; diff --git a/lib/node_modules/@stdlib/repl/lib/main.js b/lib/node_modules/@stdlib/repl/lib/main.js index 69b16574a03..c626890bac9 100644 --- a/lib/node_modules/@stdlib/repl/lib/main.js +++ b/lib/node_modules/@stdlib/repl/lib/main.js @@ -60,7 +60,6 @@ var processLine = require( './process_line.js' ); var completerFactory = require( './completer.js' ); var PreviewCompleter = require( './completer_preview.js' ); var autoMatch = require( './auto_match_symbols.js' ); -var manualMultiline = require( './handle_manual_multiline.js' ); var ALIAS_OVERRIDES = require( './alias_overrides.js' ); var SETTINGS = require( './settings.js' ); var SETTINGS_VALIDATORS = require( './settings_validators.js' ); @@ -222,7 +221,6 @@ function REPL( options ) { setNonEnumerable( this, '_multiline', {} ); setNonEnumerable( this._multiline, 'active', false ); setNonEnumerable( this._multiline, 'mode', 'incomplete_expression' ); - setNonEnumerable( this._multiline, 'buffer', '' ); // Initialize an internal flag indicating whether auto closing symbols is in progress: setNonEnumerable( this, '_auto_match_status', false ); @@ -323,7 +321,6 @@ function REPL( options ) { previewCompleter.onKeypress( data, key ); } autoMatch( self )( data, key ); - manualMultiline( self )( key ); } /** diff --git a/lib/node_modules/@stdlib/repl/lib/process_line.js b/lib/node_modules/@stdlib/repl/lib/process_line.js index 08adb975f28..8dcce73586b 100644 --- a/lib/node_modules/@stdlib/repl/lib/process_line.js +++ b/lib/node_modules/@stdlib/repl/lib/process_line.js @@ -25,7 +25,6 @@ var logger = require( 'debug' ); var Parser = require( 'acorn' ).Parser; var parseLoose = require( 'acorn-loose' ).parse; -var repeat = require( '@stdlib/string/repeat' ); var displayPrompt = require( './display_prompt.js' ); var drain = require( './drain.js' ); var multilinePlugin = require( './acorn_detect_multiline_input.js' ); @@ -66,21 +65,6 @@ function processLine( repl, line ) { repl._multiline.active = false; // false until proven otherwise cmd = repl._cmd.join( '\n' ) + line; - if ( repl._multiline.mode === 'modifier' ) { - debug( 'Detected multi-line input via modifier-key. Waiting for additional lines...' ); - repl._cmd.push( line ); - repl._multiline.active = true; - repl._multiline.mode = 'incomplete_expression'; - displayPrompt( repl, false ); - if ( /\{\s*$|\[\s*$|\(\s*$/.test( line ) ) { - repl._rli.write(' '); // auto-indentation - } - repl._ostream.write( repl._multiline.buffer ); - repl._ostream.write(repeat('\x1b[D', repl._multiline.buffer.length)); - repl._rli.line += repl._multiline.buffer; - repl._multiline.buffer = ''; // empty buffer - return; - } if ( RE_WHITESPACE.test( cmd ) ) { displayPrompt( repl, false ); return; @@ -101,9 +85,6 @@ function processLine( repl, line ) { repl._cmd.push( line ); repl._multiline.active = true; displayPrompt( repl, false ); - if ( /\{\s*$|\[\s*$|\(\s*$/.test( line ) ) { - repl._rli.write(' '); // auto-indentation - } return; } // Still possible that a user is attempting to enter an object literal across multiple lines... From 590649d570486be35d1a63e6db7aeab962a9b63d Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Wed, 27 Mar 2024 23:41:24 -0700 Subject: [PATCH 42/93] docs: update copy --- lib/node_modules/@stdlib/repl/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/node_modules/@stdlib/repl/README.md b/lib/node_modules/@stdlib/repl/README.md index bbb145f9950..4a0232c82de 100644 --- a/lib/node_modules/@stdlib/repl/README.md +++ b/lib/node_modules/@stdlib/repl/README.md @@ -318,7 +318,7 @@ var o = repl.settings(); repl.close(); ``` -To retrieve the current setting value for a specific setting, provide a `name` argument. +To retrieve the current value for a specific setting, provide a `name` argument. ```javascript var debug = require( '@stdlib/streams/node/debug-sink' ); From 89415bc13247e4f59ad564617941c9ff9c9d2cb9 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Thu, 28 Mar 2024 00:07:25 -0700 Subject: [PATCH 43/93] refactor: bind variables to REPL instance to allow "toggabilty" --- lib/node_modules/@stdlib/repl/lib/main.js | 48 +++++++++++------------ 1 file changed, 23 insertions(+), 25 deletions(-) diff --git a/lib/node_modules/@stdlib/repl/lib/main.js b/lib/node_modules/@stdlib/repl/lib/main.js index c626890bac9..8792523dccb 100644 --- a/lib/node_modules/@stdlib/repl/lib/main.js +++ b/lib/node_modules/@stdlib/repl/lib/main.js @@ -115,9 +115,6 @@ var debug = logger( 'repl' ); * repl.close(); */ function REPL( options ) { - var previewCompleter; - var completer; - var ttyWrite; var opts; var self; var err; @@ -217,13 +214,14 @@ function REPL( options ) { // Define the current workspace: setNonEnumerable( this, '_currentWorkspace', 'base' ); - // Initialize an internal status object for controlling multi-line mode: + // Initialize an internal status object for multi-line mode: setNonEnumerable( this, '_multiline', {} ); setNonEnumerable( this._multiline, 'active', false ); setNonEnumerable( this._multiline, 'mode', 'incomplete_expression' ); - // Initialize an internal flag indicating whether auto closing symbols is in progress: - setNonEnumerable( this, '_auto_match_status', false ); + // Initialize an internal status object for auto-matching: + setNonEnumerable( this, '_auto_match', {} ); + setNonEnumerable( this._auto_match, 'active', false ); // Initialize an internal flag indicating whether the REPL has been closed: setNonEnumerable( this, '_closed', false ); @@ -244,7 +242,7 @@ function REPL( options ) { setNonEnumerable( this, '_context', this.createContext() ); // Create a new TAB completer: - completer = completerFactory( this ); + setNonEnumerableReadOnly( this, '_completer', completerFactory( this ) ); // Create an internal readline interface: debug( 'Creating readline interface...' ); @@ -253,9 +251,19 @@ function REPL( options ) { 'output': this._ostream, 'terminal': opts.isTTY, 'prompt': opts.inputPrompt, - 'completer': completer + 'completer': this._completer })); + // Initialize a preview completer: + setNonEnumerable( this, '_previewCompleter', new PreviewCompleter( this._rli, this._completer, this._ostream ) ); + + // Cache a reference to the private readline interface `ttyWrite` to allow calling the method when wanting default behavior: + setNonEnumerable( this, '_ttyWrite', this._rli._ttyWrite ); + + // Overwrite the private `ttyWrite` method to allow processing input before a "keypress" event is triggered: + this._rli._ttyWrite = beforeKeypress; // WARNING: overwriting a private property + + // Add event listeners: this._rli.on( 'close', onClose ); this._rli.on( 'line', onLine ); this._rli.on( 'SIGINT', onSIGINT ); @@ -269,18 +277,6 @@ function REPL( options ) { // Add a listener for "keypress" events: this._istream.on( 'keypress', onKeypress ); - // Check whether we can initialize a preview completer... - if ( this._settings.completionPreviews ) { - // Create a new preview completer: - previewCompleter = new PreviewCompleter( this._rli, completer, this._ostream ); // eslint-disable-line max-len - - // Cache a reference to the private readline interface `ttyWrite` to allow calling the method when wanting default behavior: - ttyWrite = this._rli._ttyWrite; - - // Overwrite the private `ttyWrite` method to allow processing input before a "keypress" event is triggered: - this._rli._ttyWrite = beforeKeypress; // WARNING: overwriting a private property - } - // Write a welcome message: this._ostream.write( opts.welcome ); @@ -305,8 +301,10 @@ function REPL( options ) { * @param {Object} key - key object */ function beforeKeypress( data, key ) { - previewCompleter.beforeKeypress( data, key ); - ttyWrite.call( self._rli, data, key ); + if ( self._settings.completionPreviews ) { + self._previewCompleter.beforeKeypress( data, key ); + } + self._ttyWrite.call( self._rli, data, key ); } /** @@ -317,10 +315,10 @@ function REPL( options ) { * @param {Object} key - key object */ function onKeypress( data, key ) { - if ( previewCompleter ) { - previewCompleter.onKeypress( data, key ); - } autoMatch( self )( data, key ); + if ( self._settings.completionPreviews ) { + self._previewCompleter.onKeypress( data, key ); + } } /** From 0f577cc58cea9fa909cb160e9a9f69124066fcdd Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Thu, 28 Mar 2024 00:07:56 -0700 Subject: [PATCH 44/93] refactor: move symbols table to separate file --- .../@stdlib/repl/lib/auto_match.js | 109 ++++++++++++++++++ .../@stdlib/repl/lib/auto_match_symbols.js | 94 ++------------- 2 files changed, 119 insertions(+), 84 deletions(-) create mode 100644 lib/node_modules/@stdlib/repl/lib/auto_match.js diff --git a/lib/node_modules/@stdlib/repl/lib/auto_match.js b/lib/node_modules/@stdlib/repl/lib/auto_match.js new file mode 100644 index 00000000000..797dbe61514 --- /dev/null +++ b/lib/node_modules/@stdlib/repl/lib/auto_match.js @@ -0,0 +1,109 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2024 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +/* eslint-disable no-underscore-dangle */ + +'use strict'; + +// MODULES // + +var AUTO_MATCH_SYMBOLS = require( './auto_match_symbols.js' ); + + +// MAIN // + +/** +* Returns a callback that handles auto matching symbols. +* +* @private +* @param {REPL} repl - REPL instance +* @returns {Function} callback +*/ +function autoMatch( repl ) { + return onKeypress; + + /** + * Callback invoked upon a readline interface "keypress" event. + * + * @private + * @param {string} chunk - character pressed by the user + * @param {Object} key - keypress event information + */ + function onKeypress( chunk, key ) { + if ( repl._settings.autoMatch ) { + // Handle edge cases + if ( repl._auto_match_status ) { + // Auto delete appended symbol when deleting input + if ( + key.name === 'backspace' + ) { + repl._rli.write( null, { + 'name': 'right' + } ); + repl._rli.write( null, { + 'name': 'backspace' + } ); + return; + } + // Discard instinctive closing symbols + if ( + typeof chunk !== 'undefined' && + repl._rli.line[ repl._rli.cursor ] === chunk && + AUTO_MATCH_SYMBOLS[ repl._rli.line[ repl._rli.cursor - 2 ] ] === chunk + ) { + repl._rli.write( null, { + 'name': 'backspace' + } ); + repl._rli.write( null, { + 'name': 'right' + } ); + repl._auto_match_status = false; + return; + } + repl._auto_match_status = false; + } + + // For a bracket/quotation input, append corresponding closing symbol + if ( AUTO_MATCH_SYMBOLS[chunk] ) { + if ( + ( + AUTO_MATCH_SYMBOLS[chunk] === '\'' || AUTO_MATCH_SYMBOLS[chunk] === '"' + ) && + ( + /^[a-zA-Z0-9"'/\\]$/.test(repl._rli.line[repl._rli.cursor - 2 ]) || + /^[a-zA-Z0-9"'/\\]$/.test(repl._rli.line[repl._rli.cursor ]) + ) + ) { + // Don't auto-complete quotations around text + return; + } + repl._rli.write( AUTO_MATCH_SYMBOLS[chunk] ); + repl._rli.write( null, { + 'ctrl': true, + 'name': 'b' + } ); + repl._auto_match_status = true; + } + } + } +} + + +// EXPORTS // + +module.exports = autoMatch; diff --git a/lib/node_modules/@stdlib/repl/lib/auto_match_symbols.js b/lib/node_modules/@stdlib/repl/lib/auto_match_symbols.js index 7707bbeb336..736b878590f 100644 --- a/lib/node_modules/@stdlib/repl/lib/auto_match_symbols.js +++ b/lib/node_modules/@stdlib/repl/lib/auto_match_symbols.js @@ -16,13 +16,18 @@ * limitations under the License. */ -/* eslint-disable no-underscore-dangle */ - 'use strict'; -// VARIABLES // +// MAIN // -var SYMBOLS = { +/** +* Table mapping opening symbols with their closing counterparts. +* +* @private +* @name AUTO_MATCH_SYMBOLS +* @type {Object} +*/ +var AUTO_MATCH_SYMBOLS = { '{': '}', '[': ']', '(': ')', @@ -32,85 +37,6 @@ var SYMBOLS = { }; -// MAIN // - -/** -* Returns a callback that handles auto matching symbols. -* -* @private -* @param {REPL} repl - REPL instance -* @returns {Function} callback -*/ -function autoMatch( repl ) { - return onKeypress; - - /** - * Callback invoked upon a readline interface "keypress" event. - * - * @private - * @param {string} chunk - character pressed by the user - * @param {Object} key - keypress event information - */ - function onKeypress( chunk, key ) { - if ( repl._settings.autoMatch ) { - // Handle edge cases - if ( repl._auto_match_status ) { - // Auto delete appended symbol when deleting input - if ( - key.name === 'backspace' - ) { - repl._rli.write( null, { - 'name': 'right' - } ); - repl._rli.write( null, { - 'name': 'backspace' - } ); - return; - } - // Discard instinctive closing symbols - if ( - typeof chunk !== 'undefined' && - repl._rli.line[ repl._rli.cursor ] === chunk && - SYMBOLS[ repl._rli.line[ repl._rli.cursor - 2 ] ] === chunk - ) { - repl._rli.write( null, { - 'name': 'backspace' - } ); - repl._rli.write( null, { - 'name': 'right' - } ); - repl._auto_match_status = false; - return; - } - repl._auto_match_status = false; - } - - // For a bracket/quotation input, append corresponding closing symbol - if ( SYMBOLS[chunk] ) { - if ( - ( - SYMBOLS[chunk] === '\'' || SYMBOLS[chunk] === '"' - ) && - ( - /^[a-zA-Z0-9"'/\\]$/.test(repl._rli.line[repl._rli.cursor - 2 ]) || - /^[a-zA-Z0-9"'/\\]$/.test(repl._rli.line[repl._rli.cursor ]) - ) - ) { - // Don't auto-complete quotations around text - return; - } - repl._rli.write( SYMBOLS[chunk] ); - repl._rli.write( null, { - 'ctrl': true, - 'name': 'b' - } ); - repl._auto_match_status = true; - } - } - } -} - - // EXPORTS // -module.exports = autoMatch; +module.exports = AUTO_MATCH_SYMBOLS; From d4e0730f7b2507060d96022432b62eef003ad447 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Thu, 28 Mar 2024 00:10:30 -0700 Subject: [PATCH 45/93] fix: update require path --- lib/node_modules/@stdlib/repl/lib/main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/node_modules/@stdlib/repl/lib/main.js b/lib/node_modules/@stdlib/repl/lib/main.js index 8792523dccb..76aee73ba65 100644 --- a/lib/node_modules/@stdlib/repl/lib/main.js +++ b/lib/node_modules/@stdlib/repl/lib/main.js @@ -59,7 +59,7 @@ var inputPrompt = require( './input_prompt.js' ); var processLine = require( './process_line.js' ); var completerFactory = require( './completer.js' ); var PreviewCompleter = require( './completer_preview.js' ); -var autoMatch = require( './auto_match_symbols.js' ); +var autoMatch = require( './auto_match.js' ); var ALIAS_OVERRIDES = require( './alias_overrides.js' ); var SETTINGS = require( './settings.js' ); var SETTINGS_VALIDATORS = require( './settings_validators.js' ); From 1f14f2437bbd1a527a8e62fddf98cceac70374c6 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Thu, 28 Mar 2024 00:32:23 -0700 Subject: [PATCH 46/93] refactor: convert auto-matcher to a class This avoids unnecessary closure creation and makes consistent with preview completer. --- .../@stdlib/repl/lib/auto_match.js | 148 ++++++++++-------- .../@stdlib/repl/lib/completer_preview.js | 2 +- lib/node_modules/@stdlib/repl/lib/main.js | 13 +- 3 files changed, 87 insertions(+), 76 deletions(-) diff --git a/lib/node_modules/@stdlib/repl/lib/auto_match.js b/lib/node_modules/@stdlib/repl/lib/auto_match.js index 797dbe61514..f4f52291cab 100644 --- a/lib/node_modules/@stdlib/repl/lib/auto_match.js +++ b/lib/node_modules/@stdlib/repl/lib/auto_match.js @@ -16,94 +16,104 @@ * limitations under the License. */ -/* eslint-disable no-underscore-dangle */ +/* eslint-disable no-restricted-syntax, no-invalid-this */ 'use strict'; // MODULES // +var logger = require( 'debug' ); +var setNonEnumerableReadOnly = require( '@stdlib/utils/define-nonenumerable-read-only-property' ); var AUTO_MATCH_SYMBOLS = require( './auto_match_symbols.js' ); +// VARIABLES // + +var debug = logger( 'repl:auto_match' ); + + // MAIN // /** -* Returns a callback that handles auto matching symbols. +* Constructor for creating an auto-matcher. * * @private -* @param {REPL} repl - REPL instance -* @returns {Function} callback +* @constructor +* @param {Object} rli - readline instance +* @returns {AutoMatcher} auto-matcher instance */ -function autoMatch( repl ) { - return onKeypress; +function AutoMatcher( rli ) { + if ( !(this instanceof AutoMatcher) ) { + return new AutoMatcher(); + } + debug( 'Creating an auto-matcher...' ); + this._rli = rli; + this._active = false; + return this; +} - /** - * Callback invoked upon a readline interface "keypress" event. - * - * @private - * @param {string} chunk - character pressed by the user - * @param {Object} key - keypress event information - */ - function onKeypress( chunk, key ) { - if ( repl._settings.autoMatch ) { - // Handle edge cases - if ( repl._auto_match_status ) { - // Auto delete appended symbol when deleting input - if ( - key.name === 'backspace' - ) { - repl._rli.write( null, { - 'name': 'right' - } ); - repl._rli.write( null, { - 'name': 'backspace' - } ); - return; - } - // Discard instinctive closing symbols - if ( - typeof chunk !== 'undefined' && - repl._rli.line[ repl._rli.cursor ] === chunk && - AUTO_MATCH_SYMBOLS[ repl._rli.line[ repl._rli.cursor - 2 ] ] === chunk - ) { - repl._rli.write( null, { - 'name': 'backspace' - } ); - repl._rli.write( null, { - 'name': 'right' - } ); - repl._auto_match_status = false; - return; - } - repl._auto_match_status = false; - } +/** +* Callback for handling a "keypress" event. +* +* @name onKeypress +* @memberof AutoMatcher.prototype +* @param {string} data - input data +* @param {Object} key - key object +* @returns {void} +*/ +setNonEnumerableReadOnly( AutoMatcher.prototype, 'onKeypress', function onKeypress( data, key ) { + if ( this._active ) { + // Auto delete appended symbol when deleting input + if ( key.name === 'backspace' ) { + this._rli.write( null, { + 'name': 'right' + } ); + this._rli.write( null, { + 'name': 'backspace' + } ); + return; + } + // Discard instinctive closing symbols + if ( + this._rli.line[ this._rli.cursor ] === data && + AUTO_MATCH_SYMBOLS[ this._rli.line[ this._rli.cursor-2 ] ] === data + ) { + this._rli.write( null, { + 'name': 'backspace' + } ); + this._rli.write( null, { + 'name': 'right' + } ); + this._active = false; + return; + } + this._active = false; + } - // For a bracket/quotation input, append corresponding closing symbol - if ( AUTO_MATCH_SYMBOLS[chunk] ) { - if ( - ( - AUTO_MATCH_SYMBOLS[chunk] === '\'' || AUTO_MATCH_SYMBOLS[chunk] === '"' - ) && - ( - /^[a-zA-Z0-9"'/\\]$/.test(repl._rli.line[repl._rli.cursor - 2 ]) || - /^[a-zA-Z0-9"'/\\]$/.test(repl._rli.line[repl._rli.cursor ]) - ) - ) { - // Don't auto-complete quotations around text - return; - } - repl._rli.write( AUTO_MATCH_SYMBOLS[chunk] ); - repl._rli.write( null, { - 'ctrl': true, - 'name': 'b' - } ); - repl._auto_match_status = true; - } + // For a bracket/quotation input, append corresponding closing symbol + if ( AUTO_MATCH_SYMBOLS[ data ] ) { + if ( + ( + AUTO_MATCH_SYMBOLS[ data ] === '\'' || AUTO_MATCH_SYMBOLS[ data ] === '"' + ) && + ( + /^[a-zA-Z0-9"'/\\]$/.test( this._rli.line[ this._rli.cursor-2 ] ) || + /^[a-zA-Z0-9"'/\\]$/.test( this._rli.line[ this._rli.cursor ] ) + ) + ) { + // Don't auto-complete quotations around text + return; } + this._rli.write( AUTO_MATCH_SYMBOLS[ data ] ); + this._rli.write( null, { + 'ctrl': true, + 'name': 'b' + } ); + this._active = true; } -} +}); // EXPORTS // -module.exports = autoMatch; +module.exports = AutoMatcher; diff --git a/lib/node_modules/@stdlib/repl/lib/completer_preview.js b/lib/node_modules/@stdlib/repl/lib/completer_preview.js index 59d4ae1efdc..8a304674fe0 100644 --- a/lib/node_modules/@stdlib/repl/lib/completer_preview.js +++ b/lib/node_modules/@stdlib/repl/lib/completer_preview.js @@ -16,7 +16,7 @@ * limitations under the License. */ -/* eslint-disable no-restricted-syntax, no-underscore-dangle, no-invalid-this */ +/* eslint-disable no-restricted-syntax, no-underscore-dangle, no-invalid-this */ 'use strict'; diff --git a/lib/node_modules/@stdlib/repl/lib/main.js b/lib/node_modules/@stdlib/repl/lib/main.js index 76aee73ba65..e673bcf439f 100644 --- a/lib/node_modules/@stdlib/repl/lib/main.js +++ b/lib/node_modules/@stdlib/repl/lib/main.js @@ -59,7 +59,7 @@ var inputPrompt = require( './input_prompt.js' ); var processLine = require( './process_line.js' ); var completerFactory = require( './completer.js' ); var PreviewCompleter = require( './completer_preview.js' ); -var autoMatch = require( './auto_match.js' ); +var AutoMatcher = require( './auto_match.js' ); var ALIAS_OVERRIDES = require( './alias_overrides.js' ); var SETTINGS = require( './settings.js' ); var SETTINGS_VALIDATORS = require( './settings_validators.js' ); @@ -219,10 +219,6 @@ function REPL( options ) { setNonEnumerable( this._multiline, 'active', false ); setNonEnumerable( this._multiline, 'mode', 'incomplete_expression' ); - // Initialize an internal status object for auto-matching: - setNonEnumerable( this, '_auto_match', {} ); - setNonEnumerable( this._auto_match, 'active', false ); - // Initialize an internal flag indicating whether the REPL has been closed: setNonEnumerable( this, '_closed', false ); @@ -254,6 +250,9 @@ function REPL( options ) { 'completer': this._completer })); + // Create a new auto-matcher: + setNonEnumerableReadOnly( this, '_autoMatcher', new AutoMatcher( this._rli ) ); + // Initialize a preview completer: setNonEnumerable( this, '_previewCompleter', new PreviewCompleter( this._rli, this._completer, this._ostream ) ); @@ -315,7 +314,9 @@ function REPL( options ) { * @param {Object} key - key object */ function onKeypress( data, key ) { - autoMatch( self )( data, key ); + if ( self._settings.autoMatch ) { + self._autoMatcher.onKeypress( data, key ); + } if ( self._settings.completionPreviews ) { self._previewCompleter.onKeypress( data, key ); } From e4f50ba82a4dcab78429de9b24820e6698cb9c97 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Thu, 28 Mar 2024 00:36:16 -0700 Subject: [PATCH 47/93] refactor: make private properties read-only --- lib/node_modules/@stdlib/repl/lib/main.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/node_modules/@stdlib/repl/lib/main.js b/lib/node_modules/@stdlib/repl/lib/main.js index e673bcf439f..641098e3509 100644 --- a/lib/node_modules/@stdlib/repl/lib/main.js +++ b/lib/node_modules/@stdlib/repl/lib/main.js @@ -254,10 +254,10 @@ function REPL( options ) { setNonEnumerableReadOnly( this, '_autoMatcher', new AutoMatcher( this._rli ) ); // Initialize a preview completer: - setNonEnumerable( this, '_previewCompleter', new PreviewCompleter( this._rli, this._completer, this._ostream ) ); + setNonEnumerableReadOnly( this, '_previewCompleter', new PreviewCompleter( this._rli, this._completer, this._ostream ) ); // Cache a reference to the private readline interface `ttyWrite` to allow calling the method when wanting default behavior: - setNonEnumerable( this, '_ttyWrite', this._rli._ttyWrite ); + setNonEnumerableReadOnly( this, '_ttyWrite', this._rli._ttyWrite ); // Overwrite the private `ttyWrite` method to allow processing input before a "keypress" event is triggered: this._rli._ttyWrite = beforeKeypress; // WARNING: overwriting a private property From 53ae830afd44f61a36c51ef00df4ee660e79bc5b Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Thu, 28 Mar 2024 01:00:59 -0700 Subject: [PATCH 48/93] fix: only perform preview completion when no collisions are possible --- lib/node_modules/@stdlib/repl/lib/completer_preview.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/node_modules/@stdlib/repl/lib/completer_preview.js b/lib/node_modules/@stdlib/repl/lib/completer_preview.js index 8a304674fe0..f1a8428c487 100644 --- a/lib/node_modules/@stdlib/repl/lib/completer_preview.js +++ b/lib/node_modules/@stdlib/repl/lib/completer_preview.js @@ -183,7 +183,15 @@ setNonEnumerableReadOnly( PreviewCompleter.prototype, 'clear', function clear() * @returns {void} */ setNonEnumerableReadOnly( PreviewCompleter.prototype, 'onKeypress', function onKeypress() { - this._completer( this._rli.line, this._onCompletions ); + // Check for existing content beyond the cursor which could "collide" with a preview completion... + if ( /[^a-zA-Z0-9_$]/.test( this._rli.line.substring( this._rli.cursor ) ) ) { + return; + } + try { + this._completer( this._rli.line, this._onCompletions ); + } catch ( err ) { + debug( 'Error: %s', err.message ); + } }); /** From 0af02a28af2756f78b370d3110aac6a70771ab1b Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Thu, 28 Mar 2024 01:12:19 -0700 Subject: [PATCH 49/93] refactor: clean implementation with scoped variables --- .../@stdlib/repl/lib/auto_match.js | 37 +++++++++++-------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/lib/node_modules/@stdlib/repl/lib/auto_match.js b/lib/node_modules/@stdlib/repl/lib/auto_match.js index f4f52291cab..fb4ef292568 100644 --- a/lib/node_modules/@stdlib/repl/lib/auto_match.js +++ b/lib/node_modules/@stdlib/repl/lib/auto_match.js @@ -62,8 +62,16 @@ function AutoMatcher( rli ) { * @returns {void} */ setNonEnumerableReadOnly( AutoMatcher.prototype, 'onKeypress', function onKeypress( data, key ) { + var cursor; + var line; + var ch; + + cursor = this._rli.cursor; + line = this._rli.line; + + // If we are currently in the process of auto-matching, handle special cases... if ( this._active ) { - // Auto delete appended symbol when deleting input + // Automatically remove a closing symbol when deleting an opening symbol... if ( key.name === 'backspace' ) { this._rli.write( null, { 'name': 'right' @@ -73,11 +81,8 @@ setNonEnumerableReadOnly( AutoMatcher.prototype, 'onKeypress', function onKeypre } ); return; } - // Discard instinctive closing symbols - if ( - this._rli.line[ this._rli.cursor ] === data && - AUTO_MATCH_SYMBOLS[ this._rli.line[ this._rli.cursor-2 ] ] === data - ) { + // Remove auto-completed closing symbols when a user instinctively manually completes the closing symbol in order to avoid duplicate closing symbols... + if ( line[ cursor ] === data && AUTO_MATCH_SYMBOLS[ line[ cursor-2 ] ] === data ) { this._rli.write( null, { 'name': 'backspace' } ); @@ -87,28 +92,30 @@ setNonEnumerableReadOnly( AutoMatcher.prototype, 'onKeypress', function onKeypre this._active = false; return; } + // Reset the flag indicating that we are actively auto-matching: this._active = false; } - - // For a bracket/quotation input, append corresponding closing symbol - if ( AUTO_MATCH_SYMBOLS[ data ] ) { + ch = AUTO_MATCH_SYMBOLS[ data ]; + if ( ch !== void 0 ) { + // Avoid auto-completing quotation marks around text... if ( ( - AUTO_MATCH_SYMBOLS[ data ] === '\'' || AUTO_MATCH_SYMBOLS[ data ] === '"' + ch === '\'' || + ch === '"' ) && ( - /^[a-zA-Z0-9"'/\\]$/.test( this._rli.line[ this._rli.cursor-2 ] ) || - /^[a-zA-Z0-9"'/\\]$/.test( this._rli.line[ this._rli.cursor ] ) + /^[a-zA-Z0-9"'/\\]$/.test( line[ cursor-2 ] ) || + /^[a-zA-Z0-9"'/\\]$/.test( line[ cursor ] ) ) ) { - // Don't auto-complete quotations around text return; } - this._rli.write( AUTO_MATCH_SYMBOLS[ data ] ); + // Append a closing symbol: + this._rli.write( ch ); this._rli.write( null, { 'ctrl': true, 'name': 'b' - } ); + }); this._active = true; } }); From acc8ab6afe99d4f33129974388dbe5a58810d5e9 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Thu, 28 Mar 2024 01:22:03 -0700 Subject: [PATCH 50/93] refactor: use helper functions --- .../@stdlib/repl/lib/auto_match.js | 55 +++++++++++++++---- 1 file changed, 44 insertions(+), 11 deletions(-) diff --git a/lib/node_modules/@stdlib/repl/lib/auto_match.js b/lib/node_modules/@stdlib/repl/lib/auto_match.js index fb4ef292568..309ecaec67c 100644 --- a/lib/node_modules/@stdlib/repl/lib/auto_match.js +++ b/lib/node_modules/@stdlib/repl/lib/auto_match.js @@ -30,6 +30,48 @@ var AUTO_MATCH_SYMBOLS = require( './auto_match_symbols.js' ); // VARIABLES // var debug = logger( 'repl:auto_match' ); +var RE_TEXT = /^[a-zA-Z0-9"'/\\]$/; + + +// FUNCTIONS // + +/** +* Tests whether a provided character is a quote symbol. +* +* @private +* @param {string} ch - input character +* @returns {boolean} boolean indicating if a character is a quote symbol +* +* @example +* var out = isQuote( '"' ); +* // returns true +* +* @example +* var out = isQuote( 'a' ); +* // returns false +*/ +function isQuote( ch ) { + return ( ch === '\'' || ch === '"' ); +} + +/** +* Tests whether a provided character is text. +* +* @private +* @param {string} ch - input character +* @returns {boolean} boolean indicating if a character is considered text +* +* @example +* var out = isText( 'a' ); +* // returns true +* +* @example +* var out = isText( ']' ); +* // returns false +*/ +function isText( ch ) { + return RE_TEXT.test( ch ); +} // MAIN // @@ -82,7 +124,7 @@ setNonEnumerableReadOnly( AutoMatcher.prototype, 'onKeypress', function onKeypre return; } // Remove auto-completed closing symbols when a user instinctively manually completes the closing symbol in order to avoid duplicate closing symbols... - if ( line[ cursor ] === data && AUTO_MATCH_SYMBOLS[ line[ cursor-2 ] ] === data ) { + if ( line[ cursor ] === data && AUTO_MATCH_SYMBOLS[ line[ cursor-2 ] ] === data ) { // eslint-disable-line max-len this._rli.write( null, { 'name': 'backspace' } ); @@ -98,16 +140,7 @@ setNonEnumerableReadOnly( AutoMatcher.prototype, 'onKeypress', function onKeypre ch = AUTO_MATCH_SYMBOLS[ data ]; if ( ch !== void 0 ) { // Avoid auto-completing quotation marks around text... - if ( - ( - ch === '\'' || - ch === '"' - ) && - ( - /^[a-zA-Z0-9"'/\\]$/.test( line[ cursor-2 ] ) || - /^[a-zA-Z0-9"'/\\]$/.test( line[ cursor ] ) - ) - ) { + if ( isQuote( ch ) && ( isText( line[ cursor-2 ] ) || isText( line[ cursor ] ) ) ) { return; } // Append a closing symbol: From 0c55033c0e6c40d32ce8f6b495a4b38e3a4ea957 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Thu, 28 Mar 2024 01:56:30 -0700 Subject: [PATCH 51/93] docs: add FIXME --- lib/node_modules/@stdlib/repl/lib/completer_preview.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/node_modules/@stdlib/repl/lib/completer_preview.js b/lib/node_modules/@stdlib/repl/lib/completer_preview.js index f1a8428c487..82735a29832 100644 --- a/lib/node_modules/@stdlib/repl/lib/completer_preview.js +++ b/lib/node_modules/@stdlib/repl/lib/completer_preview.js @@ -184,7 +184,7 @@ setNonEnumerableReadOnly( PreviewCompleter.prototype, 'clear', function clear() */ setNonEnumerableReadOnly( PreviewCompleter.prototype, 'onKeypress', function onKeypress() { // Check for existing content beyond the cursor which could "collide" with a preview completion... - if ( /[^a-zA-Z0-9_$]/.test( this._rli.line.substring( this._rli.cursor ) ) ) { + if ( /[^a-zA-Z0-9_$]/.test( this._rli.line.substring( this._rli.cursor ) ) ) { // FIXME: this is not robust (see https://mathiasbynens.be/notes/javascript-identifiers) return; } try { From ec2c283a354b46196790cd7f630089599bee313d Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Thu, 28 Mar 2024 16:34:27 -0700 Subject: [PATCH 52/93] refactor: add modules for specifying settings arguments amenable to auto-completion --- .../@stdlib/repl/lib/settings_alias_args.js | 48 +++++++++++++++++++ .../@stdlib/repl/lib/settings_aliases.js | 46 ++++++++++++++++++ 2 files changed, 94 insertions(+) create mode 100644 lib/node_modules/@stdlib/repl/lib/settings_alias_args.js create mode 100644 lib/node_modules/@stdlib/repl/lib/settings_aliases.js diff --git a/lib/node_modules/@stdlib/repl/lib/settings_alias_args.js b/lib/node_modules/@stdlib/repl/lib/settings_alias_args.js new file mode 100644 index 00000000000..ead6beda6e6 --- /dev/null +++ b/lib/node_modules/@stdlib/repl/lib/settings_alias_args.js @@ -0,0 +1,48 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2024 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +// MODULES // + +var SETTINGS_ALIASES = require( './settings_aliases.js' ); + + +// MAIN // + +/** +* Returns a list of argument completion flags for a specified settings API. +* +* @private +* @param {string} alias - alias +* @returns {(Array|null)} argument completion flags +*/ +function argFlags( alias ) { + var i; + for ( i = 0; i < SETTINGS_ALIASES.length; i++ ) { + if ( SETTINGS_ALIASES[ i ][ 0 ] === alias ) { + return SETTINGS_ALIASES[ i ].slice( 1 ); + } + } + return null; +} + + +// EXPORTS // + +module.exports = argFlags; diff --git a/lib/node_modules/@stdlib/repl/lib/settings_aliases.js b/lib/node_modules/@stdlib/repl/lib/settings_aliases.js new file mode 100644 index 00000000000..7e27cf22212 --- /dev/null +++ b/lib/node_modules/@stdlib/repl/lib/settings_aliases.js @@ -0,0 +1,46 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2024 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +// MAIN // + +/* +* List of settings API aliases and corresponding argument completion compatibility. +* +* ## Notes +* +* - Each entry in the list has the following format: +* +* ``` +* [ , , ... ] +* ``` +* +* where `` is a settings API alias and `` is a `boolean` indicating whether an argument is compatible with settings name completion. +* +* - For the purposes of TAB completion, only those positional arguments which expect settings names need to be included. For example, if an API has three parameters and only the first argument expects a settings name, only that first argument needs to be included below; the remaining two arguments can be omitted, as those arguments are assumed to be incompatible with settings name completion. If an API has three parameters and only the second argument expects a settings name, only the first two arguments need to be included below, with the first argument documented as `null`; the remaining argument can be omitted. +*/ +var aliases = [ + // Note: keep in alphabetical order... + [ 'settings', true ] +]; + + +// EXPORTS // + +module.exports = aliases; From 5212dcc28904fc8be1f52278dbdcdc7dc05a0172 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Thu, 28 Mar 2024 16:36:22 -0700 Subject: [PATCH 53/93] refactor: add module exporting a regexp for matching settings APIs --- .../@stdlib/repl/lib/regexp_settings.js | 106 ++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 lib/node_modules/@stdlib/repl/lib/regexp_settings.js diff --git a/lib/node_modules/@stdlib/repl/lib/regexp_settings.js b/lib/node_modules/@stdlib/repl/lib/regexp_settings.js new file mode 100644 index 00000000000..161d77940a1 --- /dev/null +++ b/lib/node_modules/@stdlib/repl/lib/regexp_settings.js @@ -0,0 +1,106 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2024 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +// MODULES // + +var SETTINGS_ALIASES = require( './settings_aliases.js' ); + + +// MAIN // + +/** +* Returns a regular expression for matching settings APIs. +* +* ## Notes +* +* - Example output: +* +* ```text +* /\b(?:(settings)\s*\(\s*(.*,\s*)*(?:\[\s*(?:[^\]]*,\s*)*)?['"]([^'"]*))$/ +* ``` +* +* @private +* @returns {RegExp} regular expression +*/ +function createRegExp() { + var re; + var N; + var M; + var i; + + N = SETTINGS_ALIASES.length; + M = N - 1; + re = ''; + + // Match a word boundary: + re += '\\b'; + + // Create a capture group for detecting an alias with an incomplete invocation (e.g., `settings( 'foo`): + re += '(?:'; + + // Create a capture group for matching the alias... + re += '('; + for ( i = 0; i < N; i++ ) { + // Append the alias: + re += SETTINGS_ALIASES[ i ][ 0 ]; + + // Separate aliases with an OR separator: + if ( i < M ) { + re += '|'; + } + } + // Close the alias capture group: + re += ')'; + + // Match zero or more whitespace characters after the alias: + re += '\\s*'; + + // Match an opening parenthesis literal: + re += '\\('; + + // Match zero or more whitespace characters after the opening parenthesis: + re += '\\s*'; + + // Capture provided (comma-separated) arguments which precede the last argument: + re += '(.*,\\s*)*'; + + // Capture, but don't remember, an incomplete array argument (including all items except for the last) which occurs zero or one time: + re += '(?:\\[\\s*(?:[^\\]]*,\\s*)*)?'; + + // Match either a `'` or `"` literal: + re += '[\'"]'; + + // Capture the last (incomplete) argument (or array item): + re += '([^\'"]*)'; + + // Close the incomplete invocation capture group: + re += ')'; + + // Match the end of input (i.e., ensure that the match is an incomplete invocation): + re += '$'; + + // Return the regular expression: + return new RegExp( re ); +} + + +// EXPORTS // + +module.exports = createRegExp; From da738c4dfc9ad16e1c5ff6ffa07857df78c49af2 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Thu, 28 Mar 2024 16:43:46 -0700 Subject: [PATCH 54/93] refactor: add support for settings name auto-completion --- .../@stdlib/repl/lib/complete_settings.js | 91 +++++++++++++++++++ .../@stdlib/repl/lib/completer.js | 17 ++++ 2 files changed, 108 insertions(+) create mode 100644 lib/node_modules/@stdlib/repl/lib/complete_settings.js diff --git a/lib/node_modules/@stdlib/repl/lib/complete_settings.js b/lib/node_modules/@stdlib/repl/lib/complete_settings.js new file mode 100644 index 00000000000..93672a1f4da --- /dev/null +++ b/lib/node_modules/@stdlib/repl/lib/complete_settings.js @@ -0,0 +1,91 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2024 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +// MODULES // + +var logger = require( 'debug' ); +var parse = require( 'acorn-loose' ).parse; +var startsWith = require( '@stdlib/string/starts-with' ); +var settingsAliasArgs = require( './settings_alias_args.js' ); +var SETTINGS_NAMES = require( './settings_names.js' ); + + +// VARIABLES // + +var debug = logger( 'repl:completer:settings' ); +var AOPTS = { + 'ecmaVersion': 'latest' +}; + + +// MAIN // + +/** +* Completes a settings API expression. +* +* @private +* @param {Array} out - output array for storing completions +* @param {REPL} repl - REPL instance +* @param {string} expression - expression to complete +* @param {string} alias - settings API alias +* @param {string} value - value to complete +* @returns {string} value filter +*/ +function complete( out, repl, expression, alias, value ) { + var args; + var ast; + var arg; + var v; + var i; + + // Get the list of argument types for the desired API: + debug( 'Settings API: %s', alias ); + args = settingsAliasArgs( alias ); + + // Parse the expression into an AST: + debug( 'Expression: %s', expression ); + ast = parse( expression, AOPTS ); + + // Check whether the argument which triggered TAB completion has a corresponding argument type which is completable: + debug( 'Checking if argument is completable...' ); + arg = args[ ast.body[ 0 ].expression.arguments.length-1 ]; + if ( !arg ) { + debug( 'Argument which triggered TAB completion is not completable.' ); + return ''; + } + debug( 'Argument is completable.' ); + + debug( 'Searching for completion candidates...' ); + for ( i = 0; i < SETTINGS_NAMES.length; i++ ) { + v = SETTINGS_NAMES[ i ]; + if ( startsWith( v, value ) ) { + debug( 'Found a completion: %s', v ); + out.push( v ); + } else { + debug( '%s does not match filter %s. Skipping...', v, value ); + } + } + return value; +} + + +// EXPORTS // + +module.exports = complete; diff --git a/lib/node_modules/@stdlib/repl/lib/completer.js b/lib/node_modules/@stdlib/repl/lib/completer.js index a8ca2b851b2..37bbcfae860 100644 --- a/lib/node_modules/@stdlib/repl/lib/completer.js +++ b/lib/node_modules/@stdlib/repl/lib/completer.js @@ -29,10 +29,12 @@ var fsRegExp = require( './regexp_fs_aliases.js' ); var requireRegExp = require( './regexp_require.js' ); var workspaceRegExp = require( './regexp_workspace.js' ); var tutorialRegExp = require( './regexp_tutorial.js' ); +var settingsRegExp = require( './regexp_settings.js' ); var completeRequire = require( './complete_require.js' ); var completeFS = require( './complete_fs.js' ); var completeWorkspace = require( './complete_workspace.js' ); var completeTutorial = require( './complete_tutorial.js' ); +var completeSettings = require( './complete_settings.js' ); var completeExpression = require( './complete_expression.js' ); @@ -162,6 +164,21 @@ function completer( repl ) { debug( 'Results: %s', res.join( ', ' ) ); return clbk( null, [ res, line ] ); } + // Test if the line has an incomplete settings expression: + match = line.match( settingsRegExp() ); + if ( match ) { + debug( 'Detected incomplete settings expression.' ); + + debug( 'Expression: %s', match[ 0 ] ); + debug( 'Settings API: %s', match[ 1 ] ); + debug( 'Value to complete: %s', match[ 3 ] ); + line = completeSettings( res, repl, match[ 0 ], match[ 1 ], match[ 3 ] ); // eslint-disable-line max-len + res = normalize( res ); + + debug( 'Completion filter: %s', line ); + debug( 'Results: %s', res.join( ', ' ) ); + return clbk( null, [ res, line ] ); + } debug( 'Attempting to complete an incomplete expression.' ); line = completeExpression( res, repl._context, line ); res = normalize( res ); From a90fc2d9eb76c41dd72d25d48a45dadbc52b7033 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Thu, 28 Mar 2024 17:48:15 -0700 Subject: [PATCH 55/93] refactor: defer to completer when receiving a TAB character --- lib/node_modules/@stdlib/repl/lib/main.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/node_modules/@stdlib/repl/lib/main.js b/lib/node_modules/@stdlib/repl/lib/main.js index 641098e3509..b417b01510e 100644 --- a/lib/node_modules/@stdlib/repl/lib/main.js +++ b/lib/node_modules/@stdlib/repl/lib/main.js @@ -312,8 +312,12 @@ function REPL( options ) { * @private * @param {string} data - input data * @param {Object} key - key object + * @returns {void} */ function onKeypress( data, key ) { + if ( key && key.name === 'tab' ) { + return; + } if ( self._settings.autoMatch ) { self._autoMatcher.onKeypress( data, key ); } From 0059b771d8fa30e01a6b7ce7fd7c97c9f3b8c8f7 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Fri, 29 Mar 2024 15:04:52 -0700 Subject: [PATCH 56/93] refactor: use internal utility to support suppressing log messages --- lib/node_modules/@stdlib/repl/lib/commands/settings.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/node_modules/@stdlib/repl/lib/commands/settings.js b/lib/node_modules/@stdlib/repl/lib/commands/settings.js index bc6af22145d..16b8ebab64f 100644 --- a/lib/node_modules/@stdlib/repl/lib/commands/settings.js +++ b/lib/node_modules/@stdlib/repl/lib/commands/settings.js @@ -24,6 +24,7 @@ var logger = require( 'debug' ); var format = require( '@stdlib/string/format' ); +var log = require( './../log.js' ); var SETTINGS = require( './../settings.js' ); var SETTINGS_NAMES = require( './../settings_names.js' ); @@ -108,7 +109,7 @@ function command( repl ) { repl._ostream.write( format( 'Error: %s\n', err.message ) ); return; } - repl._ostream.write( '\nSuccessfully updated setting.\n' ); + log( repl, '\nSuccessfully updated setting.' ); } } From 5e26c4518a835afdcd94036f2b2d23dcfd5d55a7 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Fri, 29 Mar 2024 18:36:24 -0700 Subject: [PATCH 57/93] refactor: reorder cases in alphabetical order --- .../repl/lib/complete_walk_find_last.js | 304 +++++++++--------- 1 file changed, 152 insertions(+), 152 deletions(-) diff --git a/lib/node_modules/@stdlib/repl/lib/complete_walk_find_last.js b/lib/node_modules/@stdlib/repl/lib/complete_walk_find_last.js index 8553ac5b020..79f0fd26009 100644 --- a/lib/node_modules/@stdlib/repl/lib/complete_walk_find_last.js +++ b/lib/node_modules/@stdlib/repl/lib/complete_walk_find_last.js @@ -75,83 +75,68 @@ function walk( node ) { // eslint-disable-line max-lines-per-function while ( FLG && node.type !== 'Identifier' && node.type !== 'MemberExpression' ) { debug( 'Node type: %s', node.type ); switch ( node.type ) { - case 'ExpressionStatement': - node = node.expression; + case 'ArrayExpression': + // `[ <|>` || `[ foo<|>` || `[ 1, 2, <|>` || `[ 1, 2, foo<|>` || etc + if ( node.elements.length === 0 ) { + FLG = false; + break; + } + node = node.elements[ node.elements.length-1 ]; + break; + case 'ArrowFunctionExpression': + // `() => <|>` || `() => { <|>` + node = node.body; break; case 'AssignmentExpression': // `x = <|>` || `x = foo<|>` node = node.right; break; - case 'LogicalExpression': - // `x || <|>` || `x || foo<|>` - node = node.right; - break; case 'BinaryExpression': // `x | <|>` || `x | foo<|>` node = node.right; break; - case 'UpdateExpression': - // `++<|>` || `++foo<|>` - node = node.argument; - break; - case 'YieldExpression': - // `yield foo<|>` - if ( node.argument ) { - node = node.argument; + case 'BlockStatement': + if ( node.body.length ) { + node = node.body[ node.body.length-1 ]; break; } - // `yield <|>` + out.keywords.push.apply( out.keywords, RESERVED_KEYWORDS_EMPTY_BLOCK_STATEMENT ); // eslint-disable-line max-len FLG = false; break; - case 'SequenceExpression': - // `x, foo<|>` - node = node.expressions[ node.expressions.length-1 ]; - break; - case 'VariableDeclaration': - // `var x = <|>` || `var x = foo<|>` || `let x = <|>` || `let x = foo<|>` || `const x = <|>` || `const x = foo<|>` || `var x = 5, y = <|>` || etc. - node = node.declarations[ node.declarations.length-1 ]; - break; - case 'VariableDeclarator': - // `var foo<|>` - if ( node.id.end === node.end ) { - debug( 'Detected attempt to complete a newly created variable identifier, which is not supported.' ); - out.context = 'none'; - FLG = false; + case 'CallExpression': + // `foo( bar, <|>` + if ( node.arguments.length ) { + debug( 'Detected attempt to complete a call expression argument.' ); + node = node.arguments[ node.arguments.length-1 ]; break; } - // `var x = <|>` || `var x = foo<|>` - node = node.init; + // `foo( <|>` + debug( 'Detected attempt to complete a call expression argument.' ); + FLG = false; break; - case 'ArrayExpression': - // `[ <|>` || `[ foo<|>` || `[ 1, 2, <|>` || `[ 1, 2, foo<|>` || etc - if ( node.elements.length === 0 ) { - FLG = false; + case 'ConditionalExpression': + // `( foo ) ? <|>` + if ( node.end === node.consequent.end ) { + debug( 'Detected attempt to complete within a conditional expression consequent.' ); + node = node.consequent; break; } - node = node.elements[ node.elements.length-1 ]; + // `( foo ) ? bar : <|>` + debug( 'Detected attempt to complete within a conditional expression alternate.' ); + node = node.alternate; break; - case 'ForStatement': - // Determine from where in the statement we are trying to TAB complete... - if ( node.body.type !== 'EmptyStatement' ) { + case 'DoWhileStatement': + // `do { <|>` + if ( node.end === node.body.end ) { node = node.body; break; } - // `for ( i = 0; i < 10; <|>` - if ( node.update ) { - debug( 'Detected attempt to complete within a for loop update expression.' ); - node = node.update; - break; - } - // `for ( i = 0; <|>` - if ( node.test ) { - debug( 'Detected attempt to complete within a for loop test expression.' ); - node = node.test; - break; - } - // By elimination, must be `init` (e.g., `for ( <|>`): - debug( 'Detected attempt to complete within a for loop initialization expression.' ); - node = node.init; - out.keywords.push( 'let', 'var' ); + // `do {} while ( <|>` + debug( 'Detected attempt to complete within a do-while loop test condition.' ); + node = node.test; + break; + case 'ExpressionStatement': + node = node.expression; break; case 'ForInStatement': // `for ( k in obj ) { <|>` @@ -173,63 +158,28 @@ function walk( node ) { // eslint-disable-line max-lines-per-function debug( 'Detected attempt to complete within a for-of loop condition expression.' ); node = node.right; break; - case 'WhileStatement': - // `while ( true ) { <|>` + case 'ForStatement': + // Determine from where in the statement we are trying to TAB complete... if ( node.body.type !== 'EmptyStatement' ) { node = node.body; break; } - // `while ( <|>` - debug( 'Detected attempt to complete within a while loop test condition.' ); - node = node.test; - break; - case 'DoWhileStatement': - // `do { <|>` - if ( node.end === node.body.end ) { - node = node.body; - break; - } - // `do {} while ( <|>` - debug( 'Detected attempt to complete within a do-while loop test condition.' ); - node = node.test; - break; - case 'BlockStatement': - if ( node.body.length ) { - node = node.body[ node.body.length-1 ]; - break; - } - out.keywords.push.apply( out.keywords, RESERVED_KEYWORDS_EMPTY_BLOCK_STATEMENT ); // eslint-disable-line max-len - FLG = false; - break; - case 'CallExpression': - // `foo( bar, <|>` - if ( node.arguments.length ) { - debug( 'Detected attempt to complete a call expression argument.' ); - node = node.arguments[ node.arguments.length-1 ]; - break; - } - // `foo( <|>` - debug( 'Detected attempt to complete a call expression argument.' ); - FLG = false; - break; - case 'NewExpression': - // `new <|>` || `new Foo<|>` - if ( node.end === node.callee.end ) { - debug( 'Detected attempt to complete a new expression callee name.' ); - out.context = 'NewExpression'; - node = node.callee; + // `for ( i = 0; i < 10; <|>` + if ( node.update ) { + debug( 'Detected attempt to complete within a for loop update expression.' ); + node = node.update; break; } - // `new Foo( bar, <|>` - if ( node.arguments.length ) { - debug( 'Detected attempt to complete a new expression argument.' ); - node = node.arguments[ node.arguments.length-1 ]; + // `for ( i = 0; <|>` + if ( node.test ) { + debug( 'Detected attempt to complete within a for loop test expression.' ); + node = node.test; break; } - // `new Foo( <|>` - debug( 'Detected attempt to complete a new expression argument.' ); - out.context = '*'; - FLG = false; + // By elimination, must be `init` (e.g., `for ( <|>`): + debug( 'Detected attempt to complete within a for loop initialization expression.' ); + node = node.init; + out.keywords.push( 'let', 'var' ); break; case 'FunctionDeclaration': // `function foo( <|>` @@ -255,19 +205,6 @@ function walk( node ) { // eslint-disable-line max-lines-per-function // `foo = function() { <|>` node = node.body; break; - case 'ArrowFunctionExpression': - // `() => <|>` || `() => { <|>` - node = node.body; - break; - case 'ReturnStatement': - // `return foo<|>` - if ( node.argument ) { - node = node.argument; - break; - } - // `return <|>` - FLG = false; - break; case 'IfStatement': // Determine from where in the statement we are trying to TAB complete... @@ -287,36 +224,54 @@ function walk( node ) { // eslint-disable-line max-lines-per-function debug( 'Detected attempt to complete within an if statement test condition.' ); node = node.test; break; - case 'ConditionalExpression': - // `( foo ) ? <|>` - if ( node.end === node.consequent.end ) { - debug( 'Detected attempt to complete within a conditional expression consequent.' ); - node = node.consequent; + case 'LogicalExpression': + // `x || <|>` || `x || foo<|>` + node = node.right; + break; + case 'NewExpression': + // `new <|>` || `new Foo<|>` + if ( node.end === node.callee.end ) { + debug( 'Detected attempt to complete a new expression callee name.' ); + out.context = 'NewExpression'; + node = node.callee; break; } - // `( foo ) ? bar : <|>` - debug( 'Detected attempt to complete within a conditional expression alternate.' ); - node = node.alternate; - break; - case 'SwitchStatement': - // `switch ( <|>` || `switch ( foo<|>` - if ( node.end === node.discriminant.end ) { - debug( 'Detected attempt to complete within a switch statement discriminant.' ); - node = node.discriminant; + // `new Foo( bar, <|>` + if ( node.arguments.length ) { + debug( 'Detected attempt to complete a new expression argument.' ); + node = node.arguments[ node.arguments.length-1 ]; break; } - // `switch ( foo ) { <|>` - if ( node.cases.length === 0 ) { - debug( 'Detected attempt to complete the `case` keyword.' ); - out.context = 'SwitchCase'; - out.filter = ''; - out.keywords.push( 'case', 'default' ); + // `new Foo( <|>` + debug( 'Detected attempt to complete a new expression argument.' ); + out.context = '*'; + FLG = false; + break; + case 'ObjectExpression': + // `{<|>` + if ( node.properties.length === 0 ) { FLG = false; break; } - // `switch ( foo ) { case 'bar': <|>` - debug( 'Detected attempt to complete within a switch statement case.' ); - node = node.cases[ node.cases.length-1 ]; + // `{ 'a': 1, ...<|>` || `{ 'a': 1, ...foo<|>` + node = node.properties[ node.properties.length-1 ]; + break; + case 'ReturnStatement': + // `return foo<|>` + if ( node.argument ) { + node = node.argument; + break; + } + // `return <|>` + FLG = false; + break; + case 'SequenceExpression': + // `x, foo<|>` + node = node.expressions[ node.expressions.length-1 ]; + break; + case 'SpreadElement': + // `[...<|>` || `[...foo<|>` + node = node.argument; break; case 'SwitchCase': if ( node.test === null ) { @@ -369,6 +324,34 @@ function walk( node ) { // eslint-disable-line max-lines-per-function out.keywords.push( 'break' ); FLG = false; break; + case 'SwitchStatement': + // `switch ( <|>` || `switch ( foo<|>` + if ( node.end === node.discriminant.end ) { + debug( 'Detected attempt to complete within a switch statement discriminant.' ); + node = node.discriminant; + break; + } + // `switch ( foo ) { <|>` + if ( node.cases.length === 0 ) { + debug( 'Detected attempt to complete the `case` keyword.' ); + out.context = 'SwitchCase'; + out.filter = ''; + out.keywords.push( 'case', 'default' ); + FLG = false; + break; + } + // `switch ( foo ) { case 'bar': <|>` + debug( 'Detected attempt to complete within a switch statement case.' ); + node = node.cases[ node.cases.length-1 ]; + break; + case 'TemplateLiteral': + // ``<|> + if ( node.expressions.length === 0 ) { + FLG = false; + break; + } + node = node.expressions[ node.expressions.length-1 ]; + break; case 'ThrowStatement': // `throw <|>` || `throw foo<|>` node = node.argument; @@ -377,26 +360,43 @@ function walk( node ) { // eslint-disable-line max-lines-per-function // `try { <|>` node = node.handler.body; break; - case 'TemplateLiteral': - // ``<|> - if ( node.expressions.length === 0 ) { + case 'VariableDeclaration': + // `var x = <|>` || `var x = foo<|>` || `let x = <|>` || `let x = foo<|>` || `const x = <|>` || `const x = foo<|>` || `var x = 5, y = <|>` || etc. + node = node.declarations[ node.declarations.length-1 ]; + break; + case 'VariableDeclarator': + // `var foo<|>` + if ( node.id.end === node.end ) { + debug( 'Detected attempt to complete a newly created variable identifier, which is not supported.' ); + out.context = 'none'; FLG = false; break; } - node = node.expressions[ node.expressions.length-1 ]; + // `var x = <|>` || `var x = foo<|>` + node = node.init; break; - case 'SpreadElement': - // `[...<|>` || `[...foo<|>` + case 'UpdateExpression': + // `++<|>` || `++foo<|>` node = node.argument; break; - case 'ObjectExpression': - // `{<|>` - if ( node.properties.length === 0 ) { - FLG = false; + case 'WhileStatement': + // `while ( true ) { <|>` + if ( node.body.type !== 'EmptyStatement' ) { + node = node.body; break; } - // `{ 'a': 1, ...<|>` || `{ 'a': 1, ...foo<|>` - node = node.properties[ node.properties.length-1 ]; + // `while ( <|>` + debug( 'Detected attempt to complete within a while loop test condition.' ); + node = node.test; + break; + case 'YieldExpression': + // `yield foo<|>` + if ( node.argument ) { + node = node.argument; + break; + } + // `yield <|>` + FLG = false; break; default: out.context = 'none'; From 98364f65ff2cf7fb7f017d864dac6e131a18791c Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Fri, 29 Mar 2024 23:01:18 -0700 Subject: [PATCH 58/93] refactor: fix order --- .../@stdlib/repl/lib/complete_walk_find_last.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/node_modules/@stdlib/repl/lib/complete_walk_find_last.js b/lib/node_modules/@stdlib/repl/lib/complete_walk_find_last.js index 79f0fd26009..3a1bfba0657 100644 --- a/lib/node_modules/@stdlib/repl/lib/complete_walk_find_last.js +++ b/lib/node_modules/@stdlib/repl/lib/complete_walk_find_last.js @@ -360,6 +360,10 @@ function walk( node ) { // eslint-disable-line max-lines-per-function // `try { <|>` node = node.handler.body; break; + case 'UpdateExpression': + // `++<|>` || `++foo<|>` + node = node.argument; + break; case 'VariableDeclaration': // `var x = <|>` || `var x = foo<|>` || `let x = <|>` || `let x = foo<|>` || `const x = <|>` || `const x = foo<|>` || `var x = 5, y = <|>` || etc. node = node.declarations[ node.declarations.length-1 ]; @@ -375,10 +379,6 @@ function walk( node ) { // eslint-disable-line max-lines-per-function // `var x = <|>` || `var x = foo<|>` node = node.init; break; - case 'UpdateExpression': - // `++<|>` || `++foo<|>` - node = node.argument; - break; case 'WhileStatement': // `while ( true ) { <|>` if ( node.body.type !== 'EmptyStatement' ) { From ab671c263cb6d84958c89715c3bc0c2a2513876b Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sat, 30 Mar 2024 17:07:32 -0700 Subject: [PATCH 59/93] refactor: update implementation to use AST This commit ensures that opening symbols are not auto-closed in strings and fixes unnecessary auto-insertion of closing characters when closing characters are already present. --- .../@stdlib/repl/lib/auto_match.js | 141 +++---- .../repl/lib/auto_match_close_symbols.js | 42 ++ ..._symbols.js => auto_match_open_symbols.js} | 6 +- .../@stdlib/repl/lib/auto_match_walk.js | 382 ++++++++++++++++++ lib/node_modules/@stdlib/repl/lib/main.js | 9 +- 5 files changed, 498 insertions(+), 82 deletions(-) create mode 100644 lib/node_modules/@stdlib/repl/lib/auto_match_close_symbols.js rename lib/node_modules/@stdlib/repl/lib/{auto_match_symbols.js => auto_match_open_symbols.js} (88%) create mode 100644 lib/node_modules/@stdlib/repl/lib/auto_match_walk.js diff --git a/lib/node_modules/@stdlib/repl/lib/auto_match.js b/lib/node_modules/@stdlib/repl/lib/auto_match.js index 309ecaec67c..c2c2a8b645a 100644 --- a/lib/node_modules/@stdlib/repl/lib/auto_match.js +++ b/lib/node_modules/@stdlib/repl/lib/auto_match.js @@ -23,55 +23,20 @@ // MODULES // var logger = require( 'debug' ); +var parse = require( 'acorn-loose' ).parse; var setNonEnumerableReadOnly = require( '@stdlib/utils/define-nonenumerable-read-only-property' ); -var AUTO_MATCH_SYMBOLS = require( './auto_match_symbols.js' ); +var isString = require( '@stdlib/assert/is-string' ).isPrimitive; +var walk = require( './auto_match_walk.js' ); +var AUTO_MATCH_OPEN_SYMBOLS = require( './auto_match_open_symbols.js' ); +var AUTO_MATCH_CLOSE_SYMBOLS = require( './auto_match_close_symbols.js' ); // VARIABLES // var debug = logger( 'repl:auto_match' ); -var RE_TEXT = /^[a-zA-Z0-9"'/\\]$/; - - -// FUNCTIONS // - -/** -* Tests whether a provided character is a quote symbol. -* -* @private -* @param {string} ch - input character -* @returns {boolean} boolean indicating if a character is a quote symbol -* -* @example -* var out = isQuote( '"' ); -* // returns true -* -* @example -* var out = isQuote( 'a' ); -* // returns false -*/ -function isQuote( ch ) { - return ( ch === '\'' || ch === '"' ); -} - -/** -* Tests whether a provided character is text. -* -* @private -* @param {string} ch - input character -* @returns {boolean} boolean indicating if a character is considered text -* -* @example -* var out = isText( 'a' ); -* // returns true -* -* @example -* var out = isText( ']' ); -* // returns false -*/ -function isText( ch ) { - return RE_TEXT.test( ch ); -} +var AOPTS = { + 'ecmaVersion': 'latest' +}; // MAIN // @@ -101,56 +66,78 @@ function AutoMatcher( rli ) { * @memberof AutoMatcher.prototype * @param {string} data - input data * @param {Object} key - key object -* @returns {void} +* @returns {boolean} boolean indicating whether auto-match was successful */ -setNonEnumerableReadOnly( AutoMatcher.prototype, 'onKeypress', function onKeypress( data, key ) { +setNonEnumerableReadOnly( AutoMatcher.prototype, 'onKeypress', function onKeypress( data ) { var cursor; var line; + var ast; + var out; var ch; cursor = this._rli.cursor; line = this._rli.line; - // If we are currently in the process of auto-matching, handle special cases... - if ( this._active ) { - // Automatically remove a closing symbol when deleting an opening symbol... - if ( key.name === 'backspace' ) { - this._rli.write( null, { - 'name': 'right' - } ); + debug( 'Expression: %s', line ); + debug( 'Cursor position: %d', cursor ); + + debug( 'Performing auto-match...' ); + debug( 'Checking for an opening symbol...' ); + ch = AUTO_MATCH_OPEN_SYMBOLS[ data ]; + if ( isString( ch ) ) { + debug( 'Detected an opening symbol.' ); + + // Generate an AST for the current line: + debug( 'Generating an AST...' ); + ast = parse( line, AOPTS ); + + // Attempt to walk the AST to determine whether to auto-match... + try { + debug( 'Determining whether to auto-match...' ); + out = walk( ast, cursor ); + } catch ( err ) { + // If parsing failed, stay conservative and don't auto-match: + debug( 'Error: %s', err.message ); + return false; + } + // If parsing succeeded and we should auto-match, go ahead and write the closing character... + if ( out && data !== line[ cursor ] ) { // NOTE: `data !== line[cursor]` accounts for `foo`` being valid syntax (i.e., using untagged template literals as tags); hence, we need to guard against unnecessarily inserting a closing symbol when a user types `foo<|>` and then instinctively types ` in order to close a template literal. + debug( 'Successfully detected an auto-match candidate. Inserting closing symbol...' ); + this._rli.write( ch ); this._rli.write( null, { - 'name': 'backspace' - } ); - return; + 'ctrl': true, + 'name': 'b' + }); + debug( 'Resulting expression: %s', this._rli.line ); + debug( 'Finished performing auto-match.' ); + return true; } - // Remove auto-completed closing symbols when a user instinctively manually completes the closing symbol in order to avoid duplicate closing symbols... - if ( line[ cursor ] === data && AUTO_MATCH_SYMBOLS[ line[ cursor-2 ] ] === data ) { // eslint-disable-line max-len + debug( 'Failed to detect an auto-match candidate.' ); + } + debug( 'Checking for a closing symbol...' ); + ch = AUTO_MATCH_CLOSE_SYMBOLS[ data ]; + if ( isString( ch ) ) { + debug( 'Detected a closing symbol.' ); + + // Support users who may instinctively add a closing symbol by skipping over the closing symbol character in order to avoid inserting an unwanted duplicate character... + debug( 'Determining whether a closing symbol already exists...' ); + if ( data === line[ cursor ] ) { + debug( 'Closing symbol already exists. Skipping over existing symbol...' ); this._rli.write( null, { 'name': 'backspace' - } ); + }); this._rli.write( null, { 'name': 'right' - } ); - this._active = false; - return; - } - // Reset the flag indicating that we are actively auto-matching: - this._active = false; - } - ch = AUTO_MATCH_SYMBOLS[ data ]; - if ( ch !== void 0 ) { - // Avoid auto-completing quotation marks around text... - if ( isQuote( ch ) && ( isText( line[ cursor-2 ] ) || isText( line[ cursor ] ) ) ) { - return; + }); + debug( 'Resulting expression: %s', this._rli.line ); + debug( 'Finished performing auto-match.' ); + return true; } - // Append a closing symbol: - this._rli.write( ch ); - this._rli.write( null, { - 'ctrl': true, - 'name': 'b' - }); - this._active = true; + debug( 'Did not find a closing symbol. Inserting closing symbol...' ); } + debug( 'Failed to detect a closing symbol.' ); + debug( 'Finished performing auto-match.' ); + return false; }); diff --git a/lib/node_modules/@stdlib/repl/lib/auto_match_close_symbols.js b/lib/node_modules/@stdlib/repl/lib/auto_match_close_symbols.js new file mode 100644 index 00000000000..7608e9976ce --- /dev/null +++ b/lib/node_modules/@stdlib/repl/lib/auto_match_close_symbols.js @@ -0,0 +1,42 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2024 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +// MAIN // + +/** +* Table mapping closing symbols with their opening counterparts. +* +* @private +* @name AUTO_MATCH_CLOSE_SYMBOLS +* @type {Object} +*/ +var AUTO_MATCH_CLOSE_SYMBOLS = { + '}': '{', + ']': '[', + ')': '(', + '\'': '\'', + '"': '"', + '`': '`' +}; + + +// EXPORTS // + +module.exports = AUTO_MATCH_CLOSE_SYMBOLS; diff --git a/lib/node_modules/@stdlib/repl/lib/auto_match_symbols.js b/lib/node_modules/@stdlib/repl/lib/auto_match_open_symbols.js similarity index 88% rename from lib/node_modules/@stdlib/repl/lib/auto_match_symbols.js rename to lib/node_modules/@stdlib/repl/lib/auto_match_open_symbols.js index 736b878590f..459d70be6bc 100644 --- a/lib/node_modules/@stdlib/repl/lib/auto_match_symbols.js +++ b/lib/node_modules/@stdlib/repl/lib/auto_match_open_symbols.js @@ -24,10 +24,10 @@ * Table mapping opening symbols with their closing counterparts. * * @private -* @name AUTO_MATCH_SYMBOLS +* @name AUTO_MATCH_OPEN_SYMBOLS * @type {Object} */ -var AUTO_MATCH_SYMBOLS = { +var AUTO_MATCH_OPEN_SYMBOLS = { '{': '}', '[': ']', '(': ')', @@ -39,4 +39,4 @@ var AUTO_MATCH_SYMBOLS = { // EXPORTS // -module.exports = AUTO_MATCH_SYMBOLS; +module.exports = AUTO_MATCH_OPEN_SYMBOLS; diff --git a/lib/node_modules/@stdlib/repl/lib/auto_match_walk.js b/lib/node_modules/@stdlib/repl/lib/auto_match_walk.js new file mode 100644 index 00000000000..2b9090454c9 --- /dev/null +++ b/lib/node_modules/@stdlib/repl/lib/auto_match_walk.js @@ -0,0 +1,382 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2024 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +// MODULES // + +var logger = require( 'debug' ); + + +// VARIABLES // + +var debug = logger( 'repl:auto_match:walk' ); + + +// FUNCTIONS // + +/** +* Returns the AST node associated with a provided cursor position. +* +* @private +* @param {Array} nodes - list of AST nodes +* @param {NonNegativeInteger} cursor - cursor position +* @returns {(Node|null)} associated AST node or null +*/ +function findNode( nodes, cursor ) { + var node; + var i; + for ( i = 0; i < nodes.length; i++ ) { + node = nodes[ i ]; + if ( node.start <= cursor && cursor <= node.end ) { + return node; + } + } + return null; +} + + +// MAIN // + +/** +* Walks an abstract syntax tree (AST) to determine whether to auto-match. +* +* @private +* @param {Node} ast - AST to walk +* @param {NonNegativeInteger} cursor - cursor position +* @returns {boolean} boolean indicating whether to auto-match +*/ +function walk( ast, cursor ) { + var node; + var tmp; + + debug( 'Searching for AST node associated with current cursor position...' ); + node = findNode( ast.body, cursor ); + + debug( 'Walking the AST...' ); + while ( node && ( node.type !== 'Identifier' || node.start === node.end ) ) { + debug( 'Node type: %s', node.type ); + switch ( node.type ) { + case 'ArrayExpression': + // `[<|>` + if ( node.elements.length === 0 ) { + debug( 'Detected the start of an array expression.' ); + return true; + } + // `['<|>` || `[ 1, '<|>` || `[ ['<|>, 1, 2, 3 ]` || etc + node = findNode( node.elements, cursor ); + break; + case 'ArrowFunctionExpression': + // `() => [<|>` || `() => { return '<|>` + node = node.body; + break; + case 'AssignmentExpression': + // `x[ = 5` + if ( node.left.type === 'Identifier' && node.left.start === node.left.end ) { + node = node.left; + break; + } + // `x = [<|>` || `x = foo['<|>` + node = node.right; + break; + case 'BinaryExpression': + // `x[ | 5` + if ( node.left.type === 'Identifier' && node.left.start === node.left.end ) { + node = node.left; + break; + } + // `x | foo[<|>` + node = node.right; + break; + case 'BlockStatement': + if ( node.body.length === 0 ) { + debug( 'Detected the start of a block statement.' ); + return true; + } + node = findNode( node.body, cursor ); + break; + case 'CallExpression': + // `foo(<|>` + if ( node.arguments.length === 0 ) { + debug( 'Detected the start of a call expression.' ); + return true; + } + // `foo( bar, x['<|>` + node = findNode( node.arguments, cursor ); + break; + case 'ConditionalExpression': + // `( foo ) ? '<|>` + if ( node.end === node.consequent.end ) { + node = node.consequent; + break; + } + // `( foo ) ? bar : '<|>` + node = node.alternate; + break; + case 'DoWhileStatement': + // `do {<|>` + if ( node.end === node.body.end ) { + node = node.body; + break; + } + // `do {} while (<|>` + if ( node.test.start === node.test.end ) { + debug( 'Detected the start of a do-while test.' ); + return true; + } + node = node.test; + break; + case 'EmptyStatement': + // `(` + debug( 'Detected the start of an empty statement.' ); + return true; + case 'ExpressionStatement': + node = node.expression; + break; + case 'ForInStatement': + // `for ( k in obj ) {<|>` + if ( node.body.type !== 'EmptyStatement' ) { + node = node.body; + break; + } + // We can omit the `left` case, as `for ( var i = '` will be parsed as a `ForStatement`: + node = node.right; + break; + case 'ForOfStatement': + // `for ( i of iter ) {<|>` + if ( node.body.type !== 'EmptyStatement' ) { + node = node.body; + break; + } + // We can omit the `left` case, as `for ( var i = '` will be parsed as a `ForStatement`: + node = node.right; + break; + case 'ForStatement': + // for ( i = 0; i < 10; i++ ) {<|> + if ( node.body.type !== 'EmptyStatement' ) { + node = node.body; + break; + } + // `for ( i = 0; i < 10; foo[<|>` + if ( node.update ) { + node = node.update; + break; + } + // `for ( i = 0; foo[<|>` + if ( node.test ) { + node = node.test; + break; + } + // By elimination, must be `init` (e.g., `for ( foo[<|>`): + node = node.init; + break; + case 'FunctionDeclaration': + // `function foo(<|>` + if ( node.body.start === node.body.end ) { + debug( 'Detected the start of a function declaration.' ); + return true; + } + // `function foo() {<|>` + node = node.body; + break; + case 'FunctionExpression': + // `foo = function(<|>` + if ( node.body.start === node.body.end ) { + debug( 'Detected the start of a function expression.' ); + return true; + } + // `foo = function() {<|>` + node = node.body; + break; + case 'Identifier': + if ( node.start === node.end ) { + debug( 'Detected an "empty" identifier.' ); + return true; + } + return false; + case 'IfStatement': + // `if ( foo ) {<|>` + if ( node.alternate ) { + node = node.alternate; + break; + } + // `if ( foo ) {} else {<|>` + if ( node.consequent.type !== 'EmptyStatement' ) { + node = node.consequent; + break; + } + // By elimination, must be `test` (e.g., `if (<|>`): + node = node.test; + break; + case 'Literal': + // `'<|>` || `"<|>` + if ( node.start === node.end-1 ) { + debug( 'Detected the start of a string literal.' ); + return true; + } + // `/'<|>` || `/'<|>/` + if ( node.regex ) { + debug( 'Detected a regular expression literal.' ); + return true; + } + // `'foo[<|>` + return false; + case 'LogicalExpression': + // `x[<|> || true` + if ( node.left.type === 'Identifier' && node.left.start === node.left.end ) { + node = node.left; + break; + } + // `x || [<|>` + node = node.right; + break; + case 'MemberExpression': + // `x['<|>` || `x['<|>] = 5` + if ( node.property.start === node.property.end || node.property.type === 'Literal' ) { + debug( 'Detected the start of a member expression.' ); + return true; + } + node = node.property; + break; + case 'NewExpression': + // `new (<|>` + if ( node.end === node.callee.end ) { + node = node.callee; + break; + } + // `new Foo(<|>` + if ( node.arguments.length === 0 ) { + debug( 'Detected the start of a new expression.' ); + return true; + } + // `new Foo( bar, '<|>` + node = findNode( node.arguments, cursor ); + break; + case 'ObjectExpression': + // `{<|>` + if ( node.properties.length === 0 ) { + debug( 'Detected the start of an object expression.' ); + return true; + } + // `{ 'a': 1, 'b': '<|>` + node = findNode( node.properties, cursor ); + break; + case 'ReturnStatement': + // `return '<|>` + node = node.argument; + break; + case 'SequenceExpression': + // `x, '<|>` + node = findNode( node.expressions, cursor ); + break; + case 'SpreadElement': + // `[...foo['<|>` + node = node.argument; + break; + case 'SwitchCase': + // `switch ( foo ) { case '<|>` + if ( node.end === node.test.end ) { + node = node.test; + break; + } + node = findNode( node.consequent, cursor ); + break; + case 'SwitchStatement': + // `switch ( '<|>` || `switch ( foo[ '<|>` + if ( node.end === node.discriminant.end ) { + node = node.discriminant; + break; + } + // `switch ( foo ) {<|>` + if ( node.cases.length === 0 ) { + debug( 'Detected the start of a switch statement.' ); + return true; + } + // `switch ( foo ) { case 'bar': '<|>` + node = findNode( node.cases, cursor ); + break; + case 'TaggedTemplateExpression': + tmp = findNode( [ node.tag ], cursor ); + if ( tmp && !findNode( [ node.quasi ], cursor ) ) { + node = node.tag; + break; + } + debug( 'Detected the start of a tagged template expression.' ); + node = node.quasi; + break; + case 'TemplateElement': + return false; + case 'TemplateLiteral': + // `<|> + if ( node.start === node.end-1 ) { + debug( 'Detected the start of a template literal.' ); + return true; + } + if ( node.expression.length > 0 ) { + tmp = findNode( node.expressions, cursor ); + if ( tmp ) { + node = tmp; + break; + } + } + node = findNode( node.quasis, cursor ); + break; + case 'ThrowStatement': + // `throw new errs[ '<|>` || `throw new Error( '` + node = node.argument; + break; + case 'TryStatement': + // `try { y = foo( '<|>` + node = node.handler.body; + break; + case 'UpdateExpression': + // `++foo['<|>` + node = node.argument; + break; + case 'VariableDeclaration': + // `var x = '<|>` || `var x = {'<|>` || `let x = ['<|>` || `let x = {'<|>` || `const x = '<|>` || `const x = {'<|>` || `var x = 5, y = '<|>` || etc. + node = findNode( node.declarations, cursor ); + break; + case 'VariableDeclarator': + // `var x = [<|>` || `var x = {<|>` || etc + node = node.init; + break; + case 'WhileStatement': + // `while ( true ) {<|>` + if ( node.body.type !== 'EmptyStatement' ) { + node = node.body; + break; + } + // `while (<|>` || `while ( foo[<|>` + node = node.test; + break; + case 'YieldExpression': + // `yield [<|>` || `yield {<|>` || etc + node = node.argument; + break; + default: + return false; + } + } + return false; +} + + +// EXPORTS // + +module.exports = walk; diff --git a/lib/node_modules/@stdlib/repl/lib/main.js b/lib/node_modules/@stdlib/repl/lib/main.js index b417b01510e..74a8e2cbeb9 100644 --- a/lib/node_modules/@stdlib/repl/lib/main.js +++ b/lib/node_modules/@stdlib/repl/lib/main.js @@ -315,14 +315,19 @@ function REPL( options ) { * @returns {void} */ function onKeypress( data, key ) { + var status; if ( key && key.name === 'tab' ) { return; } if ( self._settings.autoMatch ) { - self._autoMatcher.onKeypress( data, key ); + status = self._autoMatcher.onKeypress( data, key ); } if ( self._settings.completionPreviews ) { - self._previewCompleter.onKeypress( data, key ); + if ( status ) { + self._previewCompleter.clear(); + } else { + self._previewCompleter.onKeypress( data, key ); + } } } From 691b45b60382ce6123eba32524d263df0eb47e52 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sat, 30 Mar 2024 17:10:11 -0700 Subject: [PATCH 60/93] style: add lint warnings --- lib/node_modules/@stdlib/repl/lib/auto_match_walk.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/node_modules/@stdlib/repl/lib/auto_match_walk.js b/lib/node_modules/@stdlib/repl/lib/auto_match_walk.js index 2b9090454c9..37b88214428 100644 --- a/lib/node_modules/@stdlib/repl/lib/auto_match_walk.js +++ b/lib/node_modules/@stdlib/repl/lib/auto_match_walk.js @@ -61,7 +61,7 @@ function findNode( nodes, cursor ) { * @param {NonNegativeInteger} cursor - cursor position * @returns {boolean} boolean indicating whether to auto-match */ -function walk( ast, cursor ) { +function walk( ast, cursor ) { // eslint-disable-line max-lines-per-function var node; var tmp; @@ -167,7 +167,7 @@ function walk( ast, cursor ) { node = node.right; break; case 'ForStatement': - // for ( i = 0; i < 10; i++ ) {<|> + // `for ( i = 0; i < 10; i++ ) {<|>` if ( node.body.type !== 'EmptyStatement' ) { node = node.body; break; From cc6627b8fc651cbae31647428eae711c4d03c089 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sat, 30 Mar 2024 17:10:47 -0700 Subject: [PATCH 61/93] style: address lint warning --- lib/node_modules/@stdlib/repl/lib/main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/node_modules/@stdlib/repl/lib/main.js b/lib/node_modules/@stdlib/repl/lib/main.js index 74a8e2cbeb9..ab816acd51f 100644 --- a/lib/node_modules/@stdlib/repl/lib/main.js +++ b/lib/node_modules/@stdlib/repl/lib/main.js @@ -16,7 +16,7 @@ * limitations under the License. */ -/* eslint-disable no-restricted-syntax, no-invalid-this, no-underscore-dangle */ +/* eslint-disable no-restricted-syntax, no-invalid-this, no-underscore-dangle, max-lines */ 'use strict'; From 1be8b6b980829ab49bae24258f230c1fe9184e8a Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sat, 30 Mar 2024 17:14:58 -0700 Subject: [PATCH 62/93] test: add auto-match tests and move fixture --- .../array_expression_right_bracket.json | 23 ++ .../object_expression_right_brace.json | 18 + .../auto-match/negative/right_backtick.json | 35 ++ .../negative/right_double_quote.json | 25 ++ .../negative/right_parenthesis.json | 17 + .../negative/right_single_quote.json | 25 ++ .../auto-match/negative/template_literal.json | 35 ++ .../template_literal_with_expression.json | 52 +++ .../positive/arrow_function_body.json | 33 ++ ...binary_left_member_expression_literal.json | 37 ++ .../auto-match/positive/call_expression.json | 30 ++ ...pression_string_argument_single_quote.json | 38 ++ .../auto-match/positive/do_while_body.json | 29 ++ .../auto-match/positive/do_while_test.json | 29 ++ .../positive/do_while_test_left_bracket.json | 42 ++ .../auto-match/positive/for_body.json | 74 ++++ .../auto-match/positive/for_init.json | 30 ++ .../auto-match/positive/for_test.json | 73 ++++ .../positive/for_test_member_expression.json | 74 ++++ .../auto-match/positive/for_update.json | 79 ++++ .../for_update_member_expression.json | 80 ++++ .../positive/function_declaration_body.json | 33 ++ .../function_declaration_signature.json | 33 ++ .../auto-match/positive/left_backtick.json | 51 +++ .../auto-match/positive/left_brace.json | 18 + .../auto-match/positive/left_bracket.json | 23 ++ .../positive/left_double_quote.json | 25 ++ .../auto-match/positive/left_parenthesis.json | 17 + .../positive/left_single_quote.json | 25 ++ ...ogical_left_member_expression_literal.json | 37 ++ .../logical_with_left_member_expression.json | 54 +++ ...al_with_left_nested_member_expression.json | 87 +++++ .../logical_with_right_member_expression.json | 54 +++ .../member_assignment_expression.json | 49 +++ .../member_assignment_expression_literal.json | 37 ++ .../positive/member_expression.json | 37 ++ .../member_expression_call_expression.json | 43 +++ .../positive/regexp_body_single_quote.json | 42 ++ .../positive/regexp_single_quote.json | 40 ++ .../auto-match/positive/tagged_template.json | 62 +++ .../tagged_template_left_backtick.json | 91 +++++ .../auto-match/positive/three_backticks.json | 74 ++++ .../positive/variable_declaration_string.json | 38 ++ .../auto-match/positive/while_body.json | 30 ++ .../auto-match/positive/while_test.json | 28 ++ .../integration/fixtures/auto-match/script.js | 63 +++ .../test/{ => integration}/fixtures/repl.js | 2 +- .../repl/test/integration/test.auto_match.js | 360 ++++++++++++++++++ .../integration/test.completion_previews.js | 2 +- 49 files changed, 2331 insertions(+), 2 deletions(-) create mode 100644 lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/negative/array_expression_right_bracket.json create mode 100644 lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/negative/object_expression_right_brace.json create mode 100644 lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/negative/right_backtick.json create mode 100644 lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/negative/right_double_quote.json create mode 100644 lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/negative/right_parenthesis.json create mode 100644 lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/negative/right_single_quote.json create mode 100644 lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/negative/template_literal.json create mode 100644 lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/negative/template_literal_with_expression.json create mode 100644 lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/arrow_function_body.json create mode 100644 lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/binary_left_member_expression_literal.json create mode 100644 lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/call_expression.json create mode 100644 lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/call_expression_string_argument_single_quote.json create mode 100644 lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/do_while_body.json create mode 100644 lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/do_while_test.json create mode 100644 lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/do_while_test_left_bracket.json create mode 100644 lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/for_body.json create mode 100644 lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/for_init.json create mode 100644 lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/for_test.json create mode 100644 lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/for_test_member_expression.json create mode 100644 lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/for_update.json create mode 100644 lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/for_update_member_expression.json create mode 100644 lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/function_declaration_body.json create mode 100644 lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/function_declaration_signature.json create mode 100644 lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/left_backtick.json create mode 100644 lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/left_brace.json create mode 100644 lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/left_bracket.json create mode 100644 lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/left_double_quote.json create mode 100644 lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/left_parenthesis.json create mode 100644 lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/left_single_quote.json create mode 100644 lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/logical_left_member_expression_literal.json create mode 100644 lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/logical_with_left_member_expression.json create mode 100644 lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/logical_with_left_nested_member_expression.json create mode 100644 lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/logical_with_right_member_expression.json create mode 100644 lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/member_assignment_expression.json create mode 100644 lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/member_assignment_expression_literal.json create mode 100644 lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/member_expression.json create mode 100644 lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/member_expression_call_expression.json create mode 100644 lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/regexp_body_single_quote.json create mode 100644 lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/regexp_single_quote.json create mode 100644 lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/tagged_template.json create mode 100644 lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/tagged_template_left_backtick.json create mode 100644 lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/three_backticks.json create mode 100644 lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/variable_declaration_string.json create mode 100644 lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/while_body.json create mode 100644 lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/while_test.json create mode 100644 lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/script.js rename lib/node_modules/@stdlib/repl/test/{ => integration}/fixtures/repl.js (98%) create mode 100644 lib/node_modules/@stdlib/repl/test/integration/test.auto_match.js diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/negative/array_expression_right_bracket.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/negative/array_expression_right_bracket.json new file mode 100644 index 00000000000..08cd5bda846 --- /dev/null +++ b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/negative/array_expression_right_bracket.json @@ -0,0 +1,23 @@ +{ + "expression": "[]", + "cursor": 1, + "ast": { + "type": "Program", + "start": 0, + "end": 2, + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 2, + "expression": { + "type": "ArrayExpression", + "start": 0, + "end": 2, + "elements": [] + } + } + ], + "sourceType": "script" + } +} diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/negative/object_expression_right_brace.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/negative/object_expression_right_brace.json new file mode 100644 index 00000000000..af0eda1167e --- /dev/null +++ b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/negative/object_expression_right_brace.json @@ -0,0 +1,18 @@ +{ + "expression": "{}", + "cursor": 1, + "ast": { + "type": "Program", + "start": 0, + "end": 2, + "body": [ + { + "type": "BlockStatement", + "start": 0, + "end": 2, + "body": [] + } + ], + "sourceType": "script" + } +} diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/negative/right_backtick.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/negative/right_backtick.json new file mode 100644 index 00000000000..5348d6d37f8 --- /dev/null +++ b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/negative/right_backtick.json @@ -0,0 +1,35 @@ +{ + "expression": "``", + "cursor": 1, + "ast": { + "type": "Program", + "start": 0, + "end": 2, + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 2, + "expression": { + "type": "TemplateLiteral", + "start": 0, + "end": 2, + "expressions": [], + "quasis": [ + { + "type": "TemplateElement", + "start": 1, + "end": 1, + "value": { + "raw": "", + "cooked": "" + }, + "tail": true + } + ] + } + } + ], + "sourceType": "script" + } +} diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/negative/right_double_quote.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/negative/right_double_quote.json new file mode 100644 index 00000000000..9639e899d39 --- /dev/null +++ b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/negative/right_double_quote.json @@ -0,0 +1,25 @@ +{ + "expression": "\"\"", + "cursor": 1, + "ast": { + "type": "Program", + "start": 0, + "end": 2, + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 2, + "expression": { + "type": "Literal", + "start": 0, + "end": 2, + "value": "", + "raw": "\"\"" + }, + "directive": "" + } + ], + "sourceType": "script" + } +} diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/negative/right_parenthesis.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/negative/right_parenthesis.json new file mode 100644 index 00000000000..b73b4e93051 --- /dev/null +++ b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/negative/right_parenthesis.json @@ -0,0 +1,17 @@ +{ + "expression": "()", + "cursor": 1, + "ast": { + "type": "Program", + "start": 0, + "end": 2, + "body": [ + { + "type": "EmptyStatement", + "start": 0, + "end": 2 + } + ], + "sourceType": "script" + } +} diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/negative/right_single_quote.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/negative/right_single_quote.json new file mode 100644 index 00000000000..d35d8a7ee2c --- /dev/null +++ b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/negative/right_single_quote.json @@ -0,0 +1,25 @@ +{ + "expression": "''", + "cursor": 1, + "ast": { + "type": "Program", + "start": 0, + "end": 2, + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 2, + "expression": { + "type": "Literal", + "start": 0, + "end": 2, + "value": "", + "raw": "''" + }, + "directive": "" + } + ], + "sourceType": "script" + } +} diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/negative/template_literal.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/negative/template_literal.json new file mode 100644 index 00000000000..aa50464f6f1 --- /dev/null +++ b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/negative/template_literal.json @@ -0,0 +1,35 @@ +{ + "expression": "`foo`", + "cursor": 4, + "ast": { + "type": "Program", + "start": 0, + "end": 5, + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 5, + "expression": { + "type": "TemplateLiteral", + "start": 0, + "end": 5, + "expressions": [], + "quasis": [ + { + "type": "TemplateElement", + "start": 1, + "end": 4, + "value": { + "raw": "foo", + "cooked": "foo" + }, + "tail": true + } + ] + } + } + ], + "sourceType": "script" + } +} diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/negative/template_literal_with_expression.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/negative/template_literal_with_expression.json new file mode 100644 index 00000000000..e56eaf79a46 --- /dev/null +++ b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/negative/template_literal_with_expression.json @@ -0,0 +1,52 @@ +{ + "expression": "`foo${bar}`", + "cursor": 10, + "ast": { + "type": "Program", + "start": 0, + "end": 11, + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 11, + "expression": { + "type": "TemplateLiteral", + "start": 0, + "end": 11, + "expressions": [ + { + "type": "Identifier", + "start": 6, + "end": 9, + "name": "bar" + } + ], + "quasis": [ + { + "type": "TemplateElement", + "start": 1, + "end": 4, + "value": { + "raw": "foo", + "cooked": "foo" + }, + "tail": false + }, + { + "type": "TemplateElement", + "start": 10, + "end": 10, + "value": { + "raw": "", + "cooked": "" + }, + "tail": true + } + ] + } + } + ], + "sourceType": "script" + } +} diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/arrow_function_body.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/arrow_function_body.json new file mode 100644 index 00000000000..a51d9ac35b0 --- /dev/null +++ b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/arrow_function_body.json @@ -0,0 +1,33 @@ +{ + "expression": "() => {", + "cursor": 6, + "ast": { + "type": "Program", + "start": 0, + "end": 7, + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 7, + "expression": { + "type": "ArrowFunctionExpression", + "start": 0, + "end": 7, + "id": null, + "params": [], + "generator": false, + "expression": false, + "async": false, + "body": { + "type": "BlockStatement", + "start": 6, + "end": 7, + "body": [] + } + } + } + ], + "sourceType": "script" + } +} diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/binary_left_member_expression_literal.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/binary_left_member_expression_literal.json new file mode 100644 index 00000000000..6d86d276325 --- /dev/null +++ b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/binary_left_member_expression_literal.json @@ -0,0 +1,37 @@ +{ + "expression": "x['] | 1", + "cursor": 2, + "ast": { + "type": "Program", + "start": 0, + "end": 8, + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 8, + "expression": { + "type": "MemberExpression", + "start": 0, + "end": 8, + "object": { + "type": "Identifier", + "start": 0, + "end": 1, + "name": "x" + }, + "property": { + "type": "Literal", + "start": 2, + "end": 8, + "value": "] | 1", + "raw": "'] | 1" + }, + "computed": true, + "optional": false + } + } + ], + "sourceType": "script" + } +} diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/call_expression.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/call_expression.json new file mode 100644 index 00000000000..f2677a5ad96 --- /dev/null +++ b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/call_expression.json @@ -0,0 +1,30 @@ +{ + "expression": "noop(", + "cursor": 4, + "ast": { + "type": "Program", + "start": 0, + "end": 5, + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 5, + "expression": { + "type": "CallExpression", + "start": 0, + "end": 5, + "callee": { + "type": "Identifier", + "start": 0, + "end": 4, + "name": "noop" + }, + "arguments": [], + "optional": false + } + } + ], + "sourceType": "script" + } +} diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/call_expression_string_argument_single_quote.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/call_expression_string_argument_single_quote.json new file mode 100644 index 00000000000..243e6020206 --- /dev/null +++ b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/call_expression_string_argument_single_quote.json @@ -0,0 +1,38 @@ +{ + "expression": "noop( '", + "cursor": 6, + "ast": { + "type": "Program", + "start": 0, + "end": 7, + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 7, + "expression": { + "type": "CallExpression", + "start": 0, + "end": 7, + "callee": { + "type": "Identifier", + "start": 0, + "end": 4, + "name": "noop" + }, + "arguments": [ + { + "type": "Literal", + "start": 6, + "end": 7, + "value": "", + "raw": "'" + } + ], + "optional": false + } + } + ], + "sourceType": "script" + } +} diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/do_while_body.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/do_while_body.json new file mode 100644 index 00000000000..9ee3d13e953 --- /dev/null +++ b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/do_while_body.json @@ -0,0 +1,29 @@ +{ + "expression": "do {", + "cursor": 3, + "ast": { + "type": "Program", + "start": 0, + "end": 4, + "body": [ + { + "type": "DoWhileStatement", + "start": 0, + "end": 4, + "body": { + "type": "BlockStatement", + "start": 3, + "end": 4, + "body": [] + }, + "test": { + "type": "Identifier", + "start": 4, + "end": 4, + "name": "✖" + } + } + ], + "sourceType": "script" + } +} diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/do_while_test.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/do_while_test.json new file mode 100644 index 00000000000..0668c8d1569 --- /dev/null +++ b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/do_while_test.json @@ -0,0 +1,29 @@ +{ + "expression": "do {} while (", + "cursor": 12, + "ast": { + "type": "Program", + "start": 0, + "end": 13, + "body": [ + { + "type": "DoWhileStatement", + "start": 0, + "end": 13, + "body": { + "type": "BlockStatement", + "start": 3, + "end": 5, + "body": [] + }, + "test": { + "type": "Identifier", + "start": 13, + "end": 13, + "name": "✖" + } + } + ], + "sourceType": "script" + } +} diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/do_while_test_left_bracket.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/do_while_test_left_bracket.json new file mode 100644 index 00000000000..81bd83ae2a3 --- /dev/null +++ b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/do_while_test_left_bracket.json @@ -0,0 +1,42 @@ +{ + "expression": "do {} while ( x[ )", + "cursor": 15, + "ast": { + "type": "Program", + "start": 0, + "end": 18, + "body": [ + { + "type": "DoWhileStatement", + "start": 0, + "end": 18, + "body": { + "type": "BlockStatement", + "start": 3, + "end": 5, + "body": [] + }, + "test": { + "type": "MemberExpression", + "start": 14, + "end": 17, + "object": { + "type": "Identifier", + "start": 14, + "end": 15, + "name": "x" + }, + "property": { + "type": "Identifier", + "start": 17, + "end": 17, + "name": "✖" + }, + "computed": true, + "optional": false + } + } + ], + "sourceType": "script" + } +} diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/for_body.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/for_body.json new file mode 100644 index 00000000000..b019986cc3f --- /dev/null +++ b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/for_body.json @@ -0,0 +1,74 @@ +{ + "expression": "for ( i = 0; i < 10; i++ ) {", + "cursor": 27, + "ast": { + "type": "Program", + "start": 0, + "end": 28, + "body": [ + { + "type": "ForStatement", + "start": 0, + "end": 28, + "init": { + "type": "AssignmentExpression", + "start": 6, + "end": 11, + "operator": "=", + "left": { + "type": "Identifier", + "start": 6, + "end": 7, + "name": "i" + }, + "right": { + "type": "Literal", + "start": 10, + "end": 11, + "value": 0, + "raw": "0" + } + }, + "update": { + "type": "UpdateExpression", + "start": 21, + "end": 24, + "operator": "++", + "prefix": false, + "argument": { + "type": "Identifier", + "start": 21, + "end": 22, + "name": "i" + } + }, + "test": { + "type": "BinaryExpression", + "start": 13, + "end": 19, + "left": { + "type": "Identifier", + "start": 13, + "end": 14, + "name": "i" + }, + "operator": "<", + "right": { + "type": "Literal", + "start": 17, + "end": 19, + "value": 10, + "raw": "10" + } + }, + "body": { + "type": "BlockStatement", + "start": 27, + "end": 28, + "body": [] + } + } + ], + "sourceType": "script" + } +} diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/for_init.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/for_init.json new file mode 100644 index 00000000000..d9023ac5e8e --- /dev/null +++ b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/for_init.json @@ -0,0 +1,30 @@ +{ + "expression": "for (", + "cursor": 4, + "ast": { + "type": "Program", + "start": 0, + "end": 5, + "body": [ + { + "type": "ForStatement", + "start": 0, + "end": 5, + "init": { + "type": "Identifier", + "start": 5, + "end": 5, + "name": "✖" + }, + "update": null, + "test": null, + "body": { + "type": "EmptyStatement", + "start": 5, + "end": 5 + } + } + ], + "sourceType": "script" + } +} diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/for_test.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/for_test.json new file mode 100644 index 00000000000..c9a322be08d --- /dev/null +++ b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/for_test.json @@ -0,0 +1,73 @@ +{ + "expression": "for ( i = 0; i < x[", + "cursor": 18, + "ast": { + "type": "Program", + "start": 0, + "end": 19, + "body": [ + { + "type": "ForStatement", + "start": 0, + "end": 19, + "init": { + "type": "AssignmentExpression", + "start": 6, + "end": 11, + "operator": "=", + "left": { + "type": "Identifier", + "start": 6, + "end": 7, + "name": "i" + }, + "right": { + "type": "Literal", + "start": 10, + "end": 11, + "value": 0, + "raw": "0" + } + }, + "update": null, + "test": { + "type": "BinaryExpression", + "start": 13, + "end": 19, + "left": { + "type": "Identifier", + "start": 13, + "end": 14, + "name": "i" + }, + "operator": "<", + "right": { + "type": "MemberExpression", + "start": 17, + "end": 19, + "object": { + "type": "Identifier", + "start": 17, + "end": 18, + "name": "x" + }, + "property": { + "type": "Identifier", + "start": 19, + "end": 19, + "name": "✖" + }, + "computed": true, + "optional": false + } + }, + "body": { + "type": "EmptyStatement", + "start": 19, + "end": 19 + } + } + ], + "sourceType": "script" + } +} diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/for_test_member_expression.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/for_test_member_expression.json new file mode 100644 index 00000000000..f42bcba5081 --- /dev/null +++ b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/for_test_member_expression.json @@ -0,0 +1,74 @@ +{ + "expression": "for ( i = 0; i < x[']", + "cursor": 19, + "ast": { + "type": "Program", + "start": 0, + "end": 21, + "body": [ + { + "type": "ForStatement", + "start": 0, + "end": 21, + "init": { + "type": "AssignmentExpression", + "start": 6, + "end": 11, + "operator": "=", + "left": { + "type": "Identifier", + "start": 6, + "end": 7, + "name": "i" + }, + "right": { + "type": "Literal", + "start": 10, + "end": 11, + "value": 0, + "raw": "0" + } + }, + "update": null, + "test": { + "type": "BinaryExpression", + "start": 13, + "end": 21, + "left": { + "type": "Identifier", + "start": 13, + "end": 14, + "name": "i" + }, + "operator": "<", + "right": { + "type": "MemberExpression", + "start": 17, + "end": 21, + "object": { + "type": "Identifier", + "start": 17, + "end": 18, + "name": "x" + }, + "property": { + "type": "Literal", + "start": 19, + "end": 21, + "value": "]", + "raw": "']" + }, + "computed": true, + "optional": false + } + }, + "body": { + "type": "EmptyStatement", + "start": 21, + "end": 21 + } + } + ], + "sourceType": "script" + } +} diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/for_update.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/for_update.json new file mode 100644 index 00000000000..133c55fbba6 --- /dev/null +++ b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/for_update.json @@ -0,0 +1,79 @@ +{ + "expression": "for ( i = 0; i < 10; x[", + "cursor": 22, + "ast": { + "type": "Program", + "start": 0, + "end": 23, + "body": [ + { + "type": "ForStatement", + "start": 0, + "end": 23, + "init": { + "type": "AssignmentExpression", + "start": 6, + "end": 11, + "operator": "=", + "left": { + "type": "Identifier", + "start": 6, + "end": 7, + "name": "i" + }, + "right": { + "type": "Literal", + "start": 10, + "end": 11, + "value": 0, + "raw": "0" + } + }, + "update": { + "type": "MemberExpression", + "start": 21, + "end": 23, + "object": { + "type": "Identifier", + "start": 21, + "end": 22, + "name": "x" + }, + "property": { + "type": "Identifier", + "start": 23, + "end": 23, + "name": "✖" + }, + "computed": true, + "optional": false + }, + "test": { + "type": "BinaryExpression", + "start": 13, + "end": 19, + "left": { + "type": "Identifier", + "start": 13, + "end": 14, + "name": "i" + }, + "operator": "<", + "right": { + "type": "Literal", + "start": 17, + "end": 19, + "value": 10, + "raw": "10" + } + }, + "body": { + "type": "EmptyStatement", + "start": 23, + "end": 23 + } + } + ], + "sourceType": "script" + } +} diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/for_update_member_expression.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/for_update_member_expression.json new file mode 100644 index 00000000000..b69479546d8 --- /dev/null +++ b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/for_update_member_expression.json @@ -0,0 +1,80 @@ +{ + "expression": "for ( i = 0; i < 10; x[']", + "cursor": 23, + "ast": { + "type": "Program", + "start": 0, + "end": 25, + "body": [ + { + "type": "ForStatement", + "start": 0, + "end": 25, + "init": { + "type": "AssignmentExpression", + "start": 6, + "end": 11, + "operator": "=", + "left": { + "type": "Identifier", + "start": 6, + "end": 7, + "name": "i" + }, + "right": { + "type": "Literal", + "start": 10, + "end": 11, + "value": 0, + "raw": "0" + } + }, + "update": { + "type": "MemberExpression", + "start": 21, + "end": 25, + "object": { + "type": "Identifier", + "start": 21, + "end": 22, + "name": "x" + }, + "property": { + "type": "Literal", + "start": 23, + "end": 25, + "value": "]", + "raw": "']" + }, + "computed": true, + "optional": false + }, + "test": { + "type": "BinaryExpression", + "start": 13, + "end": 19, + "left": { + "type": "Identifier", + "start": 13, + "end": 14, + "name": "i" + }, + "operator": "<", + "right": { + "type": "Literal", + "start": 17, + "end": 19, + "value": 10, + "raw": "10" + } + }, + "body": { + "type": "EmptyStatement", + "start": 25, + "end": 25 + } + } + ], + "sourceType": "script" + } +} diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/function_declaration_body.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/function_declaration_body.json new file mode 100644 index 00000000000..497ea9a1489 --- /dev/null +++ b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/function_declaration_body.json @@ -0,0 +1,33 @@ +{ + "expression": "function noop() {", + "cursor": 16, + "ast": { + "type": "Program", + "start": 0, + "end": 17, + "body": [ + { + "type": "FunctionDeclaration", + "start": 0, + "end": 17, + "id": { + "type": "Identifier", + "start": 9, + "end": 13, + "name": "noop" + }, + "params": [], + "generator": false, + "expression": false, + "async": false, + "body": { + "type": "BlockStatement", + "start": 16, + "end": 17, + "body": [] + } + } + ], + "sourceType": "script" + } +} diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/function_declaration_signature.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/function_declaration_signature.json new file mode 100644 index 00000000000..431b588a66b --- /dev/null +++ b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/function_declaration_signature.json @@ -0,0 +1,33 @@ +{ + "expression": "function noop(", + "cursor": 13, + "ast": { + "type": "Program", + "start": 0, + "end": 14, + "body": [ + { + "type": "FunctionDeclaration", + "start": 0, + "end": 14, + "id": { + "type": "Identifier", + "start": 9, + "end": 13, + "name": "noop" + }, + "params": [], + "generator": false, + "expression": false, + "async": false, + "body": { + "type": "BlockStatement", + "start": 14, + "end": 14, + "body": [] + } + } + ], + "sourceType": "script" + } +} diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/left_backtick.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/left_backtick.json new file mode 100644 index 00000000000..086b6b5f686 --- /dev/null +++ b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/left_backtick.json @@ -0,0 +1,51 @@ +{ + "expression": "`", + "cursor": 0, + "ast": { + "type": "Program", + "start": 0, + "end": 1, + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 1, + "expression": { + "type": "TemplateLiteral", + "start": 0, + "end": 1, + "expressions": [ + { + "type": "Identifier", + "start": 1, + "end": 1, + "name": "✖" + } + ], + "quasis": [ + { + "type": "TemplateElement", + "start": 1, + "end": 1, + "value": { + "raw": "" + }, + "tail": false + }, + { + "type": "TemplateElement", + "start": 1, + "end": 1, + "value": { + "cooked": "", + "raw": "" + }, + "tail": true + } + ] + } + } + ], + "sourceType": "script" + } +} diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/left_brace.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/left_brace.json new file mode 100644 index 00000000000..79e13548328 --- /dev/null +++ b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/left_brace.json @@ -0,0 +1,18 @@ +{ + "expression": "{", + "cursor": 0, + "ast": { + "type": "Program", + "start": 0, + "end": 1, + "body": [ + { + "type": "BlockStatement", + "start": 0, + "end": 1, + "body": [] + } + ], + "sourceType": "script" + } +} diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/left_bracket.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/left_bracket.json new file mode 100644 index 00000000000..5873c89e4a5 --- /dev/null +++ b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/left_bracket.json @@ -0,0 +1,23 @@ +{ + "expression": "[", + "cursor": 0, + "ast": { + "type": "Program", + "start": 0, + "end": 1, + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 1, + "expression": { + "type": "ArrayExpression", + "start": 0, + "end": 1, + "elements": [] + } + } + ], + "sourceType": "script" + } +} diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/left_double_quote.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/left_double_quote.json new file mode 100644 index 00000000000..64af1833cca --- /dev/null +++ b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/left_double_quote.json @@ -0,0 +1,25 @@ +{ + "expression": "\"", + "cursor": 0, + "ast": { + "type": "Program", + "start": 0, + "end": 1, + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 1, + "expression": { + "type": "Literal", + "start": 0, + "end": 1, + "value": "", + "raw": "\"" + }, + "directive": "" + } + ], + "sourceType": "script" + } +} diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/left_parenthesis.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/left_parenthesis.json new file mode 100644 index 00000000000..fd32590f710 --- /dev/null +++ b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/left_parenthesis.json @@ -0,0 +1,17 @@ +{ + "expression": "(", + "cursor": 0, + "ast": { + "type": "Program", + "start": 0, + "end": 1, + "body": [ + { + "type": "EmptyStatement", + "start": 0, + "end": 1 + } + ], + "sourceType": "script" + } +} diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/left_single_quote.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/left_single_quote.json new file mode 100644 index 00000000000..c29e222e77e --- /dev/null +++ b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/left_single_quote.json @@ -0,0 +1,25 @@ +{ + "expression": "'", + "cursor": 0, + "ast": { + "type": "Program", + "start": 0, + "end": 1, + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 1, + "expression": { + "type": "Literal", + "start": 0, + "end": 1, + "value": "", + "raw": "'" + }, + "directive": "" + } + ], + "sourceType": "script" + } +} diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/logical_left_member_expression_literal.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/logical_left_member_expression_literal.json new file mode 100644 index 00000000000..0a07673b39f --- /dev/null +++ b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/logical_left_member_expression_literal.json @@ -0,0 +1,37 @@ +{ + "expression": "x['] || true", + "cursor": 2, + "ast": { + "type": "Program", + "start": 0, + "end": 12, + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 12, + "expression": { + "type": "MemberExpression", + "start": 0, + "end": 12, + "object": { + "type": "Identifier", + "start": 0, + "end": 1, + "name": "x" + }, + "property": { + "type": "Literal", + "start": 2, + "end": 12, + "value": "] || true", + "raw": "'] || true" + }, + "computed": true, + "optional": false + } + } + ], + "sourceType": "script" + } +} diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/logical_with_left_member_expression.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/logical_with_left_member_expression.json new file mode 100644 index 00000000000..6b0deea4810 --- /dev/null +++ b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/logical_with_left_member_expression.json @@ -0,0 +1,54 @@ +{ + "expression": "x[ || y", + "cursor": 1, + "ast": { + "type": "Program", + "start": 0, + "end": 7, + "body": + [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 7, + "expression": + { + "type": "MemberExpression", + "start": 0, + "end": 7, + "object": + { + "type": "Identifier", + "start": 0, + "end": 1, + "name": "x" + }, + "property": + { + "type": "LogicalExpression", + "start": 3, + "end": 7, + "left": + { + "type": "Identifier", + "start": 3, + "end": 3, + "name": "✖" + }, + "operator": "||", + "right": + { + "type": "Identifier", + "start": 6, + "end": 7, + "name": "y" + } + }, + "computed": true, + "optional": false + } + } + ], + "sourceType": "script" + } +} diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/logical_with_left_nested_member_expression.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/logical_with_left_nested_member_expression.json new file mode 100644 index 00000000000..51f11052a85 --- /dev/null +++ b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/logical_with_left_nested_member_expression.json @@ -0,0 +1,87 @@ +{ + "expression": "x[ z.f[ ] || y[]", + "cursor": 6, + "ast": { + "type": "Program", + "start": 0, + "end": 16, + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 16, + "expression": { + "type": "MemberExpression", + "start": 0, + "end": 16, + "object": { + "type": "Identifier", + "start": 0, + "end": 1, + "name": "x" + }, + "property": { + "type": "LogicalExpression", + "start": 3, + "end": 16, + "left": { + "type": "MemberExpression", + "start": 3, + "end": 9, + "object": { + "type": "MemberExpression", + "start": 3, + "end": 6, + "object": { + "type": "Identifier", + "start": 3, + "end": 4, + "name": "z" + }, + "property": { + "type": "Identifier", + "start": 5, + "end": 6, + "name": "f" + }, + "computed": false, + "optional": false + }, + "property": { + "type": "Identifier", + "start": 8, + "end": 8, + "name": "✖" + }, + "computed": true, + "optional": false + }, + "operator": "||", + "right": { + "type": "MemberExpression", + "start": 13, + "end": 16, + "object": { + "type": "Identifier", + "start": 13, + "end": 14, + "name": "y" + }, + "property": { + "type": "Identifier", + "start": 15, + "end": 15, + "name": "✖" + }, + "computed": true, + "optional": false + } + }, + "computed": true, + "optional": false + } + } + ], + "sourceType": "script" + } +} diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/logical_with_right_member_expression.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/logical_with_right_member_expression.json new file mode 100644 index 00000000000..c2bd4dca564 --- /dev/null +++ b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/logical_with_right_member_expression.json @@ -0,0 +1,54 @@ +{ + "expression": "x || x[", + "cursor": 6, + "ast": { + "type": "Program", + "start": 0, + "end": 7, + "body": + [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 7, + "expression": + { + "type": "LogicalExpression", + "start": 0, + "end": 7, + "left": + { + "type": "Identifier", + "start": 0, + "end": 1, + "name": "x" + }, + "operator": "||", + "right": + { + "type": "MemberExpression", + "start": 5, + "end": 7, + "object": + { + "type": "Identifier", + "start": 5, + "end": 6, + "name": "x" + }, + "property": + { + "type": "Identifier", + "start": 7, + "end": 7, + "name": "✖" + }, + "computed": true, + "optional": false + } + } + } + ], + "sourceType": "script" + } +} diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/member_assignment_expression.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/member_assignment_expression.json new file mode 100644 index 00000000000..b8e3289eb41 --- /dev/null +++ b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/member_assignment_expression.json @@ -0,0 +1,49 @@ +{ + "expression": "x[ = 5;", + "cursor": 1, + "ast": { + "type": "Program", + "start": 0, + "end": 7, + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 7, + "expression": { + "type": "MemberExpression", + "start": 0, + "end": 6, + "object": { + "type": "Identifier", + "start": 0, + "end": 1, + "name": "x" + }, + "property": { + "type": "AssignmentExpression", + "start": 3, + "end": 6, + "operator": "=", + "left": { + "type": "Identifier", + "start": 3, + "end": 3, + "name": "✖" + }, + "right": { + "type": "Literal", + "start": 5, + "end": 6, + "value": 5, + "raw": "5" + } + }, + "computed": true, + "optional": false + } + } + ], + "sourceType": "script" + } +} diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/member_assignment_expression_literal.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/member_assignment_expression_literal.json new file mode 100644 index 00000000000..327a1c8380e --- /dev/null +++ b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/member_assignment_expression_literal.json @@ -0,0 +1,37 @@ +{ + "expression": "x['] = 5;", + "cursor": 2, + "ast": { + "type": "Program", + "start": 0, + "end": 9, + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 9, + "expression": { + "type": "MemberExpression", + "start": 0, + "end": 9, + "object": { + "type": "Identifier", + "start": 0, + "end": 1, + "name": "x" + }, + "property": { + "type": "Literal", + "start": 2, + "end": 9, + "value": "] = 5;", + "raw": "'] = 5;" + }, + "computed": true, + "optional": false + } + } + ], + "sourceType": "script" + } +} diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/member_expression.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/member_expression.json new file mode 100644 index 00000000000..c2444e831aa --- /dev/null +++ b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/member_expression.json @@ -0,0 +1,37 @@ +{ + "expression": "x[ '", + "cursor": 3, + "ast": { + "type": "Program", + "start": 0, + "end": 4, + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 4, + "expression": { + "type": "MemberExpression", + "start": 0, + "end": 4, + "object": { + "type": "Identifier", + "start": 0, + "end": 1, + "name": "x" + }, + "property": { + "type": "Literal", + "start": 3, + "end": 4, + "value": "", + "raw": "'" + }, + "computed": true, + "optional": false + } + } + ], + "sourceType": "script" + } +} diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/member_expression_call_expression.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/member_expression_call_expression.json new file mode 100644 index 00000000000..6352e2e99fe --- /dev/null +++ b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/member_expression_call_expression.json @@ -0,0 +1,43 @@ +{ + "expression": "x[ foo( ]", + "cursor": 6, + "ast": { + "type": "Program", + "start": 0, + "end": 9, + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 9, + "expression": { + "type": "MemberExpression", + "start": 0, + "end": 9, + "object": { + "type": "Identifier", + "start": 0, + "end": 1, + "name": "x" + }, + "property": { + "type": "CallExpression", + "start": 3, + "end": 9, + "callee": { + "type": "Identifier", + "start": 3, + "end": 6, + "name": "foo" + }, + "arguments": [], + "optional": false + }, + "computed": true, + "optional": false + } + } + ], + "sourceType": "script" + } +} diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/regexp_body_single_quote.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/regexp_body_single_quote.json new file mode 100644 index 00000000000..99cd06dea64 --- /dev/null +++ b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/regexp_body_single_quote.json @@ -0,0 +1,42 @@ +{ + "expression": "var x = /'/;", + "cursor": 9, + "ast": { + "type": "Program", + "start": 0, + "end": 12, + "body": [ + { + "type": "VariableDeclaration", + "start": 0, + "end": 12, + "kind": "var", + "declarations": [ + { + "type": "VariableDeclarator", + "start": 4, + "end": 11, + "id": { + "type": "Identifier", + "start": 4, + "end": 5, + "name": "x" + }, + "init": { + "type": "Literal", + "start": 8, + "end": 11, + "regex": { + "pattern": "'", + "flags": "" + }, + "value": {}, + "raw": "/'/" + } + } + ] + } + ], + "sourceType": "script" + } +} diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/regexp_single_quote.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/regexp_single_quote.json new file mode 100644 index 00000000000..b36f28b6210 --- /dev/null +++ b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/regexp_single_quote.json @@ -0,0 +1,40 @@ +{ + "expression": "var x = /'", + "cursor": 9, + "ast": { + "type": "Program", + "start": 0, + "end": 10, + "body": [ + { + "type": "VariableDeclaration", + "start": 0, + "end": 10, + "kind": "var", + "declarations": [ + { + "type": "VariableDeclarator", + "start": 4, + "end": 10, + "id": { + "type": "Identifier", + "start": 4, + "end": 5, + "name": "x" + }, + "init": { + "type": "Literal", + "start": 9, + "end": 10, + "regex": { + "flags": "" + }, + "raw": "'" + } + } + ] + } + ], + "sourceType": "script" + } +} diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/tagged_template.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/tagged_template.json new file mode 100644 index 00000000000..3eb3b3f2d69 --- /dev/null +++ b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/tagged_template.json @@ -0,0 +1,62 @@ +{ + "expression": "foo`", + "cursor": 3, + "ast": { + "type": "Program", + "start": 0, + "end": 4, + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 4, + "expression": { + "type": "TaggedTemplateExpression", + "start": 0, + "end": 4, + "tag": { + "type": "Identifier", + "start": 0, + "end": 3, + "name": "foo" + }, + "quasi": { + "type": "TemplateLiteral", + "start": 3, + "end": 4, + "expressions": [ + { + "type": "Identifier", + "start": 4, + "end": 4, + "name": "✖" + } + ], + "quasis": [ + { + "type": "TemplateElement", + "start": 4, + "end": 4, + "value": { + "raw": "" + }, + "tail": false + }, + { + "type": "TemplateElement", + "start": 4, + "end": 4, + "value": { + "cooked": "", + "raw": "" + }, + "tail": true + } + ] + } + } + } + ], + "sourceType": "script" + } +} diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/tagged_template_left_backtick.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/tagged_template_left_backtick.json new file mode 100644 index 00000000000..0131a265703 --- /dev/null +++ b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/tagged_template_left_backtick.json @@ -0,0 +1,91 @@ +{ + "expression": "`foo${bar}``", + "cursor": 11, + "ast": { + "type": "Program", + "start": 0, + "end": 12, + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 12, + "expression": { + "type": "TaggedTemplateExpression", + "start": 0, + "end": 12, + "tag": { + "type": "TemplateLiteral", + "start": 0, + "end": 11, + "expressions": [ + { + "type": "Identifier", + "start": 6, + "end": 9, + "name": "bar" + } + ], + "quasis": [ + { + "type": "TemplateElement", + "start": 1, + "end": 4, + "value": { + "raw": "foo", + "cooked": "foo" + }, + "tail": false + }, + { + "type": "TemplateElement", + "start": 10, + "end": 10, + "value": { + "raw": "", + "cooked": "" + }, + "tail": true + } + ] + }, + "quasi": { + "type": "TemplateLiteral", + "start": 11, + "end": 12, + "expressions": [ + { + "type": "Identifier", + "start": 12, + "end": 12, + "name": "✖" + } + ], + "quasis": [ + { + "type": "TemplateElement", + "start": 12, + "end": 12, + "value": { + "raw": "" + }, + "tail": false + }, + { + "type": "TemplateElement", + "start": 12, + "end": 12, + "value": { + "cooked": "", + "raw": "" + }, + "tail": true + } + ] + } + } + } + ], + "sourceType": "script" + } +} diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/three_backticks.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/three_backticks.json new file mode 100644 index 00000000000..0f8a68a7d99 --- /dev/null +++ b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/three_backticks.json @@ -0,0 +1,74 @@ +{ + "expression": "```", + "cursor": 2, + "ast": { + "type": "Program", + "start": 0, + "end": 3, + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 3, + "expression": { + "type": "TaggedTemplateExpression", + "start": 0, + "end": 3, + "tag": { + "type": "TemplateLiteral", + "start": 0, + "end": 2, + "expressions": [], + "quasis": [ + { + "type": "TemplateElement", + "start": 1, + "end": 1, + "value": { + "raw": "", + "cooked": "" + }, + "tail": true + } + ] + }, + "quasi": { + "type": "TemplateLiteral", + "start": 2, + "end": 3, + "expressions": [ + { + "type": "Identifier", + "start": 3, + "end": 3, + "name": "✖" + } + ], + "quasis": [ + { + "type": "TemplateElement", + "start": 3, + "end": 3, + "value": { + "raw": "" + }, + "tail": false + }, + { + "type": "TemplateElement", + "start": 3, + "end": 3, + "value": { + "cooked": "", + "raw": "" + }, + "tail": true + } + ] + } + } + } + ], + "sourceType": "script" + } +} diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/variable_declaration_string.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/variable_declaration_string.json new file mode 100644 index 00000000000..d45a0a9e8b6 --- /dev/null +++ b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/variable_declaration_string.json @@ -0,0 +1,38 @@ +{ + "expression": "var x = '", + "cursor": 8, + "ast": { + "type": "Program", + "start": 0, + "end": 9, + "body": [ + { + "type": "VariableDeclaration", + "start": 0, + "end": 9, + "kind": "var", + "declarations": [ + { + "type": "VariableDeclarator", + "start": 4, + "end": 9, + "id": { + "type": "Identifier", + "start": 4, + "end": 5, + "name": "x" + }, + "init": { + "type": "Literal", + "start": 8, + "end": 9, + "value": "", + "raw": "'" + } + } + ] + } + ], + "sourceType": "script" + } +} diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/while_body.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/while_body.json new file mode 100644 index 00000000000..2fd33cd0ffc --- /dev/null +++ b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/while_body.json @@ -0,0 +1,30 @@ +{ + "expression": "while ( true ) {", + "cursor": 15, + "ast": { + "type": "Program", + "start": 0, + "end": 16, + "body": [ + { + "type": "WhileStatement", + "start": 0, + "end": 16, + "test": { + "type": "Literal", + "start": 8, + "end": 12, + "value": true, + "raw": "true" + }, + "body": { + "type": "BlockStatement", + "start": 15, + "end": 16, + "body": [] + } + } + ], + "sourceType": "script" + } +} diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/while_test.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/while_test.json new file mode 100644 index 00000000000..944a75ba9ee --- /dev/null +++ b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/while_test.json @@ -0,0 +1,28 @@ +{ + "expression": "while (", + "cursor": 6, + "ast": { + "type": "Program", + "start": 0, + "end": 7, + "body": [ + { + "type": "WhileStatement", + "start": 0, + "end": 7, + "test": { + "type": "Identifier", + "start": 7, + "end": 7, + "name": "✖" + }, + "body": { + "type": "EmptyStatement", + "start": 7, + "end": 7 + } + } + ], + "sourceType": "script" + } +} diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/script.js b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/script.js new file mode 100644 index 00000000000..00280e56cb7 --- /dev/null +++ b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/script.js @@ -0,0 +1,63 @@ +#!/usr/bin/env node + +/** +* @license Apache-2.0 +* +* Copyright (c) 2024 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +// MODULES // + +var resolve = require( 'path' ).resolve; +var parse = require( 'acorn-loose' ).parse; +var writeFile = require( '@stdlib/fs/write-file' ).sync; + + +// VARIABLES // + +var AOPTS = { + 'ecmaVersion': 'latest' +}; +var FOPTS = { + 'encoding': 'utf8' +}; + + +// MAIN // + +/** +* Main execution sequence. +* +* @private +*/ +function main() { + var str; + var ast; + var out; + + str = '``'; + ast = parse( str, AOPTS ); + + out = { + 'expression': str, + 'cursor': 0, + 'ast': ast + }; + writeFile( resolve( __dirname, 'negative', 'template_literal_empty.json' ), JSON.stringify( out, null, ' ' )+'\n', FOPTS ); +} + +main(); diff --git a/lib/node_modules/@stdlib/repl/test/fixtures/repl.js b/lib/node_modules/@stdlib/repl/test/integration/fixtures/repl.js similarity index 98% rename from lib/node_modules/@stdlib/repl/test/fixtures/repl.js rename to lib/node_modules/@stdlib/repl/test/integration/fixtures/repl.js index 7e702c4f037..d59238dd217 100644 --- a/lib/node_modules/@stdlib/repl/test/fixtures/repl.js +++ b/lib/node_modules/@stdlib/repl/test/integration/fixtures/repl.js @@ -24,7 +24,7 @@ var isFunction = require( '@stdlib/assert/is-function' ); var inspectSinkStream = require( '@stdlib/streams/node/inspect-sink' ); var assign = require( '@stdlib/object/assign' ); var format = require( '@stdlib/string/format' ); -var REPL = require( './../../lib' ); +var REPL = require( './../../../lib' ); // FUNCTIONS // diff --git a/lib/node_modules/@stdlib/repl/test/integration/test.auto_match.js b/lib/node_modules/@stdlib/repl/test/integration/test.auto_match.js new file mode 100644 index 00000000000..2f86985c248 --- /dev/null +++ b/lib/node_modules/@stdlib/repl/test/integration/test.auto_match.js @@ -0,0 +1,360 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2024 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +// MODULES // + +var resolve = require( 'path' ).resolve; +var tape = require( 'tape' ); +var DebugStream = require( '@stdlib/streams/node/debug' ); +var trim = require( '@stdlib/string/trim' ); +var replace = require( '@stdlib/string/replace' ); +var readDir = require( '@stdlib/fs/read-dir' ).sync; +var format = require( '@stdlib/string/format' ); +var AUTO_MATCH_OPEN_SYMBOLS = require( './../../lib/auto_match_open_symbols.js' ); +var repl = require( './fixtures/repl.js' ); + + +// VARIABLES // + +var RE_JSON = /\.json$/; + +var RE_ANSI = /[\u001B\u009B][[\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\d/#&.:=?%@~_]+)*|[a-zA-Z\d]+(?:;[-a-zA-Z\d/#&.:=?%@~_]*)*)?\u0007)|(?:(?:\d{1,4}(?:;\d{0,4})*)?[\dA-PR-TZcf-nq-uy=><~]))/g; // eslint-disable-line no-control-regex + +var POSITIVE_FIXTURES_DIR = resolve( __dirname, 'fixtures', 'auto-match', 'positive' ); +var POSITIVE_FIXTURES_FILES = filter( readDir( POSITIVE_FIXTURES_DIR ) ); + +var NEGATIVE_FIXTURES_DIR = resolve( __dirname, 'fixtures', 'auto-match', 'negative' ); +var NEGATIVE_FIXTURES_FILES = filter( readDir( NEGATIVE_FIXTURES_DIR ) ); + + +// FUNCTIONS // + +/** +* Filters a list of files for those having a `*.json` file extension. +* +* @private +* @param {Array} list - file list +* @returns {Array} filtered list +*/ +function filter( list ) { + var out; + var i; + + out = []; + for ( i = 0; i < list.length; i++ ) { + if ( RE_JSON.test( list[ i ] ) ) { + out.push( list[ i ] ); + } + } + return out; +} + +/** +* Splices a string. +* +* @private +* @param {string} str - input string +* @param {NonNegativeInteger} idx - index at which to splice +* @returns {Array} array containing the resulting string and the removed character +*/ +function splice( str, idx ) { + var parts; + var out; + + parts = [ + str.substring( 0, idx ), + str.substring( idx+1 ) + ]; + out = parts[ 0 ] + parts[ 1 ]; + return [ out, str[ idx ], parts ]; +} + +/** +* Removes ANSI escape codes from a string. +* +* @private +* @param {string} str - input string +* @returns {string} string with ANSI escape codes removed +*/ +function stripANSI( str ) { + return replace( str, RE_ANSI, '' ); +} + +/** +* Processes output stream text and returns a string representing what is currently displayed in the REPL. +* +* ## Notes +* +* - We can rely on simple concatenation when a test expression proceeds from left-to-right (i.e., as if a user normally types); however, when a user backtracks (e.g., by moving the cursor to the left), the REPL needs to refresh the displayed text (in full) in order to shift any text after the cursor to the right to make room for inserted characters. +* +* @private +* @param {Array} raw - unprocessed output data +* @param {boolean} flg - boolean indicating whether to concatenate unprocessed output data +* @returns {string} output string +*/ +function processOutput( raw, flg ) { + var i; + if ( flg ) { + return trim( stripANSI( raw.join( '' ) ) ); + } + for ( i = raw.length-1; i >= 0; i-- ) { + // Check whether the screen display was erased, as the next element is the refreshed line... + if ( raw[ i ] === '\u001b[0J' ) { + return raw[ i+1 ]; + } + } +} + +/** +* Converts splice results to an expected output string. +* +* @private +* @param {Array} s - splice results +* @returns {string} expected output string +*/ +function spliced2expected( s ) { + return s[ 2 ][ 0 ] + s[ 1 ] + AUTO_MATCH_OPEN_SYMBOLS[ s[1] ] + s[ 2 ][ 1 ]; +} + +/** +* Returns default settings. +* +* @private +* @returns {Object} default settings +*/ +function defaultSettings() { + return { + 'autoMatch': false, + 'completionPreviews': false + }; +} + +/** +* Moves a cursor backward a specified number of positions. +* +* @private +* @param {WriteStream} stream - writable stream +* @param {NonNegativeInteger} N - number of positions +*/ +function moveBack( stream, N ) { + var i; + for ( i = 0; i < N; i++ ) { + stream.write( '\u001b[1D' ); + } +} + +/** +* Asserts that a provided expression triggers expected automatic insertion. +* +* @private +* @param {Object} t - test object +* @param {Object} fixture - fixture object +* @param {string} fixture.expression - incomplete expression string +* @param {NonNegativeInteger} fixture.cursor - cursor position for inserting a character to trigger an insertion +* @param {Function} done - callback to invoke upon completion +*/ +function assertAutoMatch( t, fixture, done ) { + var expected; + var istream; + var opts; + var N; + var r; + var s; + + istream = new DebugStream({ + 'name': 'repl-input-stream' + }); + opts = { + 'input': istream, + 'inputPrompt': '', + 'quiet': true, + 'settings': defaultSettings() + }; + r = repl( opts, onClose ); + + // Create an incomplete expression: + s = splice( fixture.expression, fixture.cursor ); + + // Construct the expected output: + expected = spliced2expected( s ); + + // Emulate the presence of an existing expression: + istream.write( s[ 0 ] ); + + // Move the cursor to where we want to insert a character to trigger auto-close: + N = s[ 0 ].length - fixture.cursor; + moveBack( istream, N ); + + // Enable auto-match: + r.settings( 'autoMatch', true ); + + // Insert the character in order to trigger auto-close: + istream.write( s[ 1 ] ); + + // Close the input stream: + istream.end(); + + // Close the REPL: + r.close(); + + function onClose( error, data ) { + var actual; + if ( error ) { + t.fail( error.message ); + return; + } + actual = processOutput( data, N === 0 ); + t.strictEqual( actual, expected, 'returns expected value' ); + done(); + } +} + +/** +* Asserts that a provided expression does not trigger automatic insertion. +* +* @private +* @param {Object} t - test object +* @param {Object} fixture - fixture object +* @param {string} fixture.expression - incomplete expression string +* @param {NonNegativeInteger} fixture.cursor - cursor position for inserting a character to trigger an insertion +* @param {Function} done - callback to invoke upon completion +*/ +function assertNoAutoMatch( t, fixture, done ) { + var expected; + var istream; + var opts; + var N; + var r; + + istream = new DebugStream({ + 'name': 'repl-input-stream' + }); + opts = { + 'input': istream, + 'inputPrompt': '', + 'quiet': true, + 'settings': defaultSettings() + }; + r = repl( opts, onClose ); + + // Construct the expected output: + expected = fixture.expression; + + // Emulate the presence of an existing expression: + istream.write( fixture.expression ); + + // Move the cursor to where we want to insert a character: + N = fixture.expression.length - fixture.cursor; + moveBack( istream, N ); + + // Enable auto-match: + r.settings( 'autoMatch', true ); + + // Insert the character in order to trigger auto-close: + istream.write( fixture.expression[ fixture.cursor ] ); + + // Close the input stream: + istream.end(); + + // Close the REPL: + r.close(); + + function onClose( error, data ) { + var actual; + if ( error ) { + t.fail( error.message ); + return; + } + actual = processOutput( data, N === 0 ); + t.strictEqual( actual, expected, 'returns expected value' ); + done(); + } +} + +/** +* Generates a test name from a fixture file name. +* +* @private +* @param {string} msg - test description +* @param {string} filename - file name +* @returns {string} test name +*/ +function testName( msg, filename ) { + var str = replace( filename, RE_JSON, '' ); + str = replace( str, '_', ' ' ); + return format( '%s (%s)', msg, str ); +} + +/** +* Returns a test function for testing against a specified fixture file. +* +* @private +* @param {string} fpath - fixture file path +* @param {Function} assert - assertion function +* @returns {Function} test function +*/ +function testFcn( fpath, assert ) { + return test; + + function test( t ) { + var fixture = require( fpath ); // eslint-disable-line stdlib/no-dynamic-require + assert( t, fixture, done ); + + function done() { + t.end(); + } + } +} + +/** +* Run tests against test fixtures. +* +* @private +* @param {string} msg - test description +* @param {string} dir - fixtures directory +* @param {Array} fixtures - list of fixtures +* @param {Function} assert - assert function +*/ +function test( msg, dir, fixtures, assert ) { + var fpath; + var f; + var t; + var i; + + for ( i = 0; i < fixtures.length; i++ ) { + f = fixtures[ i ]; + t = testName( msg, f ); + fpath = resolve( dir, f ); + tape( t, testFcn( fpath, assert ) ); + } +} + + +// TESTS // + +tape( 'main export is a function', function test( t ) { + t.ok( true, __filename ); + t.strictEqual( typeof repl, 'function', 'main export is a function' ); + t.end(); +}); + +test( 'a REPL instance supports automatically closing paired symbols', POSITIVE_FIXTURES_DIR, POSITIVE_FIXTURES_FILES, assertAutoMatch ); + +test( 'a REPL instance avoids unnecessarily inserting closing symbols', NEGATIVE_FIXTURES_DIR, NEGATIVE_FIXTURES_FILES, assertNoAutoMatch ); diff --git a/lib/node_modules/@stdlib/repl/test/integration/test.completion_previews.js b/lib/node_modules/@stdlib/repl/test/integration/test.completion_previews.js index 6cda8239274..5fbb90da1d4 100644 --- a/lib/node_modules/@stdlib/repl/test/integration/test.completion_previews.js +++ b/lib/node_modules/@stdlib/repl/test/integration/test.completion_previews.js @@ -23,7 +23,7 @@ var tape = require( 'tape' ); var DebugStream = require( '@stdlib/streams/node/debug' ); var trim = require( '@stdlib/string/trim' ); -var repl = require( './../fixtures/repl.js' ); +var repl = require( './fixtures/repl.js' ); // TESTS // From ec672ab1f31bff6fc751eb0a85b552f5d57db0e6 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sat, 30 Mar 2024 17:28:03 -0700 Subject: [PATCH 63/93] refactor: rename setting --- .../{auto_match.js => auto_close_pairs.js} | 52 +++++++++---------- ...s.js => auto_close_pairs_close_symbols.js} | 6 +-- ...ls.js => auto_close_pairs_open_symbols.js} | 6 +-- ...match_walk.js => auto_close_pairs_walk.js} | 6 +-- lib/node_modules/@stdlib/repl/lib/defaults.js | 2 +- lib/node_modules/@stdlib/repl/lib/main.js | 12 ++--- lib/node_modules/@stdlib/repl/lib/settings.js | 2 +- .../@stdlib/repl/lib/validate_settings.js | 4 +- .../array_expression_right_bracket.json | 0 .../object_expression_right_brace.json | 0 .../negative/right_backtick.json | 0 .../negative/right_double_quote.json | 0 .../negative/right_parenthesis.json | 0 .../negative/right_single_quote.json | 0 .../negative/template_literal.json | 0 .../template_literal_with_expression.json | 0 .../positive/arrow_function_body.json | 0 ...binary_left_member_expression_literal.json | 0 .../positive/call_expression.json | 0 ...pression_string_argument_single_quote.json | 0 .../positive/do_while_body.json | 0 .../positive/do_while_test.json | 0 .../positive/do_while_test_left_bracket.json | 0 .../positive/for_body.json | 0 .../positive/for_init.json | 0 .../positive/for_test.json | 0 .../positive/for_test_member_expression.json | 0 .../positive/for_update.json | 0 .../for_update_member_expression.json | 0 .../positive/function_declaration_body.json | 0 .../function_declaration_signature.json | 0 .../positive/left_backtick.json | 0 .../positive/left_brace.json | 0 .../positive/left_bracket.json | 0 .../positive/left_double_quote.json | 0 .../positive/left_parenthesis.json | 0 .../positive/left_single_quote.json | 0 ...ogical_left_member_expression_literal.json | 0 .../logical_with_left_member_expression.json | 0 ...al_with_left_nested_member_expression.json | 0 .../logical_with_right_member_expression.json | 0 .../member_assignment_expression.json | 0 .../member_assignment_expression_literal.json | 0 .../positive/member_expression.json | 0 .../member_expression_call_expression.json | 0 .../positive/regexp_body_single_quote.json | 0 .../positive/regexp_single_quote.json | 0 .../positive/tagged_template.json | 0 .../tagged_template_left_backtick.json | 0 .../positive/three_backticks.json | 0 .../positive/variable_declaration_string.json | 0 .../positive/while_body.json | 0 .../positive/while_test.json | 0 .../script.js | 0 ...auto_match.js => test.auto_close_pairs.js} | 26 +++++----- 55 files changed, 58 insertions(+), 58 deletions(-) rename lib/node_modules/@stdlib/repl/lib/{auto_match.js => auto_close_pairs.js} (71%) rename lib/node_modules/@stdlib/repl/lib/{auto_match_close_symbols.js => auto_close_pairs_close_symbols.js} (88%) rename lib/node_modules/@stdlib/repl/lib/{auto_match_open_symbols.js => auto_close_pairs_open_symbols.js} (88%) rename lib/node_modules/@stdlib/repl/lib/{auto_match_walk.js => auto_close_pairs_walk.js} (98%) rename lib/node_modules/@stdlib/repl/test/integration/fixtures/{auto-match => auto-close-pairs}/negative/array_expression_right_bracket.json (100%) rename lib/node_modules/@stdlib/repl/test/integration/fixtures/{auto-match => auto-close-pairs}/negative/object_expression_right_brace.json (100%) rename lib/node_modules/@stdlib/repl/test/integration/fixtures/{auto-match => auto-close-pairs}/negative/right_backtick.json (100%) rename lib/node_modules/@stdlib/repl/test/integration/fixtures/{auto-match => auto-close-pairs}/negative/right_double_quote.json (100%) rename lib/node_modules/@stdlib/repl/test/integration/fixtures/{auto-match => auto-close-pairs}/negative/right_parenthesis.json (100%) rename lib/node_modules/@stdlib/repl/test/integration/fixtures/{auto-match => auto-close-pairs}/negative/right_single_quote.json (100%) rename lib/node_modules/@stdlib/repl/test/integration/fixtures/{auto-match => auto-close-pairs}/negative/template_literal.json (100%) rename lib/node_modules/@stdlib/repl/test/integration/fixtures/{auto-match => auto-close-pairs}/negative/template_literal_with_expression.json (100%) rename lib/node_modules/@stdlib/repl/test/integration/fixtures/{auto-match => auto-close-pairs}/positive/arrow_function_body.json (100%) rename lib/node_modules/@stdlib/repl/test/integration/fixtures/{auto-match => auto-close-pairs}/positive/binary_left_member_expression_literal.json (100%) rename lib/node_modules/@stdlib/repl/test/integration/fixtures/{auto-match => auto-close-pairs}/positive/call_expression.json (100%) rename lib/node_modules/@stdlib/repl/test/integration/fixtures/{auto-match => auto-close-pairs}/positive/call_expression_string_argument_single_quote.json (100%) rename lib/node_modules/@stdlib/repl/test/integration/fixtures/{auto-match => auto-close-pairs}/positive/do_while_body.json (100%) rename lib/node_modules/@stdlib/repl/test/integration/fixtures/{auto-match => auto-close-pairs}/positive/do_while_test.json (100%) rename lib/node_modules/@stdlib/repl/test/integration/fixtures/{auto-match => auto-close-pairs}/positive/do_while_test_left_bracket.json (100%) rename lib/node_modules/@stdlib/repl/test/integration/fixtures/{auto-match => auto-close-pairs}/positive/for_body.json (100%) rename lib/node_modules/@stdlib/repl/test/integration/fixtures/{auto-match => auto-close-pairs}/positive/for_init.json (100%) rename lib/node_modules/@stdlib/repl/test/integration/fixtures/{auto-match => auto-close-pairs}/positive/for_test.json (100%) rename lib/node_modules/@stdlib/repl/test/integration/fixtures/{auto-match => auto-close-pairs}/positive/for_test_member_expression.json (100%) rename lib/node_modules/@stdlib/repl/test/integration/fixtures/{auto-match => auto-close-pairs}/positive/for_update.json (100%) rename lib/node_modules/@stdlib/repl/test/integration/fixtures/{auto-match => auto-close-pairs}/positive/for_update_member_expression.json (100%) rename lib/node_modules/@stdlib/repl/test/integration/fixtures/{auto-match => auto-close-pairs}/positive/function_declaration_body.json (100%) rename lib/node_modules/@stdlib/repl/test/integration/fixtures/{auto-match => auto-close-pairs}/positive/function_declaration_signature.json (100%) rename lib/node_modules/@stdlib/repl/test/integration/fixtures/{auto-match => auto-close-pairs}/positive/left_backtick.json (100%) rename lib/node_modules/@stdlib/repl/test/integration/fixtures/{auto-match => auto-close-pairs}/positive/left_brace.json (100%) rename lib/node_modules/@stdlib/repl/test/integration/fixtures/{auto-match => auto-close-pairs}/positive/left_bracket.json (100%) rename lib/node_modules/@stdlib/repl/test/integration/fixtures/{auto-match => auto-close-pairs}/positive/left_double_quote.json (100%) rename lib/node_modules/@stdlib/repl/test/integration/fixtures/{auto-match => auto-close-pairs}/positive/left_parenthesis.json (100%) rename lib/node_modules/@stdlib/repl/test/integration/fixtures/{auto-match => auto-close-pairs}/positive/left_single_quote.json (100%) rename lib/node_modules/@stdlib/repl/test/integration/fixtures/{auto-match => auto-close-pairs}/positive/logical_left_member_expression_literal.json (100%) rename lib/node_modules/@stdlib/repl/test/integration/fixtures/{auto-match => auto-close-pairs}/positive/logical_with_left_member_expression.json (100%) rename lib/node_modules/@stdlib/repl/test/integration/fixtures/{auto-match => auto-close-pairs}/positive/logical_with_left_nested_member_expression.json (100%) rename lib/node_modules/@stdlib/repl/test/integration/fixtures/{auto-match => auto-close-pairs}/positive/logical_with_right_member_expression.json (100%) rename lib/node_modules/@stdlib/repl/test/integration/fixtures/{auto-match => auto-close-pairs}/positive/member_assignment_expression.json (100%) rename lib/node_modules/@stdlib/repl/test/integration/fixtures/{auto-match => auto-close-pairs}/positive/member_assignment_expression_literal.json (100%) rename lib/node_modules/@stdlib/repl/test/integration/fixtures/{auto-match => auto-close-pairs}/positive/member_expression.json (100%) rename lib/node_modules/@stdlib/repl/test/integration/fixtures/{auto-match => auto-close-pairs}/positive/member_expression_call_expression.json (100%) rename lib/node_modules/@stdlib/repl/test/integration/fixtures/{auto-match => auto-close-pairs}/positive/regexp_body_single_quote.json (100%) rename lib/node_modules/@stdlib/repl/test/integration/fixtures/{auto-match => auto-close-pairs}/positive/regexp_single_quote.json (100%) rename lib/node_modules/@stdlib/repl/test/integration/fixtures/{auto-match => auto-close-pairs}/positive/tagged_template.json (100%) rename lib/node_modules/@stdlib/repl/test/integration/fixtures/{auto-match => auto-close-pairs}/positive/tagged_template_left_backtick.json (100%) rename lib/node_modules/@stdlib/repl/test/integration/fixtures/{auto-match => auto-close-pairs}/positive/three_backticks.json (100%) rename lib/node_modules/@stdlib/repl/test/integration/fixtures/{auto-match => auto-close-pairs}/positive/variable_declaration_string.json (100%) rename lib/node_modules/@stdlib/repl/test/integration/fixtures/{auto-match => auto-close-pairs}/positive/while_body.json (100%) rename lib/node_modules/@stdlib/repl/test/integration/fixtures/{auto-match => auto-close-pairs}/positive/while_test.json (100%) rename lib/node_modules/@stdlib/repl/test/integration/fixtures/{auto-match => auto-close-pairs}/script.js (100%) rename lib/node_modules/@stdlib/repl/test/integration/{test.auto_match.js => test.auto_close_pairs.js} (94%) diff --git a/lib/node_modules/@stdlib/repl/lib/auto_match.js b/lib/node_modules/@stdlib/repl/lib/auto_close_pairs.js similarity index 71% rename from lib/node_modules/@stdlib/repl/lib/auto_match.js rename to lib/node_modules/@stdlib/repl/lib/auto_close_pairs.js index c2c2a8b645a..50c6679bb50 100644 --- a/lib/node_modules/@stdlib/repl/lib/auto_match.js +++ b/lib/node_modules/@stdlib/repl/lib/auto_close_pairs.js @@ -26,14 +26,14 @@ var logger = require( 'debug' ); var parse = require( 'acorn-loose' ).parse; var setNonEnumerableReadOnly = require( '@stdlib/utils/define-nonenumerable-read-only-property' ); var isString = require( '@stdlib/assert/is-string' ).isPrimitive; -var walk = require( './auto_match_walk.js' ); -var AUTO_MATCH_OPEN_SYMBOLS = require( './auto_match_open_symbols.js' ); -var AUTO_MATCH_CLOSE_SYMBOLS = require( './auto_match_close_symbols.js' ); +var walk = require( './auto_close_pairs_walk.js' ); +var OPEN_SYMBOLS = require( './auto_close_pairs_open_symbols.js' ); +var CLOSE_SYMBOLS = require( './auto_close_pairs_close_symbols.js' ); // VARIABLES // -var debug = logger( 'repl:auto_match' ); +var debug = logger( 'repl:auto_close_pairs' ); var AOPTS = { 'ecmaVersion': 'latest' }; @@ -42,18 +42,18 @@ var AOPTS = { // MAIN // /** -* Constructor for creating an auto-matcher. +* Constructor for creating an auto-closer. * * @private * @constructor * @param {Object} rli - readline instance -* @returns {AutoMatcher} auto-matcher instance +* @returns {AutoCloser} auto-closer instance */ -function AutoMatcher( rli ) { - if ( !(this instanceof AutoMatcher) ) { - return new AutoMatcher(); +function AutoCloser( rli ) { + if ( !(this instanceof AutoCloser) ) { + return new AutoCloser(); } - debug( 'Creating an auto-matcher...' ); + debug( 'Creating an auto-closer...' ); this._rli = rli; this._active = false; return this; @@ -63,12 +63,12 @@ function AutoMatcher( rli ) { * Callback for handling a "keypress" event. * * @name onKeypress -* @memberof AutoMatcher.prototype +* @memberof AutoCloser.prototype * @param {string} data - input data * @param {Object} key - key object -* @returns {boolean} boolean indicating whether auto-match was successful +* @returns {boolean} boolean indicating whether auto-close was successful */ -setNonEnumerableReadOnly( AutoMatcher.prototype, 'onKeypress', function onKeypress( data ) { +setNonEnumerableReadOnly( AutoCloser.prototype, 'onKeypress', function onKeypress( data ) { var cursor; var line; var ast; @@ -81,9 +81,9 @@ setNonEnumerableReadOnly( AutoMatcher.prototype, 'onKeypress', function onKeypre debug( 'Expression: %s', line ); debug( 'Cursor position: %d', cursor ); - debug( 'Performing auto-match...' ); + debug( 'Performing auto-close...' ); debug( 'Checking for an opening symbol...' ); - ch = AUTO_MATCH_OPEN_SYMBOLS[ data ]; + ch = OPEN_SYMBOLS[ data ]; if ( isString( ch ) ) { debug( 'Detected an opening symbol.' ); @@ -91,31 +91,31 @@ setNonEnumerableReadOnly( AutoMatcher.prototype, 'onKeypress', function onKeypre debug( 'Generating an AST...' ); ast = parse( line, AOPTS ); - // Attempt to walk the AST to determine whether to auto-match... + // Attempt to walk the AST to determine whether to auto-close... try { - debug( 'Determining whether to auto-match...' ); + debug( 'Determining whether to auto-close...' ); out = walk( ast, cursor ); } catch ( err ) { - // If parsing failed, stay conservative and don't auto-match: + // If parsing failed, stay conservative and don't auto-close: debug( 'Error: %s', err.message ); return false; } - // If parsing succeeded and we should auto-match, go ahead and write the closing character... + // If parsing succeeded and we should auto-close, go ahead and write the closing character... if ( out && data !== line[ cursor ] ) { // NOTE: `data !== line[cursor]` accounts for `foo`` being valid syntax (i.e., using untagged template literals as tags); hence, we need to guard against unnecessarily inserting a closing symbol when a user types `foo<|>` and then instinctively types ` in order to close a template literal. - debug( 'Successfully detected an auto-match candidate. Inserting closing symbol...' ); + debug( 'Successfully detected an auto-close candidate. Inserting closing symbol...' ); this._rli.write( ch ); this._rli.write( null, { 'ctrl': true, 'name': 'b' }); debug( 'Resulting expression: %s', this._rli.line ); - debug( 'Finished performing auto-match.' ); + debug( 'Finished performing auto-close.' ); return true; } - debug( 'Failed to detect an auto-match candidate.' ); + debug( 'Failed to detect an auto-close candidate.' ); } debug( 'Checking for a closing symbol...' ); - ch = AUTO_MATCH_CLOSE_SYMBOLS[ data ]; + ch = CLOSE_SYMBOLS[ data ]; if ( isString( ch ) ) { debug( 'Detected a closing symbol.' ); @@ -130,17 +130,17 @@ setNonEnumerableReadOnly( AutoMatcher.prototype, 'onKeypress', function onKeypre 'name': 'right' }); debug( 'Resulting expression: %s', this._rli.line ); - debug( 'Finished performing auto-match.' ); + debug( 'Finished performing auto-close.' ); return true; } debug( 'Did not find a closing symbol. Inserting closing symbol...' ); } debug( 'Failed to detect a closing symbol.' ); - debug( 'Finished performing auto-match.' ); + debug( 'Finished performing auto-close.' ); return false; }); // EXPORTS // -module.exports = AutoMatcher; +module.exports = AutoCloser; diff --git a/lib/node_modules/@stdlib/repl/lib/auto_match_close_symbols.js b/lib/node_modules/@stdlib/repl/lib/auto_close_pairs_close_symbols.js similarity index 88% rename from lib/node_modules/@stdlib/repl/lib/auto_match_close_symbols.js rename to lib/node_modules/@stdlib/repl/lib/auto_close_pairs_close_symbols.js index 7608e9976ce..d8a3c81951e 100644 --- a/lib/node_modules/@stdlib/repl/lib/auto_match_close_symbols.js +++ b/lib/node_modules/@stdlib/repl/lib/auto_close_pairs_close_symbols.js @@ -24,10 +24,10 @@ * Table mapping closing symbols with their opening counterparts. * * @private -* @name AUTO_MATCH_CLOSE_SYMBOLS +* @name CLOSE_SYMBOLS * @type {Object} */ -var AUTO_MATCH_CLOSE_SYMBOLS = { +var CLOSE_SYMBOLS = { '}': '{', ']': '[', ')': '(', @@ -39,4 +39,4 @@ var AUTO_MATCH_CLOSE_SYMBOLS = { // EXPORTS // -module.exports = AUTO_MATCH_CLOSE_SYMBOLS; +module.exports = CLOSE_SYMBOLS; diff --git a/lib/node_modules/@stdlib/repl/lib/auto_match_open_symbols.js b/lib/node_modules/@stdlib/repl/lib/auto_close_pairs_open_symbols.js similarity index 88% rename from lib/node_modules/@stdlib/repl/lib/auto_match_open_symbols.js rename to lib/node_modules/@stdlib/repl/lib/auto_close_pairs_open_symbols.js index 459d70be6bc..96cbd69e22e 100644 --- a/lib/node_modules/@stdlib/repl/lib/auto_match_open_symbols.js +++ b/lib/node_modules/@stdlib/repl/lib/auto_close_pairs_open_symbols.js @@ -24,10 +24,10 @@ * Table mapping opening symbols with their closing counterparts. * * @private -* @name AUTO_MATCH_OPEN_SYMBOLS +* @name OPEN_SYMBOLS * @type {Object} */ -var AUTO_MATCH_OPEN_SYMBOLS = { +var OPEN_SYMBOLS = { '{': '}', '[': ']', '(': ')', @@ -39,4 +39,4 @@ var AUTO_MATCH_OPEN_SYMBOLS = { // EXPORTS // -module.exports = AUTO_MATCH_OPEN_SYMBOLS; +module.exports = OPEN_SYMBOLS; diff --git a/lib/node_modules/@stdlib/repl/lib/auto_match_walk.js b/lib/node_modules/@stdlib/repl/lib/auto_close_pairs_walk.js similarity index 98% rename from lib/node_modules/@stdlib/repl/lib/auto_match_walk.js rename to lib/node_modules/@stdlib/repl/lib/auto_close_pairs_walk.js index 37b88214428..68aee843396 100644 --- a/lib/node_modules/@stdlib/repl/lib/auto_match_walk.js +++ b/lib/node_modules/@stdlib/repl/lib/auto_close_pairs_walk.js @@ -25,7 +25,7 @@ var logger = require( 'debug' ); // VARIABLES // -var debug = logger( 'repl:auto_match:walk' ); +var debug = logger( 'repl:auto_close_pairs:walk' ); // FUNCTIONS // @@ -54,12 +54,12 @@ function findNode( nodes, cursor ) { // MAIN // /** -* Walks an abstract syntax tree (AST) to determine whether to auto-match. +* Walks an abstract syntax tree (AST) to determine whether to auto-close. * * @private * @param {Node} ast - AST to walk * @param {NonNegativeInteger} cursor - cursor position -* @returns {boolean} boolean indicating whether to auto-match +* @returns {boolean} boolean indicating whether to auto-close */ function walk( ast, cursor ) { // eslint-disable-line max-lines-per-function var node; diff --git a/lib/node_modules/@stdlib/repl/lib/defaults.js b/lib/node_modules/@stdlib/repl/lib/defaults.js index f3ff9448b5e..c7088af9cd9 100644 --- a/lib/node_modules/@stdlib/repl/lib/defaults.js +++ b/lib/node_modules/@stdlib/repl/lib/defaults.js @@ -81,7 +81,7 @@ function defaults() { // User settings: 'settings': { // Flag indicating whether to automatically insert matching brackets, parentheses, and quotes: - 'autoMatch': true, + 'autoClosePairs': true, // Flag indicating whether to enable the display of completion previews for auto-completion (note: default depends on whether TTY): 'completionPreviews': void 0 diff --git a/lib/node_modules/@stdlib/repl/lib/main.js b/lib/node_modules/@stdlib/repl/lib/main.js index ab816acd51f..06d8daa4647 100644 --- a/lib/node_modules/@stdlib/repl/lib/main.js +++ b/lib/node_modules/@stdlib/repl/lib/main.js @@ -59,7 +59,7 @@ var inputPrompt = require( './input_prompt.js' ); var processLine = require( './process_line.js' ); var completerFactory = require( './completer.js' ); var PreviewCompleter = require( './completer_preview.js' ); -var AutoMatcher = require( './auto_match.js' ); +var AutoCloser = require( './auto_close_pairs.js' ); var ALIAS_OVERRIDES = require( './alias_overrides.js' ); var SETTINGS = require( './settings.js' ); var SETTINGS_VALIDATORS = require( './settings_validators.js' ); @@ -91,7 +91,7 @@ var debug = logger( 'repl' ); * @param {string} [options.log] - file path specifying where to save REPL commands and printed output * @param {string} [options.quiet=false] - boolean indicating whether log information, confirmation messages, and other possible REPL diagnostics should be silenced * @param {Object} [options.settings] - REPL settings -* @param {boolean} [options.settings.autoMatch=true] - boolean indicating whether to automatically insert matching brackets, parentheses, and quotes +* @param {boolean} [options.settings.autoClosePairs=true] - boolean indicating whether to automatically insert matching brackets, parentheses, and quotes * @param {boolean} [options.settings.completionPreviews] - boolean indicating whether to enable completion previews for auto-completion * @throws {Error} must provide valid options * @returns {REPL} REPL instance @@ -250,8 +250,8 @@ function REPL( options ) { 'completer': this._completer })); - // Create a new auto-matcher: - setNonEnumerableReadOnly( this, '_autoMatcher', new AutoMatcher( this._rli ) ); + // Create a new auto-closer: + setNonEnumerableReadOnly( this, '_autoCloser', new AutoCloser( this._rli ) ); // Initialize a preview completer: setNonEnumerableReadOnly( this, '_previewCompleter', new PreviewCompleter( this._rli, this._completer, this._ostream ) ); @@ -319,8 +319,8 @@ function REPL( options ) { if ( key && key.name === 'tab' ) { return; } - if ( self._settings.autoMatch ) { - status = self._autoMatcher.onKeypress( data, key ); + if ( self._settings.autoClosePairs ) { + status = self._autoCloser.onKeypress( data, key ); } if ( self._settings.completionPreviews ) { if ( status ) { diff --git a/lib/node_modules/@stdlib/repl/lib/settings.js b/lib/node_modules/@stdlib/repl/lib/settings.js index 61e4a1c39c2..5eb5786de56 100644 --- a/lib/node_modules/@stdlib/repl/lib/settings.js +++ b/lib/node_modules/@stdlib/repl/lib/settings.js @@ -28,7 +28,7 @@ * @type {Object} */ var SETTINGS = { - 'autoMatch': { + 'autoClosePairs': { 'desc': 'Automatically insert matching brackets, parentheses, and quotes.', 'type': 'boolean' }, diff --git a/lib/node_modules/@stdlib/repl/lib/validate_settings.js b/lib/node_modules/@stdlib/repl/lib/validate_settings.js index 371c476df74..0efb8646791 100644 --- a/lib/node_modules/@stdlib/repl/lib/validate_settings.js +++ b/lib/node_modules/@stdlib/repl/lib/validate_settings.js @@ -36,13 +36,13 @@ var VALIDATORS = require( './settings_validators.js' ); * @private * @param {Object} opts - destination object * @param {Object} options - settings options -* @param {boolean} [options.autoMatch] - boolean indicating whether to enable auto-match +* @param {boolean} [options.autoClosePairs] - boolean indicating whether to enable auto-close * @param {boolean} [options.completionPreviews] - boolean indicating whether to enable completion previews * @returns {(Error|null)} error or null * * @example * var options = { -* 'autoMatch': true +* 'autoClosePairs': true * }; * var opts = {}; * var err = validate( opts, options ); diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/negative/array_expression_right_bracket.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/negative/array_expression_right_bracket.json similarity index 100% rename from lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/negative/array_expression_right_bracket.json rename to lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/negative/array_expression_right_bracket.json diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/negative/object_expression_right_brace.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/negative/object_expression_right_brace.json similarity index 100% rename from lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/negative/object_expression_right_brace.json rename to lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/negative/object_expression_right_brace.json diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/negative/right_backtick.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/negative/right_backtick.json similarity index 100% rename from lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/negative/right_backtick.json rename to lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/negative/right_backtick.json diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/negative/right_double_quote.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/negative/right_double_quote.json similarity index 100% rename from lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/negative/right_double_quote.json rename to lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/negative/right_double_quote.json diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/negative/right_parenthesis.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/negative/right_parenthesis.json similarity index 100% rename from lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/negative/right_parenthesis.json rename to lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/negative/right_parenthesis.json diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/negative/right_single_quote.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/negative/right_single_quote.json similarity index 100% rename from lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/negative/right_single_quote.json rename to lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/negative/right_single_quote.json diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/negative/template_literal.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/negative/template_literal.json similarity index 100% rename from lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/negative/template_literal.json rename to lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/negative/template_literal.json diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/negative/template_literal_with_expression.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/negative/template_literal_with_expression.json similarity index 100% rename from lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/negative/template_literal_with_expression.json rename to lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/negative/template_literal_with_expression.json diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/arrow_function_body.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/arrow_function_body.json similarity index 100% rename from lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/arrow_function_body.json rename to lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/arrow_function_body.json diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/binary_left_member_expression_literal.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/binary_left_member_expression_literal.json similarity index 100% rename from lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/binary_left_member_expression_literal.json rename to lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/binary_left_member_expression_literal.json diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/call_expression.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/call_expression.json similarity index 100% rename from lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/call_expression.json rename to lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/call_expression.json diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/call_expression_string_argument_single_quote.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/call_expression_string_argument_single_quote.json similarity index 100% rename from lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/call_expression_string_argument_single_quote.json rename to lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/call_expression_string_argument_single_quote.json diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/do_while_body.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/do_while_body.json similarity index 100% rename from lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/do_while_body.json rename to lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/do_while_body.json diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/do_while_test.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/do_while_test.json similarity index 100% rename from lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/do_while_test.json rename to lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/do_while_test.json diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/do_while_test_left_bracket.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/do_while_test_left_bracket.json similarity index 100% rename from lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/do_while_test_left_bracket.json rename to lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/do_while_test_left_bracket.json diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/for_body.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/for_body.json similarity index 100% rename from lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/for_body.json rename to lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/for_body.json diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/for_init.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/for_init.json similarity index 100% rename from lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/for_init.json rename to lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/for_init.json diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/for_test.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/for_test.json similarity index 100% rename from lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/for_test.json rename to lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/for_test.json diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/for_test_member_expression.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/for_test_member_expression.json similarity index 100% rename from lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/for_test_member_expression.json rename to lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/for_test_member_expression.json diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/for_update.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/for_update.json similarity index 100% rename from lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/for_update.json rename to lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/for_update.json diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/for_update_member_expression.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/for_update_member_expression.json similarity index 100% rename from lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/for_update_member_expression.json rename to lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/for_update_member_expression.json diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/function_declaration_body.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/function_declaration_body.json similarity index 100% rename from lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/function_declaration_body.json rename to lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/function_declaration_body.json diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/function_declaration_signature.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/function_declaration_signature.json similarity index 100% rename from lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/function_declaration_signature.json rename to lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/function_declaration_signature.json diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/left_backtick.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/left_backtick.json similarity index 100% rename from lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/left_backtick.json rename to lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/left_backtick.json diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/left_brace.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/left_brace.json similarity index 100% rename from lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/left_brace.json rename to lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/left_brace.json diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/left_bracket.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/left_bracket.json similarity index 100% rename from lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/left_bracket.json rename to lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/left_bracket.json diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/left_double_quote.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/left_double_quote.json similarity index 100% rename from lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/left_double_quote.json rename to lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/left_double_quote.json diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/left_parenthesis.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/left_parenthesis.json similarity index 100% rename from lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/left_parenthesis.json rename to lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/left_parenthesis.json diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/left_single_quote.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/left_single_quote.json similarity index 100% rename from lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/left_single_quote.json rename to lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/left_single_quote.json diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/logical_left_member_expression_literal.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/logical_left_member_expression_literal.json similarity index 100% rename from lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/logical_left_member_expression_literal.json rename to lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/logical_left_member_expression_literal.json diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/logical_with_left_member_expression.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/logical_with_left_member_expression.json similarity index 100% rename from lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/logical_with_left_member_expression.json rename to lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/logical_with_left_member_expression.json diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/logical_with_left_nested_member_expression.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/logical_with_left_nested_member_expression.json similarity index 100% rename from lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/logical_with_left_nested_member_expression.json rename to lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/logical_with_left_nested_member_expression.json diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/logical_with_right_member_expression.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/logical_with_right_member_expression.json similarity index 100% rename from lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/logical_with_right_member_expression.json rename to lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/logical_with_right_member_expression.json diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/member_assignment_expression.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/member_assignment_expression.json similarity index 100% rename from lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/member_assignment_expression.json rename to lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/member_assignment_expression.json diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/member_assignment_expression_literal.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/member_assignment_expression_literal.json similarity index 100% rename from lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/member_assignment_expression_literal.json rename to lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/member_assignment_expression_literal.json diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/member_expression.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/member_expression.json similarity index 100% rename from lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/member_expression.json rename to lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/member_expression.json diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/member_expression_call_expression.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/member_expression_call_expression.json similarity index 100% rename from lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/member_expression_call_expression.json rename to lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/member_expression_call_expression.json diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/regexp_body_single_quote.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/regexp_body_single_quote.json similarity index 100% rename from lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/regexp_body_single_quote.json rename to lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/regexp_body_single_quote.json diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/regexp_single_quote.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/regexp_single_quote.json similarity index 100% rename from lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/regexp_single_quote.json rename to lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/regexp_single_quote.json diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/tagged_template.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/tagged_template.json similarity index 100% rename from lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/tagged_template.json rename to lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/tagged_template.json diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/tagged_template_left_backtick.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/tagged_template_left_backtick.json similarity index 100% rename from lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/tagged_template_left_backtick.json rename to lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/tagged_template_left_backtick.json diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/three_backticks.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/three_backticks.json similarity index 100% rename from lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/three_backticks.json rename to lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/three_backticks.json diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/variable_declaration_string.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/variable_declaration_string.json similarity index 100% rename from lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/variable_declaration_string.json rename to lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/variable_declaration_string.json diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/while_body.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/while_body.json similarity index 100% rename from lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/while_body.json rename to lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/while_body.json diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/while_test.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/while_test.json similarity index 100% rename from lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/positive/while_test.json rename to lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/while_test.json diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/script.js b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/script.js similarity index 100% rename from lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-match/script.js rename to lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/script.js diff --git a/lib/node_modules/@stdlib/repl/test/integration/test.auto_match.js b/lib/node_modules/@stdlib/repl/test/integration/test.auto_close_pairs.js similarity index 94% rename from lib/node_modules/@stdlib/repl/test/integration/test.auto_match.js rename to lib/node_modules/@stdlib/repl/test/integration/test.auto_close_pairs.js index 2f86985c248..df31c8eec45 100644 --- a/lib/node_modules/@stdlib/repl/test/integration/test.auto_match.js +++ b/lib/node_modules/@stdlib/repl/test/integration/test.auto_close_pairs.js @@ -27,7 +27,7 @@ var trim = require( '@stdlib/string/trim' ); var replace = require( '@stdlib/string/replace' ); var readDir = require( '@stdlib/fs/read-dir' ).sync; var format = require( '@stdlib/string/format' ); -var AUTO_MATCH_OPEN_SYMBOLS = require( './../../lib/auto_match_open_symbols.js' ); +var OPEN_SYMBOLS = require( './../../lib/auto_close_pairs_open_symbols.js' ); var repl = require( './fixtures/repl.js' ); @@ -37,10 +37,10 @@ var RE_JSON = /\.json$/; var RE_ANSI = /[\u001B\u009B][[\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\d/#&.:=?%@~_]+)*|[a-zA-Z\d]+(?:;[-a-zA-Z\d/#&.:=?%@~_]*)*)?\u0007)|(?:(?:\d{1,4}(?:;\d{0,4})*)?[\dA-PR-TZcf-nq-uy=><~]))/g; // eslint-disable-line no-control-regex -var POSITIVE_FIXTURES_DIR = resolve( __dirname, 'fixtures', 'auto-match', 'positive' ); +var POSITIVE_FIXTURES_DIR = resolve( __dirname, 'fixtures', 'auto-close-pairs', 'positive' ); var POSITIVE_FIXTURES_FILES = filter( readDir( POSITIVE_FIXTURES_DIR ) ); -var NEGATIVE_FIXTURES_DIR = resolve( __dirname, 'fixtures', 'auto-match', 'negative' ); +var NEGATIVE_FIXTURES_DIR = resolve( __dirname, 'fixtures', 'auto-close-pairs', 'negative' ); var NEGATIVE_FIXTURES_FILES = filter( readDir( NEGATIVE_FIXTURES_DIR ) ); @@ -130,7 +130,7 @@ function processOutput( raw, flg ) { * @returns {string} expected output string */ function spliced2expected( s ) { - return s[ 2 ][ 0 ] + s[ 1 ] + AUTO_MATCH_OPEN_SYMBOLS[ s[1] ] + s[ 2 ][ 1 ]; + return s[ 2 ][ 0 ] + s[ 1 ] + OPEN_SYMBOLS[ s[1] ] + s[ 2 ][ 1 ]; } /** @@ -141,7 +141,7 @@ function spliced2expected( s ) { */ function defaultSettings() { return { - 'autoMatch': false, + 'autoClosePairs': false, 'completionPreviews': false }; } @@ -170,7 +170,7 @@ function moveBack( stream, N ) { * @param {NonNegativeInteger} fixture.cursor - cursor position for inserting a character to trigger an insertion * @param {Function} done - callback to invoke upon completion */ -function assertAutoMatch( t, fixture, done ) { +function assertAutoClose( t, fixture, done ) { var expected; var istream; var opts; @@ -202,8 +202,8 @@ function assertAutoMatch( t, fixture, done ) { N = s[ 0 ].length - fixture.cursor; moveBack( istream, N ); - // Enable auto-match: - r.settings( 'autoMatch', true ); + // Enable auto-close: + r.settings( 'autoClosePairs', true ); // Insert the character in order to trigger auto-close: istream.write( s[ 1 ] ); @@ -236,7 +236,7 @@ function assertAutoMatch( t, fixture, done ) { * @param {NonNegativeInteger} fixture.cursor - cursor position for inserting a character to trigger an insertion * @param {Function} done - callback to invoke upon completion */ -function assertNoAutoMatch( t, fixture, done ) { +function assertNoAutoClose( t, fixture, done ) { var expected; var istream; var opts; @@ -264,8 +264,8 @@ function assertNoAutoMatch( t, fixture, done ) { N = fixture.expression.length - fixture.cursor; moveBack( istream, N ); - // Enable auto-match: - r.settings( 'autoMatch', true ); + // Enable auto-close: + r.settings( 'autoClosePairs', true ); // Insert the character in order to trigger auto-close: istream.write( fixture.expression[ fixture.cursor ] ); @@ -355,6 +355,6 @@ tape( 'main export is a function', function test( t ) { t.end(); }); -test( 'a REPL instance supports automatically closing paired symbols', POSITIVE_FIXTURES_DIR, POSITIVE_FIXTURES_FILES, assertAutoMatch ); +test( 'a REPL instance supports automatically closing paired symbols', POSITIVE_FIXTURES_DIR, POSITIVE_FIXTURES_FILES, assertAutoClose ); -test( 'a REPL instance avoids unnecessarily inserting closing symbols', NEGATIVE_FIXTURES_DIR, NEGATIVE_FIXTURES_FILES, assertNoAutoMatch ); +test( 'a REPL instance avoids unnecessarily inserting closing symbols', NEGATIVE_FIXTURES_DIR, NEGATIVE_FIXTURES_FILES, assertNoAutoClose ); From 5434e3b192586cffdbf042971510bf981cc5e0e2 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sat, 30 Mar 2024 17:28:46 -0700 Subject: [PATCH 64/93] docs: rename setting --- lib/node_modules/@stdlib/repl/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/node_modules/@stdlib/repl/README.md b/lib/node_modules/@stdlib/repl/README.md index 4a0232c82de..478939687db 100644 --- a/lib/node_modules/@stdlib/repl/README.md +++ b/lib/node_modules/@stdlib/repl/README.md @@ -79,7 +79,7 @@ The function accepts the following `options`: The function supports specifying the following settings: -- **autoMatch**: boolean indicating whether to automatically insert matching brackets, parentheses, and quotes. Default: `true`. +- **autoClosePairs**: boolean indicating whether to automatically insert matching brackets, parentheses, and quotes. Default: `true`. - **completionPreviews**: boolean indicating whether to display completion previews for auto-completion. When streams are TTY, the default is `true`; otherwise, the default is `false`. #### REPL.prototype.createContext() @@ -331,7 +331,7 @@ var repl = new REPL({ // ... // Retrieve current setting value: -var v = repl.settings( 'autoMatch' ); +var v = repl.settings( 'autoClosePairs' ); // ... @@ -352,7 +352,7 @@ var repl = new REPL({ // ... // Update setting value: -repl.settings( 'autoMatch', false ); +repl.settings( 'autoClosePairs', false ); // ... From 1ff156fa741a4bb1aeeeb65432614e49664f609c Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sat, 30 Mar 2024 17:34:44 -0700 Subject: [PATCH 65/93] refactor: remove unused property --- lib/node_modules/@stdlib/repl/lib/auto_close_pairs.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/node_modules/@stdlib/repl/lib/auto_close_pairs.js b/lib/node_modules/@stdlib/repl/lib/auto_close_pairs.js index 50c6679bb50..1344f6d3eec 100644 --- a/lib/node_modules/@stdlib/repl/lib/auto_close_pairs.js +++ b/lib/node_modules/@stdlib/repl/lib/auto_close_pairs.js @@ -55,7 +55,6 @@ function AutoCloser( rli ) { } debug( 'Creating an auto-closer...' ); this._rli = rli; - this._active = false; return this; } From 662e1cf708fba10d5cf32ae70e5d8415200e4d63 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sat, 30 Mar 2024 17:43:05 -0700 Subject: [PATCH 66/93] fix: update property name --- lib/node_modules/@stdlib/repl/lib/auto_close_pairs_walk.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/node_modules/@stdlib/repl/lib/auto_close_pairs_walk.js b/lib/node_modules/@stdlib/repl/lib/auto_close_pairs_walk.js index 68aee843396..e28041bf400 100644 --- a/lib/node_modules/@stdlib/repl/lib/auto_close_pairs_walk.js +++ b/lib/node_modules/@stdlib/repl/lib/auto_close_pairs_walk.js @@ -327,7 +327,7 @@ function walk( ast, cursor ) { // eslint-disable-line max-lines-per-function debug( 'Detected the start of a template literal.' ); return true; } - if ( node.expression.length > 0 ) { + if ( node.expressions.length > 0 ) { tmp = findNode( node.expressions, cursor ); if ( tmp ) { node = tmp; From 6d8390dc498e9952bcc4fc9d40dfcd02e96a965d Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sat, 30 Mar 2024 18:28:15 -0700 Subject: [PATCH 67/93] fix: allow auto-closing within template and object expressions --- .../@stdlib/repl/lib/auto_close_pairs_walk.js | 21 +++- ...pression_string_argument_single_quote.json | 22 ++-- ...ssion_template_argument_left_backtick.json | 66 +++++++++++ .../object_expression_left_single_quote.json | 59 ++++++++++ ...te_literal_expression_with_left_brace.json | 105 ++++++++++++++++++ ..._literal_expression_with_left_bracket.json | 101 +++++++++++++++++ ...ral_expression_with_left_double_quote.json | 67 +++++++++++ ...eral_expression_with_left_parenthesis.json | 94 ++++++++++++++++ .../fixtures/auto-close-pairs/script.js | 6 +- 9 files changed, 526 insertions(+), 15 deletions(-) create mode 100644 lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/call_expression_template_argument_left_backtick.json create mode 100644 lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/object_expression_left_single_quote.json create mode 100644 lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/template_literal_expression_with_left_brace.json create mode 100644 lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/template_literal_expression_with_left_bracket.json create mode 100644 lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/template_literal_expression_with_left_double_quote.json create mode 100644 lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/template_literal_expression_with_left_parenthesis.json diff --git a/lib/node_modules/@stdlib/repl/lib/auto_close_pairs_walk.js b/lib/node_modules/@stdlib/repl/lib/auto_close_pairs_walk.js index e28041bf400..8fe1cec7cb3 100644 --- a/lib/node_modules/@stdlib/repl/lib/auto_close_pairs_walk.js +++ b/lib/node_modules/@stdlib/repl/lib/auto_close_pairs_walk.js @@ -80,6 +80,10 @@ function walk( ast, cursor ) { // eslint-disable-line max-lines-per-function } // `['<|>` || `[ 1, '<|>` || `[ ['<|>, 1, 2, 3 ]` || etc node = findNode( node.elements, cursor ); + if ( node === null ) { + // `${foo([<|>)}` + return true; + } break; case 'ArrowFunctionExpression': // `() => [<|>` || `() => { return '<|>` @@ -118,6 +122,10 @@ function walk( ast, cursor ) { // eslint-disable-line max-lines-per-function } // `foo( bar, x['<|>` node = findNode( node.arguments, cursor ); + if ( node === null ) { + // `${foo(<|>}` + return true; + } break; case 'ConditionalExpression': // `( foo ) ? '<|>` @@ -229,6 +237,11 @@ function walk( ast, cursor ) { // eslint-disable-line max-lines-per-function debug( 'Detected the start of a string literal.' ); return true; } + // `foo('<|>)` + if ( node.start === cursor-1 ) { + debug( 'Detected the start of a string literal.' ); + return true; + } // `/'<|>` || `/'<|>/` if ( node.regex ) { debug( 'Detected a regular expression literal.' ); @@ -276,6 +289,9 @@ function walk( ast, cursor ) { // eslint-disable-line max-lines-per-function // `{ 'a': 1, 'b': '<|>` node = findNode( node.properties, cursor ); break; + case 'Property': + // `{'<|>}` + return true; case 'ReturnStatement': // `return '<|>` node = node.argument; @@ -334,7 +350,10 @@ function walk( ast, cursor ) { // eslint-disable-line max-lines-per-function break; } } - node = findNode( node.quasis, cursor ); + node = findNode( node.quasis, cursor-1 ); + if ( node === null ) { + return true; + } break; case 'ThrowStatement': // `throw new errs[ '<|>` || `throw new Error( '` diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/call_expression_string_argument_single_quote.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/call_expression_string_argument_single_quote.json index 243e6020206..9f04820cbae 100644 --- a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/call_expression_string_argument_single_quote.json +++ b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/call_expression_string_argument_single_quote.json @@ -1,32 +1,32 @@ { - "expression": "noop( '", - "cursor": 6, + "expression": "foo(')", + "cursor": 4, "ast": { "type": "Program", "start": 0, - "end": 7, + "end": 6, "body": [ { "type": "ExpressionStatement", "start": 0, - "end": 7, + "end": 6, "expression": { "type": "CallExpression", "start": 0, - "end": 7, + "end": 6, "callee": { "type": "Identifier", "start": 0, - "end": 4, - "name": "noop" + "end": 3, + "name": "foo" }, "arguments": [ { "type": "Literal", - "start": 6, - "end": 7, - "value": "", - "raw": "'" + "start": 4, + "end": 6, + "value": ")", + "raw": "')" } ], "optional": false diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/call_expression_template_argument_left_backtick.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/call_expression_template_argument_left_backtick.json new file mode 100644 index 00000000000..97b46e5f2a6 --- /dev/null +++ b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/call_expression_template_argument_left_backtick.json @@ -0,0 +1,66 @@ +{ + "expression": "foo(`)", + "cursor": 4, + "ast": { + "type": "Program", + "start": 0, + "end": 6, + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 6, + "expression": { + "type": "CallExpression", + "start": 0, + "end": 6, + "callee": { + "type": "Identifier", + "start": 0, + "end": 3, + "name": "foo" + }, + "arguments": [ + { + "type": "TemplateLiteral", + "start": 4, + "end": 6, + "expressions": [ + { + "type": "Identifier", + "start": 6, + "end": 6, + "name": "✖" + } + ], + "quasis": [ + { + "type": "TemplateElement", + "start": 5, + "end": 6, + "value": { + "raw": ")", + "cooked": ")" + }, + "tail": false + }, + { + "type": "TemplateElement", + "start": 6, + "end": 6, + "value": { + "cooked": "", + "raw": "" + }, + "tail": true + } + ] + } + ], + "optional": false + } + } + ], + "sourceType": "script" + } +} diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/object_expression_left_single_quote.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/object_expression_left_single_quote.json new file mode 100644 index 00000000000..5ee0164eb41 --- /dev/null +++ b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/object_expression_left_single_quote.json @@ -0,0 +1,59 @@ +{ + "expression": "x = {'}", + "cursor": 5, + "ast": { + "type": "Program", + "start": 0, + "end": 7, + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 7, + "expression": { + "type": "AssignmentExpression", + "start": 0, + "end": 7, + "operator": "=", + "left": { + "type": "Identifier", + "start": 0, + "end": 1, + "name": "x" + }, + "right": { + "type": "ObjectExpression", + "start": 4, + "end": 7, + "properties": [ + { + "type": "Property", + "start": 5, + "end": 7, + "method": false, + "shorthand": true, + "computed": false, + "key": { + "type": "Literal", + "start": 5, + "end": 7, + "value": "}", + "raw": "'}" + }, + "kind": "init", + "value": { + "type": "Literal", + "start": 5, + "end": 7, + "value": "}", + "raw": "'}" + } + } + ] + } + } + } + ], + "sourceType": "script" + } +} diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/template_literal_expression_with_left_brace.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/template_literal_expression_with_left_brace.json new file mode 100644 index 00000000000..eeb39b7ded8 --- /dev/null +++ b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/template_literal_expression_with_left_brace.json @@ -0,0 +1,105 @@ +{ + "expression": "`${foo({)}`", + "cursor": 7, + "ast": { + "type": "Program", + "start": 0, + "end": 11, + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 11, + "expression": { + "type": "TemplateLiteral", + "start": 0, + "end": 11, + "expressions": [ + { + "type": "CallExpression", + "start": 3, + "end": 11, + "callee": { + "type": "Identifier", + "start": 3, + "end": 6, + "name": "foo" + }, + "arguments": [ + { + "type": "TaggedTemplateExpression", + "start": 7, + "end": 11, + "tag": { + "type": "ObjectExpression", + "start": 7, + "end": 10, + "properties": [] + }, + "quasi": { + "type": "TemplateLiteral", + "start": 10, + "end": 11, + "expressions": [ + { + "type": "Identifier", + "start": 11, + "end": 11, + "name": "✖" + } + ], + "quasis": [ + { + "type": "TemplateElement", + "start": 11, + "end": 11, + "value": { + "raw": "" + }, + "tail": false + }, + { + "type": "TemplateElement", + "start": 11, + "end": 11, + "value": { + "cooked": "", + "raw": "" + }, + "tail": true + } + ] + } + } + ], + "optional": false + } + ], + "quasis": [ + { + "type": "TemplateElement", + "start": 1, + "end": 1, + "value": { + "raw": "", + "cooked": "" + }, + "tail": false + }, + { + "type": "TemplateElement", + "start": 11, + "end": 11, + "value": { + "cooked": "", + "raw": "" + }, + "tail": true + } + ] + } + } + ], + "sourceType": "script" + } +} diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/template_literal_expression_with_left_bracket.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/template_literal_expression_with_left_bracket.json new file mode 100644 index 00000000000..cd630a99ac6 --- /dev/null +++ b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/template_literal_expression_with_left_bracket.json @@ -0,0 +1,101 @@ +{ + "expression": "`${foo([)}`", + "cursor": 7, + "ast": { + "type": "Program", + "start": 0, + "end": 11, + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 11, + "expression": { + "type": "TemplateLiteral", + "start": 0, + "end": 11, + "expressions": [ + { + "type": "CallExpression", + "start": 3, + "end": 11, + "callee": { + "type": "Identifier", + "start": 3, + "end": 6, + "name": "foo" + }, + "arguments": [ + { + "type": "ArrayExpression", + "start": 7, + "end": 11, + "elements": [ + { + "type": "TemplateLiteral", + "start": 10, + "end": 11, + "expressions": [ + { + "type": "Identifier", + "start": 11, + "end": 11, + "name": "✖" + } + ], + "quasis": [ + { + "type": "TemplateElement", + "start": 11, + "end": 11, + "value": { + "raw": "" + }, + "tail": false + }, + { + "type": "TemplateElement", + "start": 11, + "end": 11, + "value": { + "cooked": "", + "raw": "" + }, + "tail": true + } + ] + } + ] + } + ], + "optional": false + } + ], + "quasis": [ + { + "type": "TemplateElement", + "start": 1, + "end": 1, + "value": { + "raw": "", + "cooked": "" + }, + "tail": false + }, + { + "type": "TemplateElement", + "start": 11, + "end": 11, + "value": { + "cooked": "", + "raw": "" + }, + "tail": true + } + ] + } + } + ], + "sourceType": "script" + } +} diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/template_literal_expression_with_left_double_quote.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/template_literal_expression_with_left_double_quote.json new file mode 100644 index 00000000000..6effaaac5ae --- /dev/null +++ b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/template_literal_expression_with_left_double_quote.json @@ -0,0 +1,67 @@ +{ + "expression": "`${foo(\")}`", + "cursor": 7, + "ast": { + "type": "Program", + "start": 0, + "end": 11, + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 11, + "expression": { + "type": "TemplateLiteral", + "start": 0, + "end": 11, + "expressions": [ + { + "type": "CallExpression", + "start": 3, + "end": 11, + "callee": { + "type": "Identifier", + "start": 3, + "end": 6, + "name": "foo" + }, + "arguments": [ + { + "type": "Literal", + "start": 7, + "end": 11, + "value": ")}`", + "raw": "\")}`" + } + ], + "optional": false + } + ], + "quasis": [ + { + "type": "TemplateElement", + "start": 1, + "end": 1, + "value": { + "raw": "", + "cooked": "" + }, + "tail": false + }, + { + "type": "TemplateElement", + "start": 11, + "end": 11, + "value": { + "cooked": "", + "raw": "" + }, + "tail": true + } + ] + } + } + ], + "sourceType": "script" + } +} diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/template_literal_expression_with_left_parenthesis.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/template_literal_expression_with_left_parenthesis.json new file mode 100644 index 00000000000..00230e25a7e --- /dev/null +++ b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/template_literal_expression_with_left_parenthesis.json @@ -0,0 +1,94 @@ +{ + "expression": "`${foo(}`", + "cursor": 6, + "ast": { + "type": "Program", + "start": 0, + "end": 9, + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 9, + "expression": { + "type": "TemplateLiteral", + "start": 0, + "end": 9, + "expressions": [ + { + "type": "CallExpression", + "start": 3, + "end": 9, + "callee": { + "type": "Identifier", + "start": 3, + "end": 6, + "name": "foo" + }, + "arguments": [ + { + "type": "TemplateLiteral", + "start": 8, + "end": 9, + "expressions": [ + { + "type": "Identifier", + "start": 9, + "end": 9, + "name": "✖" + } + ], + "quasis": [ + { + "type": "TemplateElement", + "start": 9, + "end": 9, + "value": { + "raw": "" + }, + "tail": false + }, + { + "type": "TemplateElement", + "start": 9, + "end": 9, + "value": { + "cooked": "", + "raw": "" + }, + "tail": true + } + ] + } + ], + "optional": false + } + ], + "quasis": [ + { + "type": "TemplateElement", + "start": 1, + "end": 1, + "value": { + "raw": "", + "cooked": "" + }, + "tail": false + }, + { + "type": "TemplateElement", + "start": 9, + "end": 9, + "value": { + "cooked": "", + "raw": "" + }, + "tail": true + } + ] + } + } + ], + "sourceType": "script" + } +} diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/script.js b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/script.js index 00280e56cb7..e70d948f7c6 100644 --- a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/script.js +++ b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/script.js @@ -49,15 +49,15 @@ function main() { var ast; var out; - str = '``'; + str = 'x = {\'}'; ast = parse( str, AOPTS ); out = { 'expression': str, - 'cursor': 0, + 'cursor': str.length-2, 'ast': ast }; - writeFile( resolve( __dirname, 'negative', 'template_literal_empty.json' ), JSON.stringify( out, null, ' ' )+'\n', FOPTS ); + writeFile( resolve( __dirname, 'positive', 'object_expression_left_single_quote.json' ), JSON.stringify( out, null, ' ' )+'\n', FOPTS ); } main(); From 8e09e8e44eb56099d4a6d75f3185b9ac14ff013e Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sat, 30 Mar 2024 21:01:00 -0700 Subject: [PATCH 68/93] test: add RegExp test --- .../positive/regexp_literal_left_bracket.json | 36 +++++++++++++++++++ .../fixtures/auto-close-pairs/script.js | 6 ++-- 2 files changed, 39 insertions(+), 3 deletions(-) create mode 100644 lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/regexp_literal_left_bracket.json diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/regexp_literal_left_bracket.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/regexp_literal_left_bracket.json new file mode 100644 index 00000000000..7a9258a530e --- /dev/null +++ b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/positive/regexp_literal_left_bracket.json @@ -0,0 +1,36 @@ +{ + "expression": "x = /[/;", + "cursor": 5, + "ast": { + "type": "Program", + "start": 0, + "end": 8, + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 8, + "expression": { + "type": "AssignmentExpression", + "start": 0, + "end": 8, + "operator": "=", + "left": { + "type": "Identifier", + "start": 0, + "end": 1, + "name": "x" + }, + "right": { + "type": "Literal", + "start": 5, + "end": 8, + "regex": {}, + "raw": "[/;" + } + } + } + ], + "sourceType": "script" + } +} diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/script.js b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/script.js index e70d948f7c6..461d30d7c66 100644 --- a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/script.js +++ b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-close-pairs/script.js @@ -49,15 +49,15 @@ function main() { var ast; var out; - str = 'x = {\'}'; + str = 'x = /[/;'; ast = parse( str, AOPTS ); out = { 'expression': str, - 'cursor': str.length-2, + 'cursor': str.length-3, 'ast': ast }; - writeFile( resolve( __dirname, 'positive', 'object_expression_left_single_quote.json' ), JSON.stringify( out, null, ' ' )+'\n', FOPTS ); + writeFile( resolve( __dirname, 'positive', 'regexp_literal_left_bracket.json' ), JSON.stringify( out, null, ' ' )+'\n', FOPTS ); } main(); From 8f9dce8321d574c9deb09ef31eaef17d997d54c6 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sat, 30 Mar 2024 21:50:16 -0700 Subject: [PATCH 69/93] fix: address completer bug when completing after special characters --- lib/node_modules/@stdlib/repl/lib/completer.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/node_modules/@stdlib/repl/lib/completer.js b/lib/node_modules/@stdlib/repl/lib/completer.js index 37bbcfae860..6d71ad4a723 100644 --- a/lib/node_modules/@stdlib/repl/lib/completer.js +++ b/lib/node_modules/@stdlib/repl/lib/completer.js @@ -41,6 +41,7 @@ var completeExpression = require( './complete_expression.js' ); // VARIABLES // var debug = logger( 'repl:completer' ); +var RE_SPECIAL_CHARS = /[`~!@#$%^&*()-=+[\]{}\\/|;:'",<>?. ]$/; // FUNCTIONS // @@ -179,6 +180,12 @@ function completer( repl ) { debug( 'Results: %s', res.join( ', ' ) ); return clbk( null, [ res, line ] ); } + // Sanity check that we are attempting to complete something which is completable: + if ( RE_SPECIAL_CHARS.test( line.substring( 0, repl._rli.cursor ) ) ) { + debug( 'Detected attempt to trigger completion after a special character.' ); + debug( 'Results: %s', res.join( ', ' ) ); + return clbk( null, [ res, line ] ); + } debug( 'Attempting to complete an incomplete expression.' ); line = completeExpression( res, repl._context, line ); res = normalize( res ); From 0bb6ae946bcfa716528792918bb8963f5db86ba9 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sat, 30 Mar 2024 23:50:52 -0700 Subject: [PATCH 70/93] refactor: add support for auto-deleting character pairs --- lib/node_modules/@stdlib/repl/README.md | 21 +++ .../@stdlib/repl/lib/auto_close_pairs.js | 2 +- .../@stdlib/repl/lib/auto_delete_pairs.js | 133 ++++++++++++++++++ lib/node_modules/@stdlib/repl/lib/defaults.js | 3 + lib/node_modules/@stdlib/repl/lib/main.js | 26 +++- lib/node_modules/@stdlib/repl/lib/settings.js | 4 + .../@stdlib/repl/lib/validate_settings.js | 2 - 7 files changed, 182 insertions(+), 9 deletions(-) create mode 100644 lib/node_modules/@stdlib/repl/lib/auto_delete_pairs.js diff --git a/lib/node_modules/@stdlib/repl/README.md b/lib/node_modules/@stdlib/repl/README.md index 478939687db..bcf5a1239b4 100644 --- a/lib/node_modules/@stdlib/repl/README.md +++ b/lib/node_modules/@stdlib/repl/README.md @@ -80,6 +80,7 @@ The function accepts the following `options`: The function supports specifying the following settings: - **autoClosePairs**: boolean indicating whether to automatically insert matching brackets, parentheses, and quotes. Default: `true`. +- **autoDeletePairs**: boolean indicating whether to automatically delete adjacent matching brackets, parentheses, and quotes. Default: `true`. - **completionPreviews**: boolean indicating whether to display completion previews for auto-completion. When streams are TTY, the default is `true`; otherwise, the default is `false`. #### REPL.prototype.createContext() @@ -1037,6 +1038,26 @@ Stops saving commands to a file path associated with a specified record identifi // TODO ``` +#### settings( \[name\[, value]] ) + +Gets (and sets) REPL settings. + +```text +In [1]: settings() +``` + +To retrieve the current value for a specific setting, provide a `name` argument. + +```text +In [1]: settings( 'autoClosePairs' ) +``` + +To update a specific setting, provide a `value` argument. + +```text +In [1]: settings( 'autoClosePairs', false ) +``` + #### tutorial( \[name, \[options]] ) Starts a tutorial. diff --git a/lib/node_modules/@stdlib/repl/lib/auto_close_pairs.js b/lib/node_modules/@stdlib/repl/lib/auto_close_pairs.js index 1344f6d3eec..08272da2a59 100644 --- a/lib/node_modules/@stdlib/repl/lib/auto_close_pairs.js +++ b/lib/node_modules/@stdlib/repl/lib/auto_close_pairs.js @@ -51,7 +51,7 @@ var AOPTS = { */ function AutoCloser( rli ) { if ( !(this instanceof AutoCloser) ) { - return new AutoCloser(); + return new AutoCloser( rli ); } debug( 'Creating an auto-closer...' ); this._rli = rli; diff --git a/lib/node_modules/@stdlib/repl/lib/auto_delete_pairs.js b/lib/node_modules/@stdlib/repl/lib/auto_delete_pairs.js new file mode 100644 index 00000000000..0fe7b9de651 --- /dev/null +++ b/lib/node_modules/@stdlib/repl/lib/auto_delete_pairs.js @@ -0,0 +1,133 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2024 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +/* eslint-disable no-restricted-syntax, no-invalid-this */ + +'use strict'; + +// MODULES // + +var logger = require( 'debug' ); +var parse = require( 'acorn-loose' ).parse; +var findNodeAround = require( 'acorn-walk' ).findNodeAround; +var setNonEnumerableReadOnly = require( '@stdlib/utils/define-nonenumerable-read-only-property' ); +var isString = require( '@stdlib/assert/is-string' ).isPrimitive; +var OPEN_SYMBOLS = require( './auto_close_pairs_open_symbols.js' ); +var CLOSE_SYMBOLS = require( './auto_close_pairs_close_symbols.js' ); + + +// VARIABLES // + +var debug = logger( 'repl:auto_delete_pairs' ); +var AOPTS = { + 'ecmaVersion': 'latest' +}; + + +// MAIN // + +/** +* Constructor for creating an auto-deleter. +* +* @private +* @constructor +* @param {Object} rli - readline instance +* @returns {AutoDeleter} auto-deleter instance +*/ +function AutoDeleter( rli ) { + if ( !(this instanceof AutoDeleter) ) { + return new AutoDeleter( rli ); + } + debug( 'Creating an auto-deleter...' ); + this._rli = rli; + return this; +} + +/** +* Callback which should be invoked **before** a "keypress" event is processed by a readline interface. +* +* @name beforeKeypress +* @memberof AutoDeleter.prototype +* @param {string} data - input data +* @param {Object} key - key object +* @returns {boolean} boolean indicating whether auto-delete was successful +*/ +setNonEnumerableReadOnly( AutoDeleter.prototype, 'beforeKeypress', function beforeKeypress() { + var cursor; + var line; + var data; + var node; + var ast; + var ch; + + cursor = this._rli.cursor; + line = this._rli.line; + + debug( 'Expression: %s', line ); + debug( 'Cursor position: %d', cursor ); + + debug( 'Performing auto-delete...' ); + + data = line[ cursor-1 ]; + debug( 'Character to delete: %s', data ); + + debug( 'Checking if an opening symbol...' ); + ch = OPEN_SYMBOLS[ data ]; + if ( isString( ch ) ) { + debug( 'Detected an opening symbol.' ); + + debug( 'Checking if immediately followed by a closing symbol...' ); + ch = CLOSE_SYMBOLS[ line[ cursor ] ]; + if ( !isString( ch ) ) { + debug( 'Opening symbol is not followed by a closing symbol. Skipping...' ); + debug( 'Finished performing auto-delete.' ); + return false; + } + debug( 'Detected a closing symbol.' ); + + debug( 'Generating an AST...' ); + ast = parse( line, AOPTS ); + + debug( 'Checking whether characters are within a string literal...' ); + node = findNodeAround( ast, cursor-1, 'Literal' ); + if ( node && node.node.start < cursor-1 ) { + debug( 'Characters are within a string literal. Skipping...' ); + debug( 'Finished performing auto-delete.' ); + return false; + } + debug( 'Characters are not within a string literal.' ); + debug( 'Found an auto-delete candidate. Deleting symbols...' ); + this._rli.write( null, { + 'name': 'right' + }); + this._rli.write( null, { + 'name': 'backspace' + }); + debug( 'Resulting expression: %s', this._rli.line ); + debug( 'Finished performing auto-delete.' ); + return true; + } + debug( 'Failed to detect an opening symbol.' ); + debug( 'Finished performing auto-delete.' ); + return false; +}); + + +// EXPORTS // + +module.exports = AutoDeleter; diff --git a/lib/node_modules/@stdlib/repl/lib/defaults.js b/lib/node_modules/@stdlib/repl/lib/defaults.js index c7088af9cd9..a9ddd5c657a 100644 --- a/lib/node_modules/@stdlib/repl/lib/defaults.js +++ b/lib/node_modules/@stdlib/repl/lib/defaults.js @@ -83,6 +83,9 @@ function defaults() { // Flag indicating whether to automatically insert matching brackets, parentheses, and quotes: 'autoClosePairs': true, + // Flag indicating whether to automatically delete adjacent matching brackets, parentheses, and quotes: + 'autoDeletePairs': true, + // Flag indicating whether to enable the display of completion previews for auto-completion (note: default depends on whether TTY): 'completionPreviews': void 0 } diff --git a/lib/node_modules/@stdlib/repl/lib/main.js b/lib/node_modules/@stdlib/repl/lib/main.js index 06d8daa4647..82b72597615 100644 --- a/lib/node_modules/@stdlib/repl/lib/main.js +++ b/lib/node_modules/@stdlib/repl/lib/main.js @@ -60,6 +60,7 @@ var processLine = require( './process_line.js' ); var completerFactory = require( './completer.js' ); var PreviewCompleter = require( './completer_preview.js' ); var AutoCloser = require( './auto_close_pairs.js' ); +var AutoDeleter = require( './auto_delete_pairs.js' ); var ALIAS_OVERRIDES = require( './alias_overrides.js' ); var SETTINGS = require( './settings.js' ); var SETTINGS_VALIDATORS = require( './settings_validators.js' ); @@ -92,6 +93,7 @@ var debug = logger( 'repl' ); * @param {string} [options.quiet=false] - boolean indicating whether log information, confirmation messages, and other possible REPL diagnostics should be silenced * @param {Object} [options.settings] - REPL settings * @param {boolean} [options.settings.autoClosePairs=true] - boolean indicating whether to automatically insert matching brackets, parentheses, and quotes +* @param {boolean} [options.settings.autoDeletePairs=true] - boolean indicating whether to automatically delete adjacent matching brackets, parentheses, and quotes * @param {boolean} [options.settings.completionPreviews] - boolean indicating whether to enable completion previews for auto-completion * @throws {Error} must provide valid options * @returns {REPL} REPL instance @@ -253,6 +255,9 @@ function REPL( options ) { // Create a new auto-closer: setNonEnumerableReadOnly( this, '_autoCloser', new AutoCloser( this._rli ) ); + // Create a new auto-deleter: + setNonEnumerableReadOnly( this, '_autoDeleter', new AutoDeleter( this._rli ) ); + // Initialize a preview completer: setNonEnumerableReadOnly( this, '_previewCompleter', new PreviewCompleter( this._rli, this._completer, this._ostream ) ); @@ -300,7 +305,11 @@ function REPL( options ) { * @param {Object} key - key object */ function beforeKeypress( data, key ) { - if ( self._settings.completionPreviews ) { + var settings = self._settings; + if ( key && key.name === 'backspace' && settings.autoDeletePairs ) { + self._autoDeleter.beforeKeypress( data, key ); + } + if ( settings.completionPreviews ) { self._previewCompleter.beforeKeypress( data, key ); } self._ttyWrite.call( self._rli, data, key ); @@ -315,15 +324,20 @@ function REPL( options ) { * @returns {void} */ function onKeypress( data, key ) { - var status; + var autoClosed; + var settings; + if ( key && key.name === 'tab' ) { return; } - if ( self._settings.autoClosePairs ) { - status = self._autoCloser.onKeypress( data, key ); + settings = self._settings; + + if ( settings.autoClosePairs ) { + autoClosed = self._autoCloser.onKeypress( data, key ); } - if ( self._settings.completionPreviews ) { - if ( status ) { + if ( settings.completionPreviews ) { + // If auto-closing was performed, explicitly remove any currently displayed completion preview... + if ( autoClosed ) { self._previewCompleter.clear(); } else { self._previewCompleter.onKeypress( data, key ); diff --git a/lib/node_modules/@stdlib/repl/lib/settings.js b/lib/node_modules/@stdlib/repl/lib/settings.js index 5eb5786de56..caa2e40de20 100644 --- a/lib/node_modules/@stdlib/repl/lib/settings.js +++ b/lib/node_modules/@stdlib/repl/lib/settings.js @@ -32,6 +32,10 @@ var SETTINGS = { 'desc': 'Automatically insert matching brackets, parentheses, and quotes.', 'type': 'boolean' }, + 'autoDeletePairs': { + 'desc': 'Automatically delete adjacent matching brackets, parentheses, and quotes.', + 'type': 'boolean' + }, 'completionPreviews': { 'desc': 'Enable the display of completion previews for auto-completion.', 'type': 'boolean' diff --git a/lib/node_modules/@stdlib/repl/lib/validate_settings.js b/lib/node_modules/@stdlib/repl/lib/validate_settings.js index 0efb8646791..923f860f602 100644 --- a/lib/node_modules/@stdlib/repl/lib/validate_settings.js +++ b/lib/node_modules/@stdlib/repl/lib/validate_settings.js @@ -36,8 +36,6 @@ var VALIDATORS = require( './settings_validators.js' ); * @private * @param {Object} opts - destination object * @param {Object} options - settings options -* @param {boolean} [options.autoClosePairs] - boolean indicating whether to enable auto-close -* @param {boolean} [options.completionPreviews] - boolean indicating whether to enable completion previews * @returns {(Error|null)} error or null * * @example From c6d997d0a60739e61c095867a54b849d601629de Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sun, 31 Mar 2024 00:16:19 -0700 Subject: [PATCH 71/93] refactor: move deletion logic to auto-closer due to shared state --- .../@stdlib/repl/lib/auto_close_pairs.js | 80 +++++++++++ .../@stdlib/repl/lib/auto_delete_pairs.js | 133 ------------------ lib/node_modules/@stdlib/repl/lib/main.js | 6 +- 3 files changed, 81 insertions(+), 138 deletions(-) delete mode 100644 lib/node_modules/@stdlib/repl/lib/auto_delete_pairs.js diff --git a/lib/node_modules/@stdlib/repl/lib/auto_close_pairs.js b/lib/node_modules/@stdlib/repl/lib/auto_close_pairs.js index 08272da2a59..b826977ca98 100644 --- a/lib/node_modules/@stdlib/repl/lib/auto_close_pairs.js +++ b/lib/node_modules/@stdlib/repl/lib/auto_close_pairs.js @@ -24,6 +24,7 @@ var logger = require( 'debug' ); var parse = require( 'acorn-loose' ).parse; +var findNodeAround = require( 'acorn-walk' ).findNodeAround; var setNonEnumerableReadOnly = require( '@stdlib/utils/define-nonenumerable-read-only-property' ); var isString = require( '@stdlib/assert/is-string' ).isPrimitive; var walk = require( './auto_close_pairs_walk.js' ); @@ -55,9 +56,83 @@ function AutoCloser( rli ) { } debug( 'Creating an auto-closer...' ); this._rli = rli; + this._ignoreBackspace = false; return this; } +/** +* Callback which should be invoked **before** a "keypress" event is processed by a readline interface. +* +* @name beforeKeypress +* @memberof AutoCloser.prototype +* @param {string} data - input data +* @param {Object} key - key object +* @returns {boolean} boolean indicating whether auto-delete was successful +*/ +setNonEnumerableReadOnly( AutoCloser.prototype, 'beforeKeypress', function beforeKeypress() { + var cursor; + var line; + var data; + var node; + var ast; + var ch; + + if ( this._ignoreBackspace ) { + this._ignoreBackspace = false; + return false; + } + cursor = this._rli.cursor; + line = this._rli.line; + + debug( 'Expression: %s', line ); + debug( 'Cursor position: %d', cursor ); + + debug( 'Performing auto-delete...' ); + + data = line[ cursor-1 ]; + debug( 'Character to delete: %s', data ); + + debug( 'Checking if an opening symbol...' ); + ch = OPEN_SYMBOLS[ data ]; + if ( isString( ch ) ) { + debug( 'Detected an opening symbol.' ); + + debug( 'Checking if immediately followed by a closing symbol...' ); + ch = CLOSE_SYMBOLS[ line[ cursor ] ]; + if ( !isString( ch ) ) { + debug( 'Opening symbol is not followed by a closing symbol. Skipping...' ); + debug( 'Finished performing auto-delete.' ); + return false; + } + debug( 'Detected a closing symbol.' ); + + debug( 'Generating an AST...' ); + ast = parse( line, AOPTS ); + + debug( 'Checking whether characters are within a string literal...' ); + node = findNodeAround( ast, cursor-1, 'Literal' ); + if ( node && node.node.start < cursor-1 ) { + debug( 'Characters are within a string literal. Skipping...' ); + debug( 'Finished performing auto-delete.' ); + return false; + } + debug( 'Characters are not within a string literal.' ); + debug( 'Found an auto-delete candidate. Deleting symbols...' ); + this._rli.write( null, { + 'name': 'right' + }); + this._rli.write( null, { + 'name': 'backspace' + }); + debug( 'Resulting expression: %s', this._rli.line ); + debug( 'Finished performing auto-delete.' ); + return true; + } + debug( 'Failed to detect an opening symbol.' ); + debug( 'Finished performing auto-delete.' ); + return false; +}); + /** * Callback for handling a "keypress" event. * @@ -103,6 +178,8 @@ setNonEnumerableReadOnly( AutoCloser.prototype, 'onKeypress', function onKeypres if ( out && data !== line[ cursor ] ) { // NOTE: `data !== line[cursor]` accounts for `foo`` being valid syntax (i.e., using untagged template literals as tags); hence, we need to guard against unnecessarily inserting a closing symbol when a user types `foo<|>` and then instinctively types ` in order to close a template literal. debug( 'Successfully detected an auto-close candidate. Inserting closing symbol...' ); this._rli.write( ch ); + + // Move back one character: this._rli.write( null, { 'ctrl': true, 'name': 'b' @@ -122,9 +199,12 @@ setNonEnumerableReadOnly( AutoCloser.prototype, 'onKeypress', function onKeypres debug( 'Determining whether a closing symbol already exists...' ); if ( data === line[ cursor ] ) { debug( 'Closing symbol already exists. Skipping over existing symbol...' ); + this._ignoreBackspace = true; this._rli.write( null, { 'name': 'backspace' }); + + // Move to the right one character: this._rli.write( null, { 'name': 'right' }); diff --git a/lib/node_modules/@stdlib/repl/lib/auto_delete_pairs.js b/lib/node_modules/@stdlib/repl/lib/auto_delete_pairs.js deleted file mode 100644 index 0fe7b9de651..00000000000 --- a/lib/node_modules/@stdlib/repl/lib/auto_delete_pairs.js +++ /dev/null @@ -1,133 +0,0 @@ -/** -* @license Apache-2.0 -* -* Copyright (c) 2024 The Stdlib Authors. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -/* eslint-disable no-restricted-syntax, no-invalid-this */ - -'use strict'; - -// MODULES // - -var logger = require( 'debug' ); -var parse = require( 'acorn-loose' ).parse; -var findNodeAround = require( 'acorn-walk' ).findNodeAround; -var setNonEnumerableReadOnly = require( '@stdlib/utils/define-nonenumerable-read-only-property' ); -var isString = require( '@stdlib/assert/is-string' ).isPrimitive; -var OPEN_SYMBOLS = require( './auto_close_pairs_open_symbols.js' ); -var CLOSE_SYMBOLS = require( './auto_close_pairs_close_symbols.js' ); - - -// VARIABLES // - -var debug = logger( 'repl:auto_delete_pairs' ); -var AOPTS = { - 'ecmaVersion': 'latest' -}; - - -// MAIN // - -/** -* Constructor for creating an auto-deleter. -* -* @private -* @constructor -* @param {Object} rli - readline instance -* @returns {AutoDeleter} auto-deleter instance -*/ -function AutoDeleter( rli ) { - if ( !(this instanceof AutoDeleter) ) { - return new AutoDeleter( rli ); - } - debug( 'Creating an auto-deleter...' ); - this._rli = rli; - return this; -} - -/** -* Callback which should be invoked **before** a "keypress" event is processed by a readline interface. -* -* @name beforeKeypress -* @memberof AutoDeleter.prototype -* @param {string} data - input data -* @param {Object} key - key object -* @returns {boolean} boolean indicating whether auto-delete was successful -*/ -setNonEnumerableReadOnly( AutoDeleter.prototype, 'beforeKeypress', function beforeKeypress() { - var cursor; - var line; - var data; - var node; - var ast; - var ch; - - cursor = this._rli.cursor; - line = this._rli.line; - - debug( 'Expression: %s', line ); - debug( 'Cursor position: %d', cursor ); - - debug( 'Performing auto-delete...' ); - - data = line[ cursor-1 ]; - debug( 'Character to delete: %s', data ); - - debug( 'Checking if an opening symbol...' ); - ch = OPEN_SYMBOLS[ data ]; - if ( isString( ch ) ) { - debug( 'Detected an opening symbol.' ); - - debug( 'Checking if immediately followed by a closing symbol...' ); - ch = CLOSE_SYMBOLS[ line[ cursor ] ]; - if ( !isString( ch ) ) { - debug( 'Opening symbol is not followed by a closing symbol. Skipping...' ); - debug( 'Finished performing auto-delete.' ); - return false; - } - debug( 'Detected a closing symbol.' ); - - debug( 'Generating an AST...' ); - ast = parse( line, AOPTS ); - - debug( 'Checking whether characters are within a string literal...' ); - node = findNodeAround( ast, cursor-1, 'Literal' ); - if ( node && node.node.start < cursor-1 ) { - debug( 'Characters are within a string literal. Skipping...' ); - debug( 'Finished performing auto-delete.' ); - return false; - } - debug( 'Characters are not within a string literal.' ); - debug( 'Found an auto-delete candidate. Deleting symbols...' ); - this._rli.write( null, { - 'name': 'right' - }); - this._rli.write( null, { - 'name': 'backspace' - }); - debug( 'Resulting expression: %s', this._rli.line ); - debug( 'Finished performing auto-delete.' ); - return true; - } - debug( 'Failed to detect an opening symbol.' ); - debug( 'Finished performing auto-delete.' ); - return false; -}); - - -// EXPORTS // - -module.exports = AutoDeleter; diff --git a/lib/node_modules/@stdlib/repl/lib/main.js b/lib/node_modules/@stdlib/repl/lib/main.js index 82b72597615..abfed513e84 100644 --- a/lib/node_modules/@stdlib/repl/lib/main.js +++ b/lib/node_modules/@stdlib/repl/lib/main.js @@ -60,7 +60,6 @@ var processLine = require( './process_line.js' ); var completerFactory = require( './completer.js' ); var PreviewCompleter = require( './completer_preview.js' ); var AutoCloser = require( './auto_close_pairs.js' ); -var AutoDeleter = require( './auto_delete_pairs.js' ); var ALIAS_OVERRIDES = require( './alias_overrides.js' ); var SETTINGS = require( './settings.js' ); var SETTINGS_VALIDATORS = require( './settings_validators.js' ); @@ -255,9 +254,6 @@ function REPL( options ) { // Create a new auto-closer: setNonEnumerableReadOnly( this, '_autoCloser', new AutoCloser( this._rli ) ); - // Create a new auto-deleter: - setNonEnumerableReadOnly( this, '_autoDeleter', new AutoDeleter( this._rli ) ); - // Initialize a preview completer: setNonEnumerableReadOnly( this, '_previewCompleter', new PreviewCompleter( this._rli, this._completer, this._ostream ) ); @@ -307,7 +303,7 @@ function REPL( options ) { function beforeKeypress( data, key ) { var settings = self._settings; if ( key && key.name === 'backspace' && settings.autoDeletePairs ) { - self._autoDeleter.beforeKeypress( data, key ); + self._autoCloser.beforeKeypress( data, key ); } if ( settings.completionPreviews ) { self._previewCompleter.beforeKeypress( data, key ); From d0d1dbf242294423f77458681d5b94111a255fe8 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sun, 31 Mar 2024 00:50:39 -0700 Subject: [PATCH 72/93] fix: ensure corresponding closing symbol when auto-deleting pairs --- .../@stdlib/repl/lib/auto_close_pairs.js | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/lib/node_modules/@stdlib/repl/lib/auto_close_pairs.js b/lib/node_modules/@stdlib/repl/lib/auto_close_pairs.js index b826977ca98..91f0e0ba199 100644 --- a/lib/node_modules/@stdlib/repl/lib/auto_close_pairs.js +++ b/lib/node_modules/@stdlib/repl/lib/auto_close_pairs.js @@ -78,6 +78,7 @@ setNonEnumerableReadOnly( AutoCloser.prototype, 'beforeKeypress', function befor var ch; if ( this._ignoreBackspace ) { + // Reset the backspace flag to re-enable auto-deletion behavior: this._ignoreBackspace = false; return false; } @@ -97,10 +98,9 @@ setNonEnumerableReadOnly( AutoCloser.prototype, 'beforeKeypress', function befor if ( isString( ch ) ) { debug( 'Detected an opening symbol.' ); - debug( 'Checking if immediately followed by a closing symbol...' ); - ch = CLOSE_SYMBOLS[ line[ cursor ] ]; - if ( !isString( ch ) ) { - debug( 'Opening symbol is not followed by a closing symbol. Skipping...' ); + debug( 'Checking if immediately followed by a corresponding closing symbol...' ); + if ( ch !== line[ cursor ] ) { + debug( 'Opening symbol is not followed by a corresponding closing symbol. Skipping...' ); debug( 'Finished performing auto-delete.' ); return false; } @@ -121,6 +121,9 @@ setNonEnumerableReadOnly( AutoCloser.prototype, 'beforeKeypress', function befor this._rli.write( null, { 'name': 'right' }); + + // Set an internal flag to avoid having auto-deletion logic consider this backspace to be user input: + this._ignoreBackspace = true; this._rli.write( null, { 'name': 'backspace' }); @@ -198,8 +201,10 @@ setNonEnumerableReadOnly( AutoCloser.prototype, 'onKeypress', function onKeypres // Support users who may instinctively add a closing symbol by skipping over the closing symbol character in order to avoid inserting an unwanted duplicate character... debug( 'Determining whether a closing symbol already exists...' ); if ( data === line[ cursor ] ) { - debug( 'Closing symbol already exists. Skipping over existing symbol...' ); + // Set an internal flag to avoid having auto-deletion logic consider this backspace to be user input: this._ignoreBackspace = true; + + debug( 'Closing symbol already exists. Skipping over existing symbol...' ); this._rli.write( null, { 'name': 'backspace' }); From d3fd4ef34d60905378cce48c51afd91b756d695b Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sun, 31 Mar 2024 00:57:38 -0700 Subject: [PATCH 73/93] docs: update copy --- lib/node_modules/@stdlib/repl/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/node_modules/@stdlib/repl/README.md b/lib/node_modules/@stdlib/repl/README.md index bcf5a1239b4..0d52ba9a4b0 100644 --- a/lib/node_modules/@stdlib/repl/README.md +++ b/lib/node_modules/@stdlib/repl/README.md @@ -298,7 +298,7 @@ repl.close(); #### REPL.prototype.settings( \[name\[, value]] ) -Gets (and sets) REPL settings. +Returns REPL settings. ```javascript var debug = require( '@stdlib/streams/node/debug-sink' ); @@ -1040,7 +1040,7 @@ Stops saving commands to a file path associated with a specified record identifi #### settings( \[name\[, value]] ) -Gets (and sets) REPL settings. +Displays REPL settings. ```text In [1]: settings() From ff0a086587d9acade8dd92742cd544fb56c04cad Mon Sep 17 00:00:00 2001 From: Snehil Shah Date: Sun, 31 Mar 2024 14:25:49 +0000 Subject: [PATCH 74/93] docs: fix jsdoc Signed-off-by: Snehil Shah --- lib/node_modules/@stdlib/repl/lib/auto_close_pairs.js | 3 --- .../@stdlib/repl/test/integration/test.auto_close_pairs.js | 4 ---- 2 files changed, 7 deletions(-) diff --git a/lib/node_modules/@stdlib/repl/lib/auto_close_pairs.js b/lib/node_modules/@stdlib/repl/lib/auto_close_pairs.js index 91f0e0ba199..e07647b50ee 100644 --- a/lib/node_modules/@stdlib/repl/lib/auto_close_pairs.js +++ b/lib/node_modules/@stdlib/repl/lib/auto_close_pairs.js @@ -65,8 +65,6 @@ function AutoCloser( rli ) { * * @name beforeKeypress * @memberof AutoCloser.prototype -* @param {string} data - input data -* @param {Object} key - key object * @returns {boolean} boolean indicating whether auto-delete was successful */ setNonEnumerableReadOnly( AutoCloser.prototype, 'beforeKeypress', function beforeKeypress() { @@ -142,7 +140,6 @@ setNonEnumerableReadOnly( AutoCloser.prototype, 'beforeKeypress', function befor * @name onKeypress * @memberof AutoCloser.prototype * @param {string} data - input data -* @param {Object} key - key object * @returns {boolean} boolean indicating whether auto-close was successful */ setNonEnumerableReadOnly( AutoCloser.prototype, 'onKeypress', function onKeypress( data ) { diff --git a/lib/node_modules/@stdlib/repl/test/integration/test.auto_close_pairs.js b/lib/node_modules/@stdlib/repl/test/integration/test.auto_close_pairs.js index df31c8eec45..d323387c348 100644 --- a/lib/node_modules/@stdlib/repl/test/integration/test.auto_close_pairs.js +++ b/lib/node_modules/@stdlib/repl/test/integration/test.auto_close_pairs.js @@ -166,8 +166,6 @@ function moveBack( stream, N ) { * @private * @param {Object} t - test object * @param {Object} fixture - fixture object -* @param {string} fixture.expression - incomplete expression string -* @param {NonNegativeInteger} fixture.cursor - cursor position for inserting a character to trigger an insertion * @param {Function} done - callback to invoke upon completion */ function assertAutoClose( t, fixture, done ) { @@ -232,8 +230,6 @@ function assertAutoClose( t, fixture, done ) { * @private * @param {Object} t - test object * @param {Object} fixture - fixture object -* @param {string} fixture.expression - incomplete expression string -* @param {NonNegativeInteger} fixture.cursor - cursor position for inserting a character to trigger an insertion * @param {Function} done - callback to invoke upon completion */ function assertNoAutoClose( t, fixture, done ) { From 10de907cde74d6962c8528e61dad3b980e8d447a Mon Sep 17 00:00:00 2001 From: Snehil Shah Date: Sun, 31 Mar 2024 14:42:38 +0000 Subject: [PATCH 75/93] test: add tests for auto-deletion Signed-off-by: Snehil Shah --- ...expression_left_bracket_within_string.json | 25 +++ .../negative/left_backtick_within_string.json | 25 +++ .../left_double_quote_within_string.json | 25 +++ .../left_parenthesis_within_string.json | 25 +++ .../left_single_quote_within_string.json | 25 +++ ...t_expression_left_brace_within_string.json | 25 +++ .../array_expression_left_bracket.json | 23 +++ .../positive/left_backtick.json | 35 ++++ .../positive/left_double_quote.json | 25 +++ .../positive/left_parenthesis.json | 17 ++ .../positive/left_single_quote.json | 25 +++ .../object_expression_left_brace.json | 18 ++ .../test/integration/test.auto_close_pairs.js | 158 ++++++++++++++++++ 13 files changed, 451 insertions(+) create mode 100644 lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-delete-pairs/negative/array_expression_left_bracket_within_string.json create mode 100644 lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-delete-pairs/negative/left_backtick_within_string.json create mode 100644 lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-delete-pairs/negative/left_double_quote_within_string.json create mode 100644 lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-delete-pairs/negative/left_parenthesis_within_string.json create mode 100644 lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-delete-pairs/negative/left_single_quote_within_string.json create mode 100644 lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-delete-pairs/negative/object_expression_left_brace_within_string.json create mode 100644 lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-delete-pairs/positive/array_expression_left_bracket.json create mode 100644 lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-delete-pairs/positive/left_backtick.json create mode 100644 lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-delete-pairs/positive/left_double_quote.json create mode 100644 lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-delete-pairs/positive/left_parenthesis.json create mode 100644 lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-delete-pairs/positive/left_single_quote.json create mode 100644 lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-delete-pairs/positive/object_expression_left_brace.json diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-delete-pairs/negative/array_expression_left_bracket_within_string.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-delete-pairs/negative/array_expression_left_bracket_within_string.json new file mode 100644 index 00000000000..6b594194e43 --- /dev/null +++ b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-delete-pairs/negative/array_expression_left_bracket_within_string.json @@ -0,0 +1,25 @@ +{ + "expression": "'[]'", + "cursor": 1, + "ast": { + "type": "Program", + "start": 0, + "end": 4, + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 4, + "expression": { + "type": "Literal", + "start": 0, + "end": 4, + "value": "[]", + "raw": "'[]'" + }, + "directive": "[]" + } + ], + "sourceType": "script" + } +} diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-delete-pairs/negative/left_backtick_within_string.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-delete-pairs/negative/left_backtick_within_string.json new file mode 100644 index 00000000000..d5eb5b4bbef --- /dev/null +++ b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-delete-pairs/negative/left_backtick_within_string.json @@ -0,0 +1,25 @@ +{ + "expression": "'``'", + "cursor": 1, + "ast": { + "type": "Program", + "start": 0, + "end": 4, + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 4, + "expression": { + "type": "Literal", + "start": 0, + "end": 4, + "value": "``", + "raw": "'``'" + }, + "directive": "``" + } + ], + "sourceType": "script" + } +} diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-delete-pairs/negative/left_double_quote_within_string.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-delete-pairs/negative/left_double_quote_within_string.json new file mode 100644 index 00000000000..ff10a879931 --- /dev/null +++ b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-delete-pairs/negative/left_double_quote_within_string.json @@ -0,0 +1,25 @@ +{ + "expression": "'\"\"'", + "cursor": 1, + "ast": { + "type": "Program", + "start": 0, + "end": 4, + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 4, + "expression": { + "type": "Literal", + "start": 0, + "end": 4, + "value": "\"\"", + "raw": "'\"\"'" + }, + "directive": "\"\"" + } + ], + "sourceType": "script" + } +} diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-delete-pairs/negative/left_parenthesis_within_string.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-delete-pairs/negative/left_parenthesis_within_string.json new file mode 100644 index 00000000000..828cc79f114 --- /dev/null +++ b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-delete-pairs/negative/left_parenthesis_within_string.json @@ -0,0 +1,25 @@ +{ + "expression": "'()'", + "cursor": 1, + "ast": { + "type": "Program", + "start": 0, + "end": 4, + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 4, + "expression": { + "type": "Literal", + "start": 0, + "end": 4, + "value": "()", + "raw": "'()'" + }, + "directive": "()" + } + ], + "sourceType": "script" + } +} diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-delete-pairs/negative/left_single_quote_within_string.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-delete-pairs/negative/left_single_quote_within_string.json new file mode 100644 index 00000000000..d4adf591ae0 --- /dev/null +++ b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-delete-pairs/negative/left_single_quote_within_string.json @@ -0,0 +1,25 @@ +{ + "expression": "\"''\"", + "cursor": 1, + "ast": { + "type": "Program", + "start": 0, + "end": 2, + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 4, + "expression": { + "type": "Literal", + "start": 0, + "end": 4, + "value": "''", + "raw": "\"''\"" + }, + "directive": "''" + } + ], + "sourceType": "script" + } +} diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-delete-pairs/negative/object_expression_left_brace_within_string.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-delete-pairs/negative/object_expression_left_brace_within_string.json new file mode 100644 index 00000000000..b21b0721757 --- /dev/null +++ b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-delete-pairs/negative/object_expression_left_brace_within_string.json @@ -0,0 +1,25 @@ +{ + "expression": "'{}'", + "cursor": 1, + "ast": { + "type": "Program", + "start": 0, + "end": 4, + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 4, + "expression": { + "type": "Literal", + "start": 0, + "end": 4, + "value": "{}", + "raw": "'{}'" + }, + "directive": "{}" + } + ], + "sourceType": "script" + } +} diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-delete-pairs/positive/array_expression_left_bracket.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-delete-pairs/positive/array_expression_left_bracket.json new file mode 100644 index 00000000000..08cd5bda846 --- /dev/null +++ b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-delete-pairs/positive/array_expression_left_bracket.json @@ -0,0 +1,23 @@ +{ + "expression": "[]", + "cursor": 1, + "ast": { + "type": "Program", + "start": 0, + "end": 2, + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 2, + "expression": { + "type": "ArrayExpression", + "start": 0, + "end": 2, + "elements": [] + } + } + ], + "sourceType": "script" + } +} diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-delete-pairs/positive/left_backtick.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-delete-pairs/positive/left_backtick.json new file mode 100644 index 00000000000..5348d6d37f8 --- /dev/null +++ b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-delete-pairs/positive/left_backtick.json @@ -0,0 +1,35 @@ +{ + "expression": "``", + "cursor": 1, + "ast": { + "type": "Program", + "start": 0, + "end": 2, + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 2, + "expression": { + "type": "TemplateLiteral", + "start": 0, + "end": 2, + "expressions": [], + "quasis": [ + { + "type": "TemplateElement", + "start": 1, + "end": 1, + "value": { + "raw": "", + "cooked": "" + }, + "tail": true + } + ] + } + } + ], + "sourceType": "script" + } +} diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-delete-pairs/positive/left_double_quote.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-delete-pairs/positive/left_double_quote.json new file mode 100644 index 00000000000..9639e899d39 --- /dev/null +++ b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-delete-pairs/positive/left_double_quote.json @@ -0,0 +1,25 @@ +{ + "expression": "\"\"", + "cursor": 1, + "ast": { + "type": "Program", + "start": 0, + "end": 2, + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 2, + "expression": { + "type": "Literal", + "start": 0, + "end": 2, + "value": "", + "raw": "\"\"" + }, + "directive": "" + } + ], + "sourceType": "script" + } +} diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-delete-pairs/positive/left_parenthesis.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-delete-pairs/positive/left_parenthesis.json new file mode 100644 index 00000000000..b73b4e93051 --- /dev/null +++ b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-delete-pairs/positive/left_parenthesis.json @@ -0,0 +1,17 @@ +{ + "expression": "()", + "cursor": 1, + "ast": { + "type": "Program", + "start": 0, + "end": 2, + "body": [ + { + "type": "EmptyStatement", + "start": 0, + "end": 2 + } + ], + "sourceType": "script" + } +} diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-delete-pairs/positive/left_single_quote.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-delete-pairs/positive/left_single_quote.json new file mode 100644 index 00000000000..d35d8a7ee2c --- /dev/null +++ b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-delete-pairs/positive/left_single_quote.json @@ -0,0 +1,25 @@ +{ + "expression": "''", + "cursor": 1, + "ast": { + "type": "Program", + "start": 0, + "end": 2, + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 2, + "expression": { + "type": "Literal", + "start": 0, + "end": 2, + "value": "", + "raw": "''" + }, + "directive": "" + } + ], + "sourceType": "script" + } +} diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-delete-pairs/positive/object_expression_left_brace.json b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-delete-pairs/positive/object_expression_left_brace.json new file mode 100644 index 00000000000..af0eda1167e --- /dev/null +++ b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-delete-pairs/positive/object_expression_left_brace.json @@ -0,0 +1,18 @@ +{ + "expression": "{}", + "cursor": 1, + "ast": { + "type": "Program", + "start": 0, + "end": 2, + "body": [ + { + "type": "BlockStatement", + "start": 0, + "end": 2, + "body": [] + } + ], + "sourceType": "script" + } +} diff --git a/lib/node_modules/@stdlib/repl/test/integration/test.auto_close_pairs.js b/lib/node_modules/@stdlib/repl/test/integration/test.auto_close_pairs.js index d323387c348..1cfe8ebaad4 100644 --- a/lib/node_modules/@stdlib/repl/test/integration/test.auto_close_pairs.js +++ b/lib/node_modules/@stdlib/repl/test/integration/test.auto_close_pairs.js @@ -43,6 +43,12 @@ var POSITIVE_FIXTURES_FILES = filter( readDir( POSITIVE_FIXTURES_DIR ) ); var NEGATIVE_FIXTURES_DIR = resolve( __dirname, 'fixtures', 'auto-close-pairs', 'negative' ); var NEGATIVE_FIXTURES_FILES = filter( readDir( NEGATIVE_FIXTURES_DIR ) ); +var POSITIVE_FIXTURES_DELETE_DIR = resolve( __dirname, 'fixtures', 'auto-delete-pairs', 'positive' ); // eslint-disable-line id-length +var POSITIVE_FIXTURES_DELETE_FILES = filter( readDir( POSITIVE_FIXTURES_DELETE_DIR ) ); // eslint-disable-line max-len, id-length + +var NEGATIVE_FIXTURES_DELETE_DIR = resolve( __dirname, 'fixtures', 'auto-delete-pairs', 'negative' ); // eslint-disable-line id-length +var NEGATIVE_FIXTURES_DELETE_FILES = filter( readDir( NEGATIVE_FIXTURES_DELETE_DIR ) ); // eslint-disable-line max-len, id-length + // FUNCTIONS // @@ -284,6 +290,154 @@ function assertNoAutoClose( t, fixture, done ) { } } +/** +* Asserts that a provided expression triggers expected automatic deletion of closed symbols. +* +* @private +* @param {Object} t - test object +* @param {Object} fixture - fixture object +* @param {Function} done - callback to invoke upon completion +*/ +function assertAutoDelete( t, fixture, done ) { + var expected; + var istream; + var opts; + var N; + var r; + + istream = new DebugStream({ + 'name': 'repl-input-stream' + }); + opts = { + 'input': istream, + 'inputPrompt': '', + 'quiet': true, + 'settings': defaultSettings() + }; + r = repl( opts, onClose ); + + istream = new DebugStream({ + 'name': 'repl-input-stream' + }); + opts = { + 'input': istream, + 'inputPrompt': '', + 'quiet': true, + 'settings': defaultSettings() + }; + r = repl( opts, onClose ); + + // Construct the expected output: + expected = fixture.expression.substring( 0, fixture.cursor-1 ); + expected += fixture.expression.substring( fixture.cursor+1 ); + + // Emulate the presence of an existing expression: + istream.write( fixture.expression ); + + // Move the cursor to where we want to delete a character: + N = fixture.expression.length - fixture.cursor; + moveBack( istream, N ); + + // Enable auto-close: + r.settings( 'autoClosePairs', true ); + + // Delete the character in order to trigger auto-delete: + r._rli.write( null, { // eslint-disable-line no-underscore-dangle + 'name': 'backspace' + }); + + // Close the input stream: + istream.end(); + + // Close the REPL: + r.close(); + + function onClose( error, data ) { + var actual; + if ( error ) { + t.fail( error.message ); + return; + } + actual = processOutput( data, N === 0 ); + t.strictEqual( actual, expected, 'returns expected value' ); + done(); + } +} + +/** +* Asserts that a provided expression does not trigger automatic deletion of closed symbols. +* +* @private +* @param {Object} t - test object +* @param {Object} fixture - fixture object +* @param {Function} done - callback to invoke upon completion +*/ +function assertNoAutoDelete( t, fixture, done ) { + var expected; + var istream; + var opts; + var N; + var r; + + istream = new DebugStream({ + 'name': 'repl-input-stream' + }); + opts = { + 'input': istream, + 'inputPrompt': '', + 'quiet': true, + 'settings': defaultSettings() + }; + r = repl( opts, onClose ); + + istream = new DebugStream({ + 'name': 'repl-input-stream' + }); + opts = { + 'input': istream, + 'inputPrompt': '', + 'quiet': true, + 'settings': defaultSettings() + }; + r = repl( opts, onClose ); + + // Construct the expected output: + expected = fixture.expression.substring( 0, fixture.cursor-1 ); + expected += fixture.expression.substring( fixture.cursor ); + + // Emulate the presence of an existing expression: + istream.write( fixture.expression ); + + // Move the cursor to where we want to delete a character: + N = fixture.expression.length - fixture.cursor; + moveBack( istream, N ); + + // Enable auto-close: + r.settings( 'autoClosePairs', true ); + + // Delete the character in order to trigger auto-delete: + r._rli.write( null, { // eslint-disable-line no-underscore-dangle + 'name': 'backspace' + }); + + // Close the input stream: + istream.end(); + + // Close the REPL: + r.close(); + + function onClose( error, data ) { + var actual; + if ( error ) { + t.fail( error.message ); + return; + } + actual = processOutput( data, N === 0 ); + t.strictEqual( actual, expected, 'returns expected value' ); + done(); + } +} + /** * Generates a test name from a fixture file name. * @@ -354,3 +508,7 @@ tape( 'main export is a function', function test( t ) { test( 'a REPL instance supports automatically closing paired symbols', POSITIVE_FIXTURES_DIR, POSITIVE_FIXTURES_FILES, assertAutoClose ); test( 'a REPL instance avoids unnecessarily inserting closing symbols', NEGATIVE_FIXTURES_DIR, NEGATIVE_FIXTURES_FILES, assertNoAutoClose ); + +test( 'a REPL instance supports automatically deleting paired symbols', POSITIVE_FIXTURES_DELETE_DIR, POSITIVE_FIXTURES_DELETE_FILES, assertAutoDelete ); + +test( 'a REPL instance avoids auto-deletion when symbols are within a string literal', NEGATIVE_FIXTURES_DELETE_DIR, NEGATIVE_FIXTURES_DELETE_FILES, assertNoAutoDelete ); From 2f53984ba234cd8ee927e724dc3da48706d2294e Mon Sep 17 00:00:00 2001 From: Snehil Shah Date: Sun, 31 Mar 2024 21:03:55 +0000 Subject: [PATCH 76/93] Revert "docs: fix jsdoc" This reverts commit ff0a086587d9acade8dd92742cd544fb56c04cad. --- lib/node_modules/@stdlib/repl/lib/auto_close_pairs.js | 3 +++ .../@stdlib/repl/test/integration/test.auto_close_pairs.js | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/lib/node_modules/@stdlib/repl/lib/auto_close_pairs.js b/lib/node_modules/@stdlib/repl/lib/auto_close_pairs.js index e07647b50ee..91f0e0ba199 100644 --- a/lib/node_modules/@stdlib/repl/lib/auto_close_pairs.js +++ b/lib/node_modules/@stdlib/repl/lib/auto_close_pairs.js @@ -65,6 +65,8 @@ function AutoCloser( rli ) { * * @name beforeKeypress * @memberof AutoCloser.prototype +* @param {string} data - input data +* @param {Object} key - key object * @returns {boolean} boolean indicating whether auto-delete was successful */ setNonEnumerableReadOnly( AutoCloser.prototype, 'beforeKeypress', function beforeKeypress() { @@ -140,6 +142,7 @@ setNonEnumerableReadOnly( AutoCloser.prototype, 'beforeKeypress', function befor * @name onKeypress * @memberof AutoCloser.prototype * @param {string} data - input data +* @param {Object} key - key object * @returns {boolean} boolean indicating whether auto-close was successful */ setNonEnumerableReadOnly( AutoCloser.prototype, 'onKeypress', function onKeypress( data ) { diff --git a/lib/node_modules/@stdlib/repl/test/integration/test.auto_close_pairs.js b/lib/node_modules/@stdlib/repl/test/integration/test.auto_close_pairs.js index 1cfe8ebaad4..4c96638c480 100644 --- a/lib/node_modules/@stdlib/repl/test/integration/test.auto_close_pairs.js +++ b/lib/node_modules/@stdlib/repl/test/integration/test.auto_close_pairs.js @@ -172,6 +172,8 @@ function moveBack( stream, N ) { * @private * @param {Object} t - test object * @param {Object} fixture - fixture object +* @param {string} fixture.expression - incomplete expression string +* @param {NonNegativeInteger} fixture.cursor - cursor position for inserting a character to trigger an insertion * @param {Function} done - callback to invoke upon completion */ function assertAutoClose( t, fixture, done ) { @@ -236,6 +238,8 @@ function assertAutoClose( t, fixture, done ) { * @private * @param {Object} t - test object * @param {Object} fixture - fixture object +* @param {string} fixture.expression - incomplete expression string +* @param {NonNegativeInteger} fixture.cursor - cursor position for inserting a character to trigger an insertion * @param {Function} done - callback to invoke upon completion */ function assertNoAutoClose( t, fixture, done ) { From a1477a38780009bd12847637a8ad38487bf5563c Mon Sep 17 00:00:00 2001 From: Snehil Shah Date: Sun, 31 Mar 2024 21:17:11 +0000 Subject: [PATCH 77/93] test: fix tests Signed-off-by: Snehil Shah --- .../test/integration/test.auto_close_pairs.js | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/lib/node_modules/@stdlib/repl/test/integration/test.auto_close_pairs.js b/lib/node_modules/@stdlib/repl/test/integration/test.auto_close_pairs.js index 4c96638c480..69b5ad4a590 100644 --- a/lib/node_modules/@stdlib/repl/test/integration/test.auto_close_pairs.js +++ b/lib/node_modules/@stdlib/repl/test/integration/test.auto_close_pairs.js @@ -148,6 +148,7 @@ function spliced2expected( s ) { function defaultSettings() { return { 'autoClosePairs': false, + 'autoDeletePairs': false, 'completionPreviews': false }; } @@ -342,13 +343,11 @@ function assertAutoDelete( t, fixture, done ) { N = fixture.expression.length - fixture.cursor; moveBack( istream, N ); - // Enable auto-close: - r.settings( 'autoClosePairs', true ); + // Enable auto-delete: + r.settings( 'autoDeletePairs', true ); // Delete the character in order to trigger auto-delete: - r._rli.write( null, { // eslint-disable-line no-underscore-dangle - 'name': 'backspace' - }); + istream.write( '\x08' ); // Close the input stream: istream.end(); @@ -416,13 +415,11 @@ function assertNoAutoDelete( t, fixture, done ) { N = fixture.expression.length - fixture.cursor; moveBack( istream, N ); - // Enable auto-close: - r.settings( 'autoClosePairs', true ); + // Enable auto-delete: + r.settings( 'autoDeletePairs', true ); // Delete the character in order to trigger auto-delete: - r._rli.write( null, { // eslint-disable-line no-underscore-dangle - 'name': 'backspace' - }); + istream.write( '\x08' ); // Close the input stream: istream.end(); From 6ab1028637208ac3a313a2289f9fa46dd0323728 Mon Sep 17 00:00:00 2001 From: Snehil Shah Date: Sun, 31 Mar 2024 21:35:38 +0000 Subject: [PATCH 78/93] refactor: separate auto-delete & auto-closing tests Signed-off-by: Snehil Shah --- .../test/integration/test.auto_close_pairs.js | 154 -------- .../integration/test.auto_delete_pairs.js | 345 ++++++++++++++++++ 2 files changed, 345 insertions(+), 154 deletions(-) create mode 100644 lib/node_modules/@stdlib/repl/test/integration/test.auto_delete_pairs.js diff --git a/lib/node_modules/@stdlib/repl/test/integration/test.auto_close_pairs.js b/lib/node_modules/@stdlib/repl/test/integration/test.auto_close_pairs.js index 69b5ad4a590..5c652ad58b3 100644 --- a/lib/node_modules/@stdlib/repl/test/integration/test.auto_close_pairs.js +++ b/lib/node_modules/@stdlib/repl/test/integration/test.auto_close_pairs.js @@ -43,12 +43,6 @@ var POSITIVE_FIXTURES_FILES = filter( readDir( POSITIVE_FIXTURES_DIR ) ); var NEGATIVE_FIXTURES_DIR = resolve( __dirname, 'fixtures', 'auto-close-pairs', 'negative' ); var NEGATIVE_FIXTURES_FILES = filter( readDir( NEGATIVE_FIXTURES_DIR ) ); -var POSITIVE_FIXTURES_DELETE_DIR = resolve( __dirname, 'fixtures', 'auto-delete-pairs', 'positive' ); // eslint-disable-line id-length -var POSITIVE_FIXTURES_DELETE_FILES = filter( readDir( POSITIVE_FIXTURES_DELETE_DIR ) ); // eslint-disable-line max-len, id-length - -var NEGATIVE_FIXTURES_DELETE_DIR = resolve( __dirname, 'fixtures', 'auto-delete-pairs', 'negative' ); // eslint-disable-line id-length -var NEGATIVE_FIXTURES_DELETE_FILES = filter( readDir( NEGATIVE_FIXTURES_DELETE_DIR ) ); // eslint-disable-line max-len, id-length - // FUNCTIONS // @@ -295,150 +289,6 @@ function assertNoAutoClose( t, fixture, done ) { } } -/** -* Asserts that a provided expression triggers expected automatic deletion of closed symbols. -* -* @private -* @param {Object} t - test object -* @param {Object} fixture - fixture object -* @param {Function} done - callback to invoke upon completion -*/ -function assertAutoDelete( t, fixture, done ) { - var expected; - var istream; - var opts; - var N; - var r; - - istream = new DebugStream({ - 'name': 'repl-input-stream' - }); - opts = { - 'input': istream, - 'inputPrompt': '', - 'quiet': true, - 'settings': defaultSettings() - }; - r = repl( opts, onClose ); - - istream = new DebugStream({ - 'name': 'repl-input-stream' - }); - opts = { - 'input': istream, - 'inputPrompt': '', - 'quiet': true, - 'settings': defaultSettings() - }; - r = repl( opts, onClose ); - - // Construct the expected output: - expected = fixture.expression.substring( 0, fixture.cursor-1 ); - expected += fixture.expression.substring( fixture.cursor+1 ); - - // Emulate the presence of an existing expression: - istream.write( fixture.expression ); - - // Move the cursor to where we want to delete a character: - N = fixture.expression.length - fixture.cursor; - moveBack( istream, N ); - - // Enable auto-delete: - r.settings( 'autoDeletePairs', true ); - - // Delete the character in order to trigger auto-delete: - istream.write( '\x08' ); - - // Close the input stream: - istream.end(); - - // Close the REPL: - r.close(); - - function onClose( error, data ) { - var actual; - if ( error ) { - t.fail( error.message ); - return; - } - actual = processOutput( data, N === 0 ); - t.strictEqual( actual, expected, 'returns expected value' ); - done(); - } -} - -/** -* Asserts that a provided expression does not trigger automatic deletion of closed symbols. -* -* @private -* @param {Object} t - test object -* @param {Object} fixture - fixture object -* @param {Function} done - callback to invoke upon completion -*/ -function assertNoAutoDelete( t, fixture, done ) { - var expected; - var istream; - var opts; - var N; - var r; - - istream = new DebugStream({ - 'name': 'repl-input-stream' - }); - opts = { - 'input': istream, - 'inputPrompt': '', - 'quiet': true, - 'settings': defaultSettings() - }; - r = repl( opts, onClose ); - - istream = new DebugStream({ - 'name': 'repl-input-stream' - }); - opts = { - 'input': istream, - 'inputPrompt': '', - 'quiet': true, - 'settings': defaultSettings() - }; - r = repl( opts, onClose ); - - // Construct the expected output: - expected = fixture.expression.substring( 0, fixture.cursor-1 ); - expected += fixture.expression.substring( fixture.cursor ); - - // Emulate the presence of an existing expression: - istream.write( fixture.expression ); - - // Move the cursor to where we want to delete a character: - N = fixture.expression.length - fixture.cursor; - moveBack( istream, N ); - - // Enable auto-delete: - r.settings( 'autoDeletePairs', true ); - - // Delete the character in order to trigger auto-delete: - istream.write( '\x08' ); - - // Close the input stream: - istream.end(); - - // Close the REPL: - r.close(); - - function onClose( error, data ) { - var actual; - if ( error ) { - t.fail( error.message ); - return; - } - actual = processOutput( data, N === 0 ); - t.strictEqual( actual, expected, 'returns expected value' ); - done(); - } -} - /** * Generates a test name from a fixture file name. * @@ -509,7 +359,3 @@ tape( 'main export is a function', function test( t ) { test( 'a REPL instance supports automatically closing paired symbols', POSITIVE_FIXTURES_DIR, POSITIVE_FIXTURES_FILES, assertAutoClose ); test( 'a REPL instance avoids unnecessarily inserting closing symbols', NEGATIVE_FIXTURES_DIR, NEGATIVE_FIXTURES_FILES, assertNoAutoClose ); - -test( 'a REPL instance supports automatically deleting paired symbols', POSITIVE_FIXTURES_DELETE_DIR, POSITIVE_FIXTURES_DELETE_FILES, assertAutoDelete ); - -test( 'a REPL instance avoids auto-deletion when symbols are within a string literal', NEGATIVE_FIXTURES_DELETE_DIR, NEGATIVE_FIXTURES_DELETE_FILES, assertNoAutoDelete ); diff --git a/lib/node_modules/@stdlib/repl/test/integration/test.auto_delete_pairs.js b/lib/node_modules/@stdlib/repl/test/integration/test.auto_delete_pairs.js new file mode 100644 index 00000000000..366e529c67e --- /dev/null +++ b/lib/node_modules/@stdlib/repl/test/integration/test.auto_delete_pairs.js @@ -0,0 +1,345 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2024 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +// MODULES // + +var resolve = require( 'path' ).resolve; +var tape = require( 'tape' ); +var DebugStream = require( '@stdlib/streams/node/debug' ); +var trim = require( '@stdlib/string/trim' ); +var replace = require( '@stdlib/string/replace' ); +var readDir = require( '@stdlib/fs/read-dir' ).sync; +var format = require( '@stdlib/string/format' ); +var repl = require( './fixtures/repl.js' ); + + +// VARIABLES // + +var RE_JSON = /\.json$/; + +var RE_ANSI = /[\u001B\u009B][[\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\d/#&.:=?%@~_]+)*|[a-zA-Z\d]+(?:;[-a-zA-Z\d/#&.:=?%@~_]*)*)?\u0007)|(?:(?:\d{1,4}(?:;\d{0,4})*)?[\dA-PR-TZcf-nq-uy=><~]))/g; // eslint-disable-line no-control-regex + +var POSITIVE_FIXTURES_DIR = resolve( __dirname, 'fixtures', 'auto-delete-pairs', 'positive' ); +var POSITIVE_FIXTURES_FILES = filter( readDir( POSITIVE_FIXTURES_DIR ) ); + +var NEGATIVE_FIXTURES_DIR = resolve( __dirname, 'fixtures', 'auto-delete-pairs', 'negative' ); +var NEGATIVE_FIXTURES_FILES = filter( readDir( NEGATIVE_FIXTURES_DIR ) ); + + +// FUNCTIONS // + +/** +* Filters a list of files for those having a `*.json` file extension. +* +* @private +* @param {Array} list - file list +* @returns {Array} filtered list +*/ +function filter( list ) { + var out; + var i; + + out = []; + for ( i = 0; i < list.length; i++ ) { + if ( RE_JSON.test( list[ i ] ) ) { + out.push( list[ i ] ); + } + } + return out; +} + +/** +* Removes ANSI escape codes from a string. +* +* @private +* @param {string} str - input string +* @returns {string} string with ANSI escape codes removed +*/ +function stripANSI( str ) { + return replace( str, RE_ANSI, '' ); +} + +/** +* Processes output stream text and returns a string representing what is currently displayed in the REPL. +* +* ## Notes +* +* - We can rely on simple concatenation when a test expression proceeds from left-to-right (i.e., as if a user normally types); however, when a user backtracks (e.g., by moving the cursor to the left), the REPL needs to refresh the displayed text (in full) in order to shift any text after the cursor to the right to make room for inserted characters. +* +* @private +* @param {Array} raw - unprocessed output data +* @param {boolean} flg - boolean indicating whether to concatenate unprocessed output data +* @returns {string} output string +*/ +function processOutput( raw, flg ) { + var i; + if ( flg ) { + return trim( stripANSI( raw.join( '' ) ) ); + } + for ( i = raw.length-1; i >= 0; i-- ) { + // Check whether the screen display was erased, as the next element is the refreshed line... + if ( raw[ i ] === '\u001b[0J' ) { + return raw[ i+1 ]; + } + } +} + +/** +* Returns default settings. +* +* @private +* @returns {Object} default settings +*/ +function defaultSettings() { + return { + 'autoClosePairs': false, + 'autoDeletePairs': false, + 'completionPreviews': false + }; +} + +/** +* Moves a cursor backward a specified number of positions. +* +* @private +* @param {WriteStream} stream - writable stream +* @param {NonNegativeInteger} N - number of positions +*/ +function moveBack( stream, N ) { + var i; + for ( i = 0; i < N; i++ ) { + stream.write( '\u001b[1D' ); + } +} + +/** +* Asserts that a provided expression triggers expected automatic deletion of closed symbols. +* +* @private +* @param {Object} t - test object +* @param {Object} fixture - fixture object +* @param {Function} done - callback to invoke upon completion +*/ +function assertAutoDelete( t, fixture, done ) { + var expected; + var istream; + var opts; + var N; + var r; + + istream = new DebugStream({ + 'name': 'repl-input-stream' + }); + opts = { + 'input': istream, + 'inputPrompt': '', + 'quiet': true, + 'settings': defaultSettings() + }; + r = repl( opts, onClose ); + + istream = new DebugStream({ + 'name': 'repl-input-stream' + }); + opts = { + 'input': istream, + 'inputPrompt': '', + 'quiet': true, + 'settings': defaultSettings() + }; + r = repl( opts, onClose ); + + // Construct the expected output: + expected = fixture.expression.substring( 0, fixture.cursor-1 ); + expected += fixture.expression.substring( fixture.cursor+1 ); + + // Emulate the presence of an existing expression: + istream.write( fixture.expression ); + + // Move the cursor to where we want to delete a character: + N = fixture.expression.length - fixture.cursor; + moveBack( istream, N ); + + // Enable auto-delete: + r.settings( 'autoDeletePairs', true ); + + // Delete the character in order to trigger auto-delete: + istream.write( '\u0008' ); + + // Close the input stream: + istream.end(); + + // Close the REPL: + r.close(); + + function onClose( error, data ) { + var actual; + if ( error ) { + t.fail( error.message ); + return; + } + actual = processOutput( data, N === 0 ); + t.strictEqual( actual, expected, 'returns expected value' ); + done(); + } +} + +/** +* Asserts that a provided expression does not trigger automatic deletion of closed symbols. +* +* @private +* @param {Object} t - test object +* @param {Object} fixture - fixture object +* @param {Function} done - callback to invoke upon completion +*/ +function assertNoAutoDelete( t, fixture, done ) { + var expected; + var istream; + var opts; + var N; + var r; + + istream = new DebugStream({ + 'name': 'repl-input-stream' + }); + opts = { + 'input': istream, + 'inputPrompt': '', + 'quiet': true, + 'settings': defaultSettings() + }; + r = repl( opts, onClose ); + + istream = new DebugStream({ + 'name': 'repl-input-stream' + }); + opts = { + 'input': istream, + 'inputPrompt': '', + 'quiet': true, + 'settings': defaultSettings() + }; + r = repl( opts, onClose ); + + // Construct the expected output: + expected = fixture.expression.substring( 0, fixture.cursor-1 ); + expected += fixture.expression.substring( fixture.cursor ); + + // Emulate the presence of an existing expression: + istream.write( fixture.expression ); + + // Move the cursor to where we want to delete a character: + N = fixture.expression.length - fixture.cursor; + moveBack( istream, N ); + + // Enable auto-delete: + r.settings( 'autoDeletePairs', true ); + + // Delete the character in order to trigger auto-delete: + istream.write( '\u0008' ); + + // Close the input stream: + istream.end(); + + // Close the REPL: + r.close(); + + function onClose( error, data ) { + var actual; + if ( error ) { + t.fail( error.message ); + return; + } + actual = processOutput( data, N === 0 ); + t.strictEqual( actual, expected, 'returns expected value' ); + done(); + } +} + +/** +* Generates a test name from a fixture file name. +* +* @private +* @param {string} msg - test description +* @param {string} filename - file name +* @returns {string} test name +*/ +function testName( msg, filename ) { + var str = replace( filename, RE_JSON, '' ); + str = replace( str, '_', ' ' ); + return format( '%s (%s)', msg, str ); +} + +/** +* Returns a test function for testing against a specified fixture file. +* +* @private +* @param {string} fpath - fixture file path +* @param {Function} assert - assertion function +* @returns {Function} test function +*/ +function testFcn( fpath, assert ) { + return test; + + function test( t ) { + var fixture = require( fpath ); // eslint-disable-line stdlib/no-dynamic-require + assert( t, fixture, done ); + + function done() { + t.end(); + } + } +} + +/** +* Run tests against test fixtures. +* +* @private +* @param {string} msg - test description +* @param {string} dir - fixtures directory +* @param {Array} fixtures - list of fixtures +* @param {Function} assert - assert function +*/ +function test( msg, dir, fixtures, assert ) { + var fpath; + var f; + var t; + var i; + + for ( i = 0; i < fixtures.length; i++ ) { + f = fixtures[ i ]; + t = testName( msg, f ); + fpath = resolve( dir, f ); + tape( t, testFcn( fpath, assert ) ); + } +} + + +// TESTS // + +tape( 'main export is a function', function test( t ) { + t.ok( true, __filename ); + t.strictEqual( typeof repl, 'function', 'main export is a function' ); + t.end(); +}); + +test( 'a REPL instance supports automatically deleting paired symbols', POSITIVE_FIXTURES_DIR, POSITIVE_FIXTURES_FILES, assertAutoDelete ); + +test( 'a REPL instance avoids auto-deletion when symbols are within a string literal', NEGATIVE_FIXTURES_DIR, NEGATIVE_FIXTURES_FILES, assertNoAutoDelete ); From 6b1f6f0b4ee1463cbb2ec395881b2d75a35d0456 Mon Sep 17 00:00:00 2001 From: Snehil Shah Date: Sun, 31 Mar 2024 21:52:41 +0000 Subject: [PATCH 79/93] refactor: move conditional to the method itself Signed-off-by: Snehil Shah --- .../@stdlib/repl/lib/auto_close_pairs.js | 106 +++++++++--------- lib/node_modules/@stdlib/repl/lib/main.js | 2 +- 2 files changed, 55 insertions(+), 53 deletions(-) diff --git a/lib/node_modules/@stdlib/repl/lib/auto_close_pairs.js b/lib/node_modules/@stdlib/repl/lib/auto_close_pairs.js index 91f0e0ba199..9706601d058 100644 --- a/lib/node_modules/@stdlib/repl/lib/auto_close_pairs.js +++ b/lib/node_modules/@stdlib/repl/lib/auto_close_pairs.js @@ -65,11 +65,11 @@ function AutoCloser( rli ) { * * @name beforeKeypress * @memberof AutoCloser.prototype -* @param {string} data - input data +* @param {string} input - input data * @param {Object} key - key object * @returns {boolean} boolean indicating whether auto-delete was successful */ -setNonEnumerableReadOnly( AutoCloser.prototype, 'beforeKeypress', function beforeKeypress() { +setNonEnumerableReadOnly( AutoCloser.prototype, 'beforeKeypress', function beforeKeypress( input, key ) { var cursor; var line; var data; @@ -77,63 +77,65 @@ setNonEnumerableReadOnly( AutoCloser.prototype, 'beforeKeypress', function befor var ast; var ch; - if ( this._ignoreBackspace ) { - // Reset the backspace flag to re-enable auto-deletion behavior: - this._ignoreBackspace = false; - return false; - } - cursor = this._rli.cursor; - line = this._rli.line; - - debug( 'Expression: %s', line ); - debug( 'Cursor position: %d', cursor ); - - debug( 'Performing auto-delete...' ); - - data = line[ cursor-1 ]; - debug( 'Character to delete: %s', data ); - - debug( 'Checking if an opening symbol...' ); - ch = OPEN_SYMBOLS[ data ]; - if ( isString( ch ) ) { - debug( 'Detected an opening symbol.' ); - - debug( 'Checking if immediately followed by a corresponding closing symbol...' ); - if ( ch !== line[ cursor ] ) { - debug( 'Opening symbol is not followed by a corresponding closing symbol. Skipping...' ); - debug( 'Finished performing auto-delete.' ); + if ( key && key.name === 'backspace' ) { + if ( this._ignoreBackspace ) { + // Reset the backspace flag to re-enable auto-deletion behavior: + this._ignoreBackspace = false; return false; } - debug( 'Detected a closing symbol.' ); - - debug( 'Generating an AST...' ); - ast = parse( line, AOPTS ); + cursor = this._rli.cursor; + line = this._rli.line; + + debug( 'Expression: %s', line ); + debug( 'Cursor position: %d', cursor ); + + debug( 'Performing auto-delete...' ); + + data = line[ cursor-1 ]; + debug( 'Character to delete: %s', data ); + + debug( 'Checking if an opening symbol...' ); + ch = OPEN_SYMBOLS[ data ]; + if ( isString( ch ) ) { + debug( 'Detected an opening symbol.' ); + + debug( 'Checking if immediately followed by a corresponding closing symbol...' ); + if ( ch !== line[ cursor ] ) { + debug( 'Opening symbol is not followed by a corresponding closing symbol. Skipping...' ); + debug( 'Finished performing auto-delete.' ); + return false; + } + debug( 'Detected a closing symbol.' ); + + debug( 'Generating an AST...' ); + ast = parse( line, AOPTS ); + + debug( 'Checking whether characters are within a string literal...' ); + node = findNodeAround( ast, cursor-1, 'Literal' ); + if ( node && node.node.start < cursor-1 ) { + debug( 'Characters are within a string literal. Skipping...' ); + debug( 'Finished performing auto-delete.' ); + return false; + } + debug( 'Characters are not within a string literal.' ); + debug( 'Found an auto-delete candidate. Deleting symbols...' ); + this._rli.write( null, { + 'name': 'right' + }); - debug( 'Checking whether characters are within a string literal...' ); - node = findNodeAround( ast, cursor-1, 'Literal' ); - if ( node && node.node.start < cursor-1 ) { - debug( 'Characters are within a string literal. Skipping...' ); + // Set an internal flag to avoid having auto-deletion logic consider this backspace to be user input: + this._ignoreBackspace = true; + this._rli.write( null, { + 'name': 'backspace' + }); + debug( 'Resulting expression: %s', this._rli.line ); debug( 'Finished performing auto-delete.' ); - return false; + return true; } - debug( 'Characters are not within a string literal.' ); - debug( 'Found an auto-delete candidate. Deleting symbols...' ); - this._rli.write( null, { - 'name': 'right' - }); - - // Set an internal flag to avoid having auto-deletion logic consider this backspace to be user input: - this._ignoreBackspace = true; - this._rli.write( null, { - 'name': 'backspace' - }); - debug( 'Resulting expression: %s', this._rli.line ); + debug( 'Failed to detect an opening symbol.' ); debug( 'Finished performing auto-delete.' ); - return true; + return false; } - debug( 'Failed to detect an opening symbol.' ); - debug( 'Finished performing auto-delete.' ); - return false; }); /** diff --git a/lib/node_modules/@stdlib/repl/lib/main.js b/lib/node_modules/@stdlib/repl/lib/main.js index abfed513e84..bb0819c3973 100644 --- a/lib/node_modules/@stdlib/repl/lib/main.js +++ b/lib/node_modules/@stdlib/repl/lib/main.js @@ -302,7 +302,7 @@ function REPL( options ) { */ function beforeKeypress( data, key ) { var settings = self._settings; - if ( key && key.name === 'backspace' && settings.autoDeletePairs ) { + if ( settings.autoDeletePairs ) { self._autoCloser.beforeKeypress( data, key ); } if ( settings.completionPreviews ) { From b8344c815937a766c44da6fbd9a4ea6d1219b970 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sun, 31 Mar 2024 16:36:14 -0700 Subject: [PATCH 80/93] refactor: early return to avoid unnecessary indentation and rename parameter --- .../@stdlib/repl/lib/auto_close_pairs.js | 110 +++++++++--------- 1 file changed, 55 insertions(+), 55 deletions(-) diff --git a/lib/node_modules/@stdlib/repl/lib/auto_close_pairs.js b/lib/node_modules/@stdlib/repl/lib/auto_close_pairs.js index 9706601d058..d4deef205b9 100644 --- a/lib/node_modules/@stdlib/repl/lib/auto_close_pairs.js +++ b/lib/node_modules/@stdlib/repl/lib/auto_close_pairs.js @@ -65,77 +65,77 @@ function AutoCloser( rli ) { * * @name beforeKeypress * @memberof AutoCloser.prototype -* @param {string} input - input data +* @param {string} data - input data * @param {Object} key - key object * @returns {boolean} boolean indicating whether auto-delete was successful */ -setNonEnumerableReadOnly( AutoCloser.prototype, 'beforeKeypress', function beforeKeypress( input, key ) { +setNonEnumerableReadOnly( AutoCloser.prototype, 'beforeKeypress', function beforeKeypress( data, key ) { var cursor; var line; - var data; var node; var ast; var ch; - if ( key && key.name === 'backspace' ) { - if ( this._ignoreBackspace ) { - // Reset the backspace flag to re-enable auto-deletion behavior: - this._ignoreBackspace = false; + if ( !key || key.name !== 'backspace' ) { + return false; + } + if ( this._ignoreBackspace ) { + // Reset the backspace flag to re-enable auto-deletion behavior: + this._ignoreBackspace = false; + return false; + } + cursor = this._rli.cursor; + line = this._rli.line; + + debug( 'Expression: %s', line ); + debug( 'Cursor position: %d', cursor ); + + debug( 'Performing auto-delete...' ); + + ch = line[ cursor-1 ]; + debug( 'Character to delete: %s', ch ); + + debug( 'Checking if an opening symbol...' ); + ch = OPEN_SYMBOLS[ ch ]; + if ( isString( ch ) ) { + debug( 'Detected an opening symbol.' ); + + debug( 'Checking if immediately followed by a corresponding closing symbol...' ); + if ( ch !== line[ cursor ] ) { + debug( 'Opening symbol is not followed by a corresponding closing symbol. Skipping...' ); + debug( 'Finished performing auto-delete.' ); return false; } - cursor = this._rli.cursor; - line = this._rli.line; - - debug( 'Expression: %s', line ); - debug( 'Cursor position: %d', cursor ); - - debug( 'Performing auto-delete...' ); - - data = line[ cursor-1 ]; - debug( 'Character to delete: %s', data ); - - debug( 'Checking if an opening symbol...' ); - ch = OPEN_SYMBOLS[ data ]; - if ( isString( ch ) ) { - debug( 'Detected an opening symbol.' ); - - debug( 'Checking if immediately followed by a corresponding closing symbol...' ); - if ( ch !== line[ cursor ] ) { - debug( 'Opening symbol is not followed by a corresponding closing symbol. Skipping...' ); - debug( 'Finished performing auto-delete.' ); - return false; - } - debug( 'Detected a closing symbol.' ); - - debug( 'Generating an AST...' ); - ast = parse( line, AOPTS ); - - debug( 'Checking whether characters are within a string literal...' ); - node = findNodeAround( ast, cursor-1, 'Literal' ); - if ( node && node.node.start < cursor-1 ) { - debug( 'Characters are within a string literal. Skipping...' ); - debug( 'Finished performing auto-delete.' ); - return false; - } - debug( 'Characters are not within a string literal.' ); - debug( 'Found an auto-delete candidate. Deleting symbols...' ); - this._rli.write( null, { - 'name': 'right' - }); + debug( 'Detected a closing symbol.' ); - // Set an internal flag to avoid having auto-deletion logic consider this backspace to be user input: - this._ignoreBackspace = true; - this._rli.write( null, { - 'name': 'backspace' - }); - debug( 'Resulting expression: %s', this._rli.line ); + debug( 'Generating an AST...' ); + ast = parse( line, AOPTS ); + + debug( 'Checking whether characters are within a string literal...' ); + node = findNodeAround( ast, cursor-1, 'Literal' ); + if ( node && node.node.start < cursor-1 ) { + debug( 'Characters are within a string literal. Skipping...' ); debug( 'Finished performing auto-delete.' ); - return true; + return false; } - debug( 'Failed to detect an opening symbol.' ); + debug( 'Characters are not within a string literal.' ); + debug( 'Found an auto-delete candidate. Deleting symbols...' ); + this._rli.write( null, { + 'name': 'right' + }); + + // Set an internal flag to avoid having auto-deletion logic consider this backspace to be user input: + this._ignoreBackspace = true; + this._rli.write( null, { + 'name': 'backspace' + }); + debug( 'Resulting expression: %s', this._rli.line ); debug( 'Finished performing auto-delete.' ); - return false; + return true; } + debug( 'Failed to detect an opening symbol.' ); + debug( 'Finished performing auto-delete.' ); + return false; }); /** From d27f4c5f62990e8f52c148487b7bbcd23f95e46d Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sun, 31 Mar 2024 16:39:40 -0700 Subject: [PATCH 81/93] docs: document properties --- .../@stdlib/repl/test/integration/test.auto_delete_pairs.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/node_modules/@stdlib/repl/test/integration/test.auto_delete_pairs.js b/lib/node_modules/@stdlib/repl/test/integration/test.auto_delete_pairs.js index 366e529c67e..73c0858ad89 100644 --- a/lib/node_modules/@stdlib/repl/test/integration/test.auto_delete_pairs.js +++ b/lib/node_modules/@stdlib/repl/test/integration/test.auto_delete_pairs.js @@ -135,6 +135,8 @@ function moveBack( stream, N ) { * @private * @param {Object} t - test object * @param {Object} fixture - fixture object +* @param {string} fixture.expression - incomplete expression string +* @param {NonNegativeInteger} fixture.cursor - cursor position for deleting a character * @param {Function} done - callback to invoke upon completion */ function assertAutoDelete( t, fixture, done ) { @@ -207,6 +209,8 @@ function assertAutoDelete( t, fixture, done ) { * @private * @param {Object} t - test object * @param {Object} fixture - fixture object +* @param {string} fixture.expression - incomplete expression string +* @param {NonNegativeInteger} fixture.cursor - cursor position for deleting a character * @param {Function} done - callback to invoke upon completion */ function assertNoAutoDelete( t, fixture, done ) { From a70003fec907994d2849e6cf84d6cdfc46519343 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sun, 31 Mar 2024 16:41:10 -0700 Subject: [PATCH 82/93] test: add separate test generation script --- .../fixtures/auto-delete-pairs/script.js | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-delete-pairs/script.js diff --git a/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-delete-pairs/script.js b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-delete-pairs/script.js new file mode 100644 index 00000000000..2fdb45c2398 --- /dev/null +++ b/lib/node_modules/@stdlib/repl/test/integration/fixtures/auto-delete-pairs/script.js @@ -0,0 +1,63 @@ +#!/usr/bin/env node + +/** +* @license Apache-2.0 +* +* Copyright (c) 2024 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +// MODULES // + +var resolve = require( 'path' ).resolve; +var parse = require( 'acorn-loose' ).parse; +var writeFile = require( '@stdlib/fs/write-file' ).sync; + + +// VARIABLES // + +var AOPTS = { + 'ecmaVersion': 'latest' +}; +var FOPTS = { + 'encoding': 'utf8' +}; + + +// MAIN // + +/** +* Main execution sequence. +* +* @private +*/ +function main() { + var str; + var ast; + var out; + + str = '``'; + ast = parse( str, AOPTS ); + + out = { + 'expression': str, + 'cursor': 1, + 'ast': ast + }; + writeFile( resolve( __dirname, 'positive', 'left_backtick.json' ), JSON.stringify( out, null, ' ' )+'\n', FOPTS ); +} + +main(); From 0afd3b891a53e7244c3df7ba4bb86bcdf5c195e9 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sun, 31 Mar 2024 16:47:59 -0700 Subject: [PATCH 83/93] docs: update parameter type to reflect usage --- lib/node_modules/@stdlib/repl/lib/auto_close_pairs.js | 4 ++-- lib/node_modules/@stdlib/repl/lib/completer_preview.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/node_modules/@stdlib/repl/lib/auto_close_pairs.js b/lib/node_modules/@stdlib/repl/lib/auto_close_pairs.js index d4deef205b9..7165ecb3c5b 100644 --- a/lib/node_modules/@stdlib/repl/lib/auto_close_pairs.js +++ b/lib/node_modules/@stdlib/repl/lib/auto_close_pairs.js @@ -66,7 +66,7 @@ function AutoCloser( rli ) { * @name beforeKeypress * @memberof AutoCloser.prototype * @param {string} data - input data -* @param {Object} key - key object +* @param {(Object|void)} key - key object * @returns {boolean} boolean indicating whether auto-delete was successful */ setNonEnumerableReadOnly( AutoCloser.prototype, 'beforeKeypress', function beforeKeypress( data, key ) { @@ -144,7 +144,7 @@ setNonEnumerableReadOnly( AutoCloser.prototype, 'beforeKeypress', function befor * @name onKeypress * @memberof AutoCloser.prototype * @param {string} data - input data -* @param {Object} key - key object +* @param {(Object|void)} key - key object * @returns {boolean} boolean indicating whether auto-close was successful */ setNonEnumerableReadOnly( AutoCloser.prototype, 'onKeypress', function onKeypress( data ) { diff --git a/lib/node_modules/@stdlib/repl/lib/completer_preview.js b/lib/node_modules/@stdlib/repl/lib/completer_preview.js index 82735a29832..ac14a6f9d8e 100644 --- a/lib/node_modules/@stdlib/repl/lib/completer_preview.js +++ b/lib/node_modules/@stdlib/repl/lib/completer_preview.js @@ -179,7 +179,7 @@ setNonEnumerableReadOnly( PreviewCompleter.prototype, 'clear', function clear() * @name onKeypress * @memberof PreviewCompleter.prototype * @param {string} data - input data -* @param {Object} key - key object +* @param {(Object|void)} key - key object * @returns {void} */ setNonEnumerableReadOnly( PreviewCompleter.prototype, 'onKeypress', function onKeypress() { @@ -200,7 +200,7 @@ setNonEnumerableReadOnly( PreviewCompleter.prototype, 'onKeypress', function onK * @name beforeKeypress * @memberof PreviewCompleter.prototype * @param {string} data - input data -* @param {Object} key - key object +* @param {(Object|void)} key - key object * @returns {void} */ setNonEnumerableReadOnly( PreviewCompleter.prototype, 'beforeKeypress', function beforeKeypress( data, key ) { From b25fcaa52b19e747dd3eed2021c034513628b944 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sun, 31 Mar 2024 16:57:08 -0700 Subject: [PATCH 84/93] refactor: move regular expression to separate file --- .../@stdlib/repl/lib/completer.js | 6 ++- .../lib/regexp_reserved_syntax_characters.js | 42 +++++++++++++++++++ 2 files changed, 46 insertions(+), 2 deletions(-) create mode 100644 lib/node_modules/@stdlib/repl/lib/regexp_reserved_syntax_characters.js diff --git a/lib/node_modules/@stdlib/repl/lib/completer.js b/lib/node_modules/@stdlib/repl/lib/completer.js index 6d71ad4a723..acb4bf833d0 100644 --- a/lib/node_modules/@stdlib/repl/lib/completer.js +++ b/lib/node_modules/@stdlib/repl/lib/completer.js @@ -30,6 +30,7 @@ var requireRegExp = require( './regexp_require.js' ); var workspaceRegExp = require( './regexp_workspace.js' ); var tutorialRegExp = require( './regexp_tutorial.js' ); var settingsRegExp = require( './regexp_settings.js' ); +var reservedCharsRegExp = require( './regexp_reserved_syntax_characters.js' ); var completeRequire = require( './complete_require.js' ); var completeFS = require( './complete_fs.js' ); var completeWorkspace = require( './complete_workspace.js' ); @@ -41,7 +42,6 @@ var completeExpression = require( './complete_expression.js' ); // VARIABLES // var debug = logger( 'repl:completer' ); -var RE_SPECIAL_CHARS = /[`~!@#$%^&*()-=+[\]{}\\/|;:'",<>?. ]$/; // FUNCTIONS // @@ -96,6 +96,7 @@ function completer( repl ) { * @returns {void} */ function complete( line, clbk ) { + var cursor; var match; var exts; var res; @@ -181,7 +182,8 @@ function completer( repl ) { return clbk( null, [ res, line ] ); } // Sanity check that we are attempting to complete something which is completable: - if ( RE_SPECIAL_CHARS.test( line.substring( 0, repl._rli.cursor ) ) ) { + cursor = repl._rli.cursor; + if ( reservedCharsRegExp().test( line.substring( cursor-1, cursor ) ) ) { // eslint-disable-line max-len debug( 'Detected attempt to trigger completion after a special character.' ); debug( 'Results: %s', res.join( ', ' ) ); return clbk( null, [ res, line ] ); diff --git a/lib/node_modules/@stdlib/repl/lib/regexp_reserved_syntax_characters.js b/lib/node_modules/@stdlib/repl/lib/regexp_reserved_syntax_characters.js new file mode 100644 index 00000000000..dd6f2c6fcd7 --- /dev/null +++ b/lib/node_modules/@stdlib/repl/lib/regexp_reserved_syntax_characters.js @@ -0,0 +1,42 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2019 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +// MAIN // + +/** +* Returns a regular expression for matching reserved JavaScript syntax characters. +* +* @private +* @returns {RegExp} regular expression +* +* @example +* var RE_SYNTAX_CHARS = createRegExp(); +* +* var bool = RE_SYNTAX_CHARS.test( '()' ); +* // returns true +*/ +function createRegExp() { + return /[`~!@#%^&*()-=+[\]{}\\/|;:'",<>?. ]/; +} + + +// EXPORTS // + +module.exports = createRegExp; From a96053025d6b4e565f0cec25fa58beeb6270ce7d Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sun, 31 Mar 2024 17:10:17 -0700 Subject: [PATCH 85/93] refactor: access preceding character directly --- lib/node_modules/@stdlib/repl/lib/completer.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/node_modules/@stdlib/repl/lib/completer.js b/lib/node_modules/@stdlib/repl/lib/completer.js index acb4bf833d0..5871b7887ae 100644 --- a/lib/node_modules/@stdlib/repl/lib/completer.js +++ b/lib/node_modules/@stdlib/repl/lib/completer.js @@ -96,7 +96,6 @@ function completer( repl ) { * @returns {void} */ function complete( line, clbk ) { - var cursor; var match; var exts; var res; @@ -182,8 +181,7 @@ function completer( repl ) { return clbk( null, [ res, line ] ); } // Sanity check that we are attempting to complete something which is completable: - cursor = repl._rli.cursor; - if ( reservedCharsRegExp().test( line.substring( cursor-1, cursor ) ) ) { // eslint-disable-line max-len + if ( reservedCharsRegExp().test( line[ repl._rli.cursor-1 ] ) ) { debug( 'Detected attempt to trigger completion after a special character.' ); debug( 'Results: %s', res.join( ', ' ) ); return clbk( null, [ res, line ] ); From aee610cde9600ac0b9e962681f204c20befb6b94 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sun, 31 Mar 2024 17:36:08 -0700 Subject: [PATCH 86/93] refactor: replicate logic in private method --- .../@stdlib/repl/lib/auto_close_pairs.js | 79 +++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/lib/node_modules/@stdlib/repl/lib/auto_close_pairs.js b/lib/node_modules/@stdlib/repl/lib/auto_close_pairs.js index 7165ecb3c5b..58ae0278bcd 100644 --- a/lib/node_modules/@stdlib/repl/lib/auto_close_pairs.js +++ b/lib/node_modules/@stdlib/repl/lib/auto_close_pairs.js @@ -27,6 +27,7 @@ var parse = require( 'acorn-loose' ).parse; var findNodeAround = require( 'acorn-walk' ).findNodeAround; var setNonEnumerableReadOnly = require( '@stdlib/utils/define-nonenumerable-read-only-property' ); var isString = require( '@stdlib/assert/is-string' ).isPrimitive; +var reservedCharsRegExp = require( './regexp_reserved_syntax_characters.js' ); var walk = require( './auto_close_pairs_walk.js' ); var OPEN_SYMBOLS = require( './auto_close_pairs_open_symbols.js' ); var CLOSE_SYMBOLS = require( './auto_close_pairs_close_symbols.js' ); @@ -40,6 +41,20 @@ var AOPTS = { }; +// FUNCTIONS // + +/** +* Tests whether a character is a quote character. +* +* @private +* @param {string} ch - input character +* @returns {boolean} boolean indicating whether a character is a quote character +*/ +function isQuote( ch ) { + return ( ch === '\'' || ch === '"' ); +} + + // MAIN // /** @@ -60,6 +75,70 @@ function AutoCloser( rli ) { return this; } +/** +* Processes an opening symbol. +* +* @private +* @name _autocloseOpenSymbol +* @memberof AutoCloser.prototype +* @param {string} line - current line content +* @param {NonNegativeInteger} cursor - cursor position +* @param {string} data - input data +* @returns {boolean} boolean indicating whether auto-close was successful +*/ +setNonEnumerableReadOnly( AutoCloser.prototype, '_autocloseOpenSymbol', function _autocloseOpenSymbol( line, cursor, data ) { + var ast; + var out; + var ch; + + debug( 'Checking for an opening symbol...' ); + ch = OPEN_SYMBOLS[ data ]; + if ( !isString( ch ) ) { + debug( 'Failed to detect an opening symbol.' ); + return false; + } + debug( 'Detected an opening symbol.' ); + + // Avoid auto-closing when the input data is already present, and further account for `foo`` being valid syntax (i.e., using untagged template literals as tags); hence, we need to guard against unnecessarily inserting a closing symbol when a user types `foo<|>` and then instinctively types ` in order to close a template literal... + if ( data === line[ cursor ] ) { + debug( 'Closing symbol is already present. Skipping...' ); + return false; + } + // Generate an AST for the current line: + debug( 'Generating an AST...' ); + ast = parse( line, AOPTS ); + + // Attempt to walk the AST to determine whether to auto-close... + try { + debug( 'Determining whether to auto-close...' ); + out = walk( ast, cursor ); + } catch ( err ) { + // If parsing failed, stay conservative and don't auto-close: + debug( 'Error: %s', err.message ); + return false; + } + // If we failed to conclusively determine whether to auto-close, stay conservative and don't auto-close... + if ( !out ) { + debug( 'Failed to detect an auto-close candidate.' ); + return false; + } + // If the auto-close candidate is a quote character, avoid auto-closing when the opening character is inserted immediately before characters which could reasonably be considered string characters... + if ( isQuote( ch ) && line[ cursor+1 ] && !reservedCharsRegExp().test( line[ cursor+1 ] ) ) { // eslint-disable-line max-len + debug( 'Failed to detect an auto-close candidate. Detected a quote character immediately preceding potential character belonging to a string literal.' ); + return false; + } + debug( 'Successfully detected an auto-close candidate. Inserting closing symbol...' ); + this._rli.write( ch ); + + // Move back one character: + this._rli.write( null, { + 'ctrl': true, + 'name': 'b' + }); + debug( 'Resulting expression: %s', this._rli.line ); + return true; +}); + /** * Callback which should be invoked **before** a "keypress" event is processed by a readline interface. * From 5653b88823b440653ca64d04901c16df6ea09ef1 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sun, 31 Mar 2024 17:39:05 -0700 Subject: [PATCH 87/93] refactor: delegate open symbol processing to private method --- .../@stdlib/repl/lib/auto_close_pairs.js | 36 +------------------ 1 file changed, 1 insertion(+), 35 deletions(-) diff --git a/lib/node_modules/@stdlib/repl/lib/auto_close_pairs.js b/lib/node_modules/@stdlib/repl/lib/auto_close_pairs.js index 58ae0278bcd..68c1c2f7d3d 100644 --- a/lib/node_modules/@stdlib/repl/lib/auto_close_pairs.js +++ b/lib/node_modules/@stdlib/repl/lib/auto_close_pairs.js @@ -229,8 +229,6 @@ setNonEnumerableReadOnly( AutoCloser.prototype, 'beforeKeypress', function befor setNonEnumerableReadOnly( AutoCloser.prototype, 'onKeypress', function onKeypress( data ) { var cursor; var line; - var ast; - var out; var ch; cursor = this._rli.cursor; @@ -240,40 +238,8 @@ setNonEnumerableReadOnly( AutoCloser.prototype, 'onKeypress', function onKeypres debug( 'Cursor position: %d', cursor ); debug( 'Performing auto-close...' ); - debug( 'Checking for an opening symbol...' ); - ch = OPEN_SYMBOLS[ data ]; - if ( isString( ch ) ) { - debug( 'Detected an opening symbol.' ); - - // Generate an AST for the current line: - debug( 'Generating an AST...' ); - ast = parse( line, AOPTS ); - - // Attempt to walk the AST to determine whether to auto-close... - try { - debug( 'Determining whether to auto-close...' ); - out = walk( ast, cursor ); - } catch ( err ) { - // If parsing failed, stay conservative and don't auto-close: - debug( 'Error: %s', err.message ); - return false; - } - // If parsing succeeded and we should auto-close, go ahead and write the closing character... - if ( out && data !== line[ cursor ] ) { // NOTE: `data !== line[cursor]` accounts for `foo`` being valid syntax (i.e., using untagged template literals as tags); hence, we need to guard against unnecessarily inserting a closing symbol when a user types `foo<|>` and then instinctively types ` in order to close a template literal. - debug( 'Successfully detected an auto-close candidate. Inserting closing symbol...' ); - this._rli.write( ch ); + this._autocloseOpenSymbol( line, cursor, data ); - // Move back one character: - this._rli.write( null, { - 'ctrl': true, - 'name': 'b' - }); - debug( 'Resulting expression: %s', this._rli.line ); - debug( 'Finished performing auto-close.' ); - return true; - } - debug( 'Failed to detect an auto-close candidate.' ); - } debug( 'Checking for a closing symbol...' ); ch = CLOSE_SYMBOLS[ data ]; if ( isString( ch ) ) { From f7cc5c70ca6065c3697abc07b703f6b892f262c3 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sun, 31 Mar 2024 17:58:40 -0700 Subject: [PATCH 88/93] refactor: copy logic for handling a closing symbol to a private method --- .../@stdlib/repl/lib/auto_close_pairs.js | 58 +++++++++++++++++-- 1 file changed, 54 insertions(+), 4 deletions(-) diff --git a/lib/node_modules/@stdlib/repl/lib/auto_close_pairs.js b/lib/node_modules/@stdlib/repl/lib/auto_close_pairs.js index 68c1c2f7d3d..84d1bf0e870 100644 --- a/lib/node_modules/@stdlib/repl/lib/auto_close_pairs.js +++ b/lib/node_modules/@stdlib/repl/lib/auto_close_pairs.js @@ -84,7 +84,7 @@ function AutoCloser( rli ) { * @param {string} line - current line content * @param {NonNegativeInteger} cursor - cursor position * @param {string} data - input data -* @returns {boolean} boolean indicating whether auto-close was successful +* @returns {boolean} boolean indicating whether line content was updated */ setNonEnumerableReadOnly( AutoCloser.prototype, '_autocloseOpenSymbol', function _autocloseOpenSymbol( line, cursor, data ) { var ast; @@ -101,7 +101,7 @@ setNonEnumerableReadOnly( AutoCloser.prototype, '_autocloseOpenSymbol', function // Avoid auto-closing when the input data is already present, and further account for `foo`` being valid syntax (i.e., using untagged template literals as tags); hence, we need to guard against unnecessarily inserting a closing symbol when a user types `foo<|>` and then instinctively types ` in order to close a template literal... if ( data === line[ cursor ] ) { - debug( 'Closing symbol is already present. Skipping...' ); + debug( 'Failed to detect an auto-close candidate. Closing symbol is already present.' ); return false; } // Generate an AST for the current line: @@ -119,7 +119,7 @@ setNonEnumerableReadOnly( AutoCloser.prototype, '_autocloseOpenSymbol', function } // If we failed to conclusively determine whether to auto-close, stay conservative and don't auto-close... if ( !out ) { - debug( 'Failed to detect an auto-close candidate.' ); + debug( 'Failed to detect an auto-close candidate. AST parsing did not conclusively support auto-closing.' ); return false; } // If the auto-close candidate is a quote character, avoid auto-closing when the opening character is inserted immediately before characters which could reasonably be considered string characters... @@ -139,6 +139,51 @@ setNonEnumerableReadOnly( AutoCloser.prototype, '_autocloseOpenSymbol', function return true; }); +/** +* Processes a closing symbol. +* +* @private +* @name _autocloseCloseSymbol +* @memberof AutoCloser.prototype +* @param {string} line - current line content +* @param {NonNegativeInteger} cursor - cursor position +* @param {string} data - input data +* @returns {boolean} boolean indicating whether line content was updated +*/ +setNonEnumerableReadOnly( AutoCloser.prototype, '_autocloseCloseSymbol', function _autocloseCloseSymbol( line, cursor, data ) { + var ch; + + debug( 'Checking for a closing symbol...' ); + ch = CLOSE_SYMBOLS[ data ]; + if ( !isString( ch ) ) { + debug( 'Failed to detect a closing symbol.' ); + return false; + } + debug( 'Detected a closing symbol.' ); + + // Support users who may instinctively add a closing symbol by skipping over the closing symbol character, and thus avoid inserting an unwanted duplicate character... + debug( 'Determining whether a closing symbol already exists...' ); + if ( data !== line[ cursor ] ) { + // Did not detect a closing symbol to skip over... + debug( 'Did not find an existing closing symbol.' ); + return false; + } + // Set an internal flag to avoid having auto-deletion logic consider this backspace to be user input: + this._ignoreBackspace = true; + + debug( 'Closing symbol already exists. Removing duplicate symbol...' ); + this._rli.write( null, { + 'name': 'backspace' + }); + + // Move to the right one character: + this._rli.write( null, { + 'name': 'right' + }); + debug( 'Resulting expression: %s', this._rli.line ); + return true; +}); + /** * Callback which should be invoked **before** a "keypress" event is processed by a readline interface. * @@ -227,6 +272,7 @@ setNonEnumerableReadOnly( AutoCloser.prototype, 'beforeKeypress', function befor * @returns {boolean} boolean indicating whether auto-close was successful */ setNonEnumerableReadOnly( AutoCloser.prototype, 'onKeypress', function onKeypress( data ) { + var status; var cursor; var line; var ch; @@ -238,7 +284,11 @@ setNonEnumerableReadOnly( AutoCloser.prototype, 'onKeypress', function onKeypres debug( 'Cursor position: %d', cursor ); debug( 'Performing auto-close...' ); - this._autocloseOpenSymbol( line, cursor, data ); + status = this._autocloseOpenSymbol( line, cursor, data ); + if ( status ) { + debug( 'Finished performing auto-close.' ); + return true; + } debug( 'Checking for a closing symbol...' ); ch = CLOSE_SYMBOLS[ data ]; From badfc2cd0aa7abdc66d555e399acfe4d658ca17c Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sun, 31 Mar 2024 18:00:34 -0700 Subject: [PATCH 89/93] refactor: delegate to private method for handling a closing symbol --- .../@stdlib/repl/lib/auto_close_pairs.js | 32 +++---------------- 1 file changed, 4 insertions(+), 28 deletions(-) diff --git a/lib/node_modules/@stdlib/repl/lib/auto_close_pairs.js b/lib/node_modules/@stdlib/repl/lib/auto_close_pairs.js index 84d1bf0e870..6d4efb07369 100644 --- a/lib/node_modules/@stdlib/repl/lib/auto_close_pairs.js +++ b/lib/node_modules/@stdlib/repl/lib/auto_close_pairs.js @@ -275,7 +275,6 @@ setNonEnumerableReadOnly( AutoCloser.prototype, 'onKeypress', function onKeypres var status; var cursor; var line; - var ch; cursor = this._rli.cursor; line = this._rli.line; @@ -289,34 +288,11 @@ setNonEnumerableReadOnly( AutoCloser.prototype, 'onKeypress', function onKeypres debug( 'Finished performing auto-close.' ); return true; } - - debug( 'Checking for a closing symbol...' ); - ch = CLOSE_SYMBOLS[ data ]; - if ( isString( ch ) ) { - debug( 'Detected a closing symbol.' ); - - // Support users who may instinctively add a closing symbol by skipping over the closing symbol character in order to avoid inserting an unwanted duplicate character... - debug( 'Determining whether a closing symbol already exists...' ); - if ( data === line[ cursor ] ) { - // Set an internal flag to avoid having auto-deletion logic consider this backspace to be user input: - this._ignoreBackspace = true; - - debug( 'Closing symbol already exists. Skipping over existing symbol...' ); - this._rli.write( null, { - 'name': 'backspace' - }); - - // Move to the right one character: - this._rli.write( null, { - 'name': 'right' - }); - debug( 'Resulting expression: %s', this._rli.line ); - debug( 'Finished performing auto-close.' ); - return true; - } - debug( 'Did not find a closing symbol. Inserting closing symbol...' ); + status = this._autocloseCloseSymbol( line, cursor, data ); + if ( status ) { + debug( 'Finished performing auto-close.' ); + return true; } - debug( 'Failed to detect a closing symbol.' ); debug( 'Finished performing auto-close.' ); return false; }); From 840e9728cf41e1f0c9414a7dba6e0362a45e5212 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sun, 31 Mar 2024 18:08:36 -0700 Subject: [PATCH 90/93] refactor: implement handling of opening symbol during auto-deletion in private method --- .../@stdlib/repl/lib/auto_close_pairs.js | 59 ++++++++++++++++++- 1 file changed, 57 insertions(+), 2 deletions(-) diff --git a/lib/node_modules/@stdlib/repl/lib/auto_close_pairs.js b/lib/node_modules/@stdlib/repl/lib/auto_close_pairs.js index 6d4efb07369..32344b38ff0 100644 --- a/lib/node_modules/@stdlib/repl/lib/auto_close_pairs.js +++ b/lib/node_modules/@stdlib/repl/lib/auto_close_pairs.js @@ -76,7 +76,7 @@ function AutoCloser( rli ) { } /** -* Processes an opening symbol. +* Processes an opening symbol when performing auto-close. * * @private * @name _autocloseOpenSymbol @@ -140,7 +140,7 @@ setNonEnumerableReadOnly( AutoCloser.prototype, '_autocloseOpenSymbol', function }); /** -* Processes a closing symbol. +* Processes a closing symbol when performing auto-close. * * @private * @name _autocloseCloseSymbol @@ -184,6 +184,61 @@ setNonEnumerableReadOnly( AutoCloser.prototype, '_autocloseCloseSymbol', functio return true; }); +/** +* Processes an opening symbol when performing auto-delete. +* +* @private +* @name _autocloseOpenSymbol +* @memberof AutoCloser.prototype +* @param {string} line - current line content +* @param {NonNegativeInteger} cursor - cursor position +* @param {string} data - character to delete +* @returns {boolean} boolean indicating whether line content was updated +*/ +setNonEnumerableReadOnly( AutoCloser.prototype, '_autodeleteOpenSymbol', function _autodeleteOpenSymbol( line, cursor, data ) { + var node; + var ast; + var ch; + + debug( 'Checking for an opening symbol...' ); + ch = OPEN_SYMBOLS[ data ]; + if ( !isString( ch ) ) { + debug( 'Failed to detect an opening symbol.' ); + return false; + } + debug( 'Detected an opening symbol.' ); + + debug( 'Checking if immediately followed by a corresponding closing symbol...' ); + if ( ch !== line[ cursor ] ) { + debug( 'Failed to detect an auto-delete candidate. Opening symbol is not followed by a corresponding closing symbol.' ); + return false; + } + debug( 'Detected a closing symbol.' ); + + debug( 'Generating an AST...' ); + ast = parse( line, AOPTS ); + + debug( 'Checking whether characters are within a string literal...' ); + node = findNodeAround( ast, cursor-1, 'Literal' ); + if ( node && node.node.start < cursor-1 ) { + debug( 'Failed to detect an auto-delete candidate. Characters are within a string literal.' ); + return false; + } + debug( 'Characters are not within a string literal.' ); + debug( 'Successfully detected an auto-delete candidate. Deleting symbols...' ); + this._rli.write( null, { + 'name': 'right' + }); + + // Set an internal flag to avoid having auto-deletion logic consider this backspace to be user input: + this._ignoreBackspace = true; + this._rli.write( null, { + 'name': 'backspace' + }); + debug( 'Resulting expression: %s', this._rli.line ); + return true; +}); + /** * Callback which should be invoked **before** a "keypress" event is processed by a readline interface. * From 52de42cec9c3e0d7805f13d00c244fa58d6da981 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sun, 31 Mar 2024 18:14:37 -0700 Subject: [PATCH 91/93] refactor: delegate to private method --- .../@stdlib/repl/lib/auto_close_pairs.js | 54 ++++--------------- 1 file changed, 9 insertions(+), 45 deletions(-) diff --git a/lib/node_modules/@stdlib/repl/lib/auto_close_pairs.js b/lib/node_modules/@stdlib/repl/lib/auto_close_pairs.js index 32344b38ff0..a4bf667e51d 100644 --- a/lib/node_modules/@stdlib/repl/lib/auto_close_pairs.js +++ b/lib/node_modules/@stdlib/repl/lib/auto_close_pairs.js @@ -246,14 +246,12 @@ setNonEnumerableReadOnly( AutoCloser.prototype, '_autodeleteOpenSymbol', functio * @memberof AutoCloser.prototype * @param {string} data - input data * @param {(Object|void)} key - key object -* @returns {boolean} boolean indicating whether auto-delete was successful +* @returns {boolean} boolean indicating whether line content was updated */ setNonEnumerableReadOnly( AutoCloser.prototype, 'beforeKeypress', function beforeKeypress( data, key ) { + var status; var cursor; var line; - var node; - var ast; - var ch; if ( !key || key.name !== 'backspace' ) { return false; @@ -269,50 +267,15 @@ setNonEnumerableReadOnly( AutoCloser.prototype, 'beforeKeypress', function befor debug( 'Expression: %s', line ); debug( 'Cursor position: %d', cursor ); - debug( 'Performing auto-delete...' ); + data = line[ cursor-1 ]; + debug( 'Character to delete: %s', data ); - ch = line[ cursor-1 ]; - debug( 'Character to delete: %s', ch ); - - debug( 'Checking if an opening symbol...' ); - ch = OPEN_SYMBOLS[ ch ]; - if ( isString( ch ) ) { - debug( 'Detected an opening symbol.' ); - - debug( 'Checking if immediately followed by a corresponding closing symbol...' ); - if ( ch !== line[ cursor ] ) { - debug( 'Opening symbol is not followed by a corresponding closing symbol. Skipping...' ); - debug( 'Finished performing auto-delete.' ); - return false; - } - debug( 'Detected a closing symbol.' ); - - debug( 'Generating an AST...' ); - ast = parse( line, AOPTS ); - - debug( 'Checking whether characters are within a string literal...' ); - node = findNodeAround( ast, cursor-1, 'Literal' ); - if ( node && node.node.start < cursor-1 ) { - debug( 'Characters are within a string literal. Skipping...' ); - debug( 'Finished performing auto-delete.' ); - return false; - } - debug( 'Characters are not within a string literal.' ); - debug( 'Found an auto-delete candidate. Deleting symbols...' ); - this._rli.write( null, { - 'name': 'right' - }); - - // Set an internal flag to avoid having auto-deletion logic consider this backspace to be user input: - this._ignoreBackspace = true; - this._rli.write( null, { - 'name': 'backspace' - }); - debug( 'Resulting expression: %s', this._rli.line ); + debug( 'Performing auto-delete...' ); + status = this._autodeleteOpenSymbol( line, cursor, data ); + if ( status ) { debug( 'Finished performing auto-delete.' ); return true; } - debug( 'Failed to detect an opening symbol.' ); debug( 'Finished performing auto-delete.' ); return false; }); @@ -324,7 +287,7 @@ setNonEnumerableReadOnly( AutoCloser.prototype, 'beforeKeypress', function befor * @memberof AutoCloser.prototype * @param {string} data - input data * @param {(Object|void)} key - key object -* @returns {boolean} boolean indicating whether auto-close was successful +* @returns {boolean} boolean indicating whether line content was updated */ setNonEnumerableReadOnly( AutoCloser.prototype, 'onKeypress', function onKeypress( data ) { var status; @@ -336,6 +299,7 @@ setNonEnumerableReadOnly( AutoCloser.prototype, 'onKeypress', function onKeypres debug( 'Expression: %s', line ); debug( 'Cursor position: %d', cursor ); + debug( 'Character to insert: %s', data ); debug( 'Performing auto-close...' ); status = this._autocloseOpenSymbol( line, cursor, data ); From 03b1fd0e33dedfb1149b08915251c608db0cfc7a Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sun, 31 Mar 2024 18:21:18 -0700 Subject: [PATCH 92/93] docs: update param type --- lib/node_modules/@stdlib/repl/lib/main.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/node_modules/@stdlib/repl/lib/main.js b/lib/node_modules/@stdlib/repl/lib/main.js index bb0819c3973..a9af0d4dc0c 100644 --- a/lib/node_modules/@stdlib/repl/lib/main.js +++ b/lib/node_modules/@stdlib/repl/lib/main.js @@ -298,7 +298,7 @@ function REPL( options ) { * * @private * @param {string} data - input data - * @param {Object} key - key object + * @param {(Object|void)} key - key object */ function beforeKeypress( data, key ) { var settings = self._settings; @@ -316,7 +316,7 @@ function REPL( options ) { * * @private * @param {string} data - input data - * @param {Object} key - key object + * @param {(Object|void)} key - key object * @returns {void} */ function onKeypress( data, key ) { From 24bb5cc448eea8ecfebf487610d85fd388ed2b2a Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sun, 31 Mar 2024 18:22:58 -0700 Subject: [PATCH 93/93] docs: fix copyright year --- .../@stdlib/repl/lib/regexp_reserved_syntax_characters.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/node_modules/@stdlib/repl/lib/regexp_reserved_syntax_characters.js b/lib/node_modules/@stdlib/repl/lib/regexp_reserved_syntax_characters.js index dd6f2c6fcd7..90c75e3c0a7 100644 --- a/lib/node_modules/@stdlib/repl/lib/regexp_reserved_syntax_characters.js +++ b/lib/node_modules/@stdlib/repl/lib/regexp_reserved_syntax_characters.js @@ -1,7 +1,7 @@ /** * @license Apache-2.0 * -* Copyright (c) 2019 The Stdlib Authors. +* Copyright (c) 2024 The Stdlib Authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License.