diff --git a/packages/cli-repl/src/arg-parser.ts b/packages/cli-repl/src/arg-parser.ts index 604908d970..172676ed95 100644 --- a/packages/cli-repl/src/arg-parser.ts +++ b/packages/cli-repl/src/arg-parser.ts @@ -2,7 +2,7 @@ import { CliOptions } from '@mongosh/service-provider-server'; import { USAGE } from './constants'; import i18n from '@mongosh/i18n'; import minimist from 'minimist'; -import clr from './clr'; +import { colorizeForStderr as clr } from './clr'; /** * Unknown translation key. diff --git a/packages/cli-repl/src/cli-repl.ts b/packages/cli-repl/src/cli-repl.ts index 440bfd047d..324c3764ab 100644 --- a/packages/cli-repl/src/cli-repl.ts +++ b/packages/cli-repl/src/cli-repl.ts @@ -97,7 +97,7 @@ class CliRepl { */ async connect(driverUri: string, driverOptions: NodeOptions): Promise { if (!this.options.nodb) { - console.log(i18n.__(CONNECTING), ' ', clr(retractPassword(driverUri), ['bold', 'green'])); + console.log(i18n.__(CONNECTING), ' ', this.clr(retractPassword(driverUri), ['bold', 'green'])); } return await CliServiceProvider.connect(driverUri, driverOptions, this.options); } @@ -116,9 +116,9 @@ class CliRepl { prompt: '> ', writer: this.writer, completer: completer.bind(null, version), - terminal: true, breakEvalOnSigint: true, preview: false, + terminal: process.env.MONGOSH_FORCE_TERMINAL ? true : undefined }); const originalDisplayPrompt = this.repl.displayPrompt.bind(this.repl); @@ -128,12 +128,14 @@ class CliRepl { this.lineByLineInput.nextLine(); }; - const originalEditorAction = this.repl.commands.editor.action.bind(this.repl); + if (this.repl.commands.editor) { + const originalEditorAction = this.repl.commands.editor.action.bind(this.repl); - this.repl.commands.editor.action = (): any => { - this.lineByLineInput.disableBlockOnNewline(); - return originalEditorAction(); - }; + this.repl.commands.editor.action = (): any => { + this.lineByLineInput.disableBlockOnNewline(); + return originalEditorAction(); + }; + } this.repl.defineCommand('clear', { help: '', @@ -355,10 +357,10 @@ class CliRepl { stack: result.stack }; this.bus.emit('mongosh:error', output); - return formatOutput({ type: 'Error', value: output }); + return this.formatOutput({ type: 'Error', value: output }); } - return formatOutput({ type: result.type, value: result.printable }); + return this.formatOutput({ type: result.type, value: result.printable }); }; verifyNodeVersion(): void { @@ -377,7 +379,7 @@ class CliRepl { greet(): void { const { version } = require('../package.json'); console.log(`Using MongoDB: ${this.internalState.connectionInfo.buildInfo.version}`); - console.log(`${clr('Using Mongosh Beta', ['bold', 'yellow'])}: ${version}`); + console.log(`${this.clr('Using Mongosh Beta', ['bold', 'yellow'])}: ${version}`); console.log(`${MONGOSH_WIKI}`); if (!this.disableGreetingMessage) console.log(TELEMETRY); } @@ -410,7 +412,7 @@ class CliRepl { read(readOptions, (error, password) => { if (error) { this.bus.emit('mongosh:error', error); - return console.log(formatError(error)); + return console.log(this.formatError(error)); } driverOptions.auth.password = password; @@ -465,7 +467,7 @@ class CliRepl { this.bus.emit('mongosh:error', error); } - console.error(formatError(error)); + console.error(this.formatError(error)); return process.exit(1); } @@ -475,6 +477,25 @@ class CliRepl { // https://github.com/DefinitelyTyped/DefinitelyTyped/pull/48646 (this.repl as any).output.write(joined + '\n'); } + + formatOutput(value: any): string { + return formatOutput(value, this.getFormatOptions()); + } + + formatError(value: any): string { + return formatError(value, this.getFormatOptions()); + } + + clr(text: string, style: string|string[]): string { + return clr(text, style, this.getFormatOptions()); + } + + getFormatOptions(): { colors: boolean } { + return { + colors: this.repl ? this.repl.useColors : + process.stdout.isTTY && process.stdout.getColorDepth() > 1 + }; + } } export default CliRepl; diff --git a/packages/cli-repl/src/clr.ts b/packages/cli-repl/src/clr.ts index 7ec0203e1b..d5ed592990 100644 --- a/packages/cli-repl/src/clr.ts +++ b/packages/cli-repl/src/clr.ts @@ -1,5 +1,18 @@ import ansi from 'ansi-escape-sequences'; -export default function clr(text: string, style: any): string { - return process.stdout.isTTY ? ansi.format(text, style) : text; +export default function colorize(text: string, style: string|string[], options: { colors: boolean }): string { + if (options.colors) { + return ansi.format(text, style); + } + return text; +} + +export function colorizeForStdout(text: string, style: string|string[]): string { + return colorize(text, style, { + colors: process.stdout.isTTY && process.stdout.getColorDepth() > 1 }); +} + +export function colorizeForStderr(text: string, style: string|string[]): string { + return colorize(text, style, { + colors: process.stderr.isTTY && process.stderr.getColorDepth() > 1 }); } diff --git a/packages/cli-repl/src/constants.ts b/packages/cli-repl/src/constants.ts index 8b5e576d6f..1b25ef4c62 100644 --- a/packages/cli-repl/src/constants.ts +++ b/packages/cli-repl/src/constants.ts @@ -1,5 +1,5 @@ import i18n from '@mongosh/i18n'; -import clr from './clr'; +import { colorizeForStderr as clr } from './clr'; export const TELEMETRY = ` ${i18n.__('cli-repl.cli-repl.telemetry')} diff --git a/packages/cli-repl/src/format-output.spec.ts b/packages/cli-repl/src/format-output.spec.ts index db20b0a76c..8ce49e12eb 100644 --- a/packages/cli-repl/src/format-output.spec.ts +++ b/packages/cli-repl/src/format-output.spec.ts @@ -1,268 +1,270 @@ /* eslint no-control-regex: 0 */ -import format from './format-output'; +import formatRaw from './format-output'; import { expect } from 'chai'; -function stripAnsiColors(str): string { - return str.replace(/\x1B[[(?);]{0,2}(;?\d)*./g, ''); -} +for (const colors of [ false, true ]) { + describe(`formatOutput with 'colors' set to ${colors}`, () => { + const format = (value: any): string => formatRaw(value, { colors }); + const stripAnsiColors = colors ? + (str: string): string => str.replace(/\x1B[[(?);]{0,2}(;?\d)*./g, '') : + (str: string): string => str; -describe('formatOutput', () => { - context('when the result is a string', () => { - it('returns the output', () => { - expect(format({ value: 'test' })).to.equal('test'); + context('when the result is a string', () => { + it('returns the output', () => { + expect(format({ value: 'test' })).to.equal('test'); + }); }); - }); - context('when the result is undefined', () => { - it('returns the output', () => { - expect(format({ value: undefined })).to.equal(''); + context('when the result is undefined', () => { + it('returns the output', () => { + expect(format({ value: undefined })).to.equal(''); + }); }); - }); - context('when the result is an object', () => { - it('returns the inspection', () => { - expect(format({ value: 2 })).to.include('2'); + context('when the result is an object', () => { + it('returns the inspection', () => { + expect(format({ value: 2 })).to.include('2'); + }); }); - }); - context('when the result is a Cursor', () => { - context('when the Cursor is not empty', () => { - it('returns the inspection', () => { - const output = stripAnsiColors(format({ - value: [{ doc: 1 }, { doc: 2 }], - type: 'Cursor' - })); + context('when the result is a Cursor', () => { + context('when the Cursor is not empty', () => { + it('returns the inspection', () => { + const output = stripAnsiColors(format({ + value: [{ doc: 1 }, { doc: 2 }], + type: 'Cursor' + })); + + expect(output).to.include('doc: 1'); + expect(output).to.include('doc: 2'); + }); + }); + + context('when the Cursor is empty', () => { + it('returns an empty string', () => { + const output = stripAnsiColors(format({ + value: [], + type: 'Cursor' + })); - expect(output).to.include('doc: 1'); - expect(output).to.include('doc: 2'); + expect(output).to.equal(''); + }); }); }); - context('when the Cursor is empty', () => { - it('returns an empty string', () => { - const output = stripAnsiColors(format({ - value: [], - type: 'Cursor' - })); + context('when the result is a CursorIterationResult', () => { + context('when the CursorIterationResult is not empty', () => { + it('returns the inspection', () => { + const output = stripAnsiColors(format({ + value: [{ doc: 1 }, { doc: 2 }], + type: 'CursorIterationResult' + })); + + expect(output).to.include('doc: 1'); + expect(output).to.include('doc: 2'); + }); + }); + + context('when the CursorIterationResult is empty', () => { + it('returns "no cursor"', () => { + const output = stripAnsiColors(format({ + value: [], + type: 'CursorIterationResult' + })); - expect(output).to.equal(''); + expect(output).to.equal('no cursor'); + }); }); }); - }); - - context('when the result is a CursorIterationResult', () => { - context('when the CursorIterationResult is not empty', () => { - it('returns the inspection', () => { + context('when the result is an Error', () => { + it('returns only name and message', () => { const output = stripAnsiColors(format({ - value: [{ doc: 1 }, { doc: 2 }], - type: 'CursorIterationResult' + value: new Error('Something went wrong.'), + type: 'Error' })); - expect(output).to.include('doc: 1'); - expect(output).to.include('doc: 2'); + expect(output).to.equal('\rError: Something went wrong.'); }); }); - context('when the CursorIterationResult is empty', () => { - it('returns "no cursor"', () => { + context('when the result is ShowDatabasesResult', () => { + it('returns the help text', () => { const output = stripAnsiColors(format({ - value: [], - type: 'CursorIterationResult' + value: [ + { name: 'admin', sizeOnDisk: 45056, empty: false }, + { name: 'dxl', sizeOnDisk: 8192, empty: false }, + { name: 'supplies', sizeOnDisk: 2236416, empty: false }, + { name: 'test', sizeOnDisk: 5664768, empty: false }, + { name: 'test', sizeOnDisk: 599999768000, empty: false } + ], + type: 'ShowDatabasesResult' })); - expect(output).to.equal('no cursor'); + expect(output).to.contain('admin 45.1 kB\ndxl 8.19 kB\nsupplies 2.24 MB\ntest 5.66 MB\ntest 600 GB'); }); }); - }); - context('when the result is an Error', () => { - it('returns only name and message', () => { - const output = stripAnsiColors(format({ - value: new Error('Something went wrong.'), - type: 'Error' - })); - - expect(output).to.equal('\rError: Something went wrong.'); - }); - }); - - context('when the result is ShowDatabasesResult', () => { - it('returns the help text', () => { - const output = stripAnsiColors(format({ - value: [ - { name: 'admin', sizeOnDisk: 45056, empty: false }, - { name: 'dxl', sizeOnDisk: 8192, empty: false }, - { name: 'supplies', sizeOnDisk: 2236416, empty: false }, - { name: 'test', sizeOnDisk: 5664768, empty: false }, - { name: 'test', sizeOnDisk: 599999768000, empty: false } - ], - type: 'ShowDatabasesResult' - })); - - expect(output).to.contain('admin 45.1 kB\ndxl 8.19 kB\nsupplies 2.24 MB\ntest 5.66 MB\ntest 600 GB'); - }); - }); - context('when the result is ShowCollectionsResult', () => { - it('returns the help text', () => { - const output = stripAnsiColors(format({ - value: [ - 'nested_documents', 'decimal128', 'coll', 'people_imported', 'cats' - ], - type: 'ShowCollectionsResult' - })); + context('when the result is ShowCollectionsResult', () => { + it('returns the help text', () => { + const output = stripAnsiColors(format({ + value: [ + 'nested_documents', 'decimal128', 'coll', 'people_imported', 'cats' + ], + type: 'ShowCollectionsResult' + })); - expect(output).to.contain('nested_documents\ndecimal128\ncoll\npeople_imported\ncats'); + expect(output).to.contain('nested_documents\ndecimal128\ncoll\npeople_imported\ncats'); + }); }); - }); - context('when the result is StatsResult', () => { - it('returns the --- separated list', () => { - const output = stripAnsiColors(format({ - value: { - c1: { metadata: 1 }, - c2: { metadata: 2 } - }, - type: 'StatsResult' - })); + context('when the result is StatsResult', () => { + it('returns the --- separated list', () => { + const output = stripAnsiColors(format({ + value: { + c1: { metadata: 1 }, + c2: { metadata: 2 } + }, + type: 'StatsResult' + })); - expect(output).to.contain('c1\n{ metadata: 1 }\n---\nc2\n{ metadata: 2 }'); + expect(output).to.contain('c1\n{ metadata: 1 }\n---\nc2\n{ metadata: 2 }'); + }); }); - }); - context('when the result is ListCommandsResult', () => { - it('returns the formatted list', () => { - const output = stripAnsiColors(format({ - value: { - c1: { metadata1: 1, help: 'help1' }, - c2: { metadata2: 2, help: 'help2' } - }, - type: 'ListCommandsResult' - })); + context('when the result is ListCommandsResult', () => { + it('returns the formatted list', () => { + const output = stripAnsiColors(format({ + value: { + c1: { metadata1: 1, help: 'help1' }, + c2: { metadata2: 2, help: 'help2' } + }, + type: 'ListCommandsResult' + })); - expect(output).to.contain('c1: metadata1\nhelp1\n\nc2: metadata2\nhelp2'); + expect(output).to.contain('c1: metadata1\nhelp1\n\nc2: metadata2\nhelp2'); + }); }); - }); - context('when the result is a ShowProfileResult', () => { - it('returns the warning if empty', () => { - const output = stripAnsiColors(format({ - value: { - count: 0 - }, - type: 'ShowProfileResult' - })); + context('when the result is a ShowProfileResult', () => { + it('returns the warning if empty', () => { + const output = stripAnsiColors(format({ + value: { + count: 0 + }, + type: 'ShowProfileResult' + })); - expect(output).to.contain('db.system.profile is empty'); - }); - it('returns the formatted list if not empty', () => { - const output = stripAnsiColors(format({ - value: { - count: 2, - result: [ - { - op: 'command', - ns: 'test.system.profile', - command: { - aggregate: 'system.profile', - pipeline: [ - { '$match': {} }, - { '$group': { _id: 1, n: { '$sum': 1 } } } - ], - cursor: {}, - lsid: { id: 'bin' }, - '$db': 'test' - }, - keysExamined: 0, - docsExamined: 6, - cursorExhausted: true, - numYield: 0, - nreturned: 1, - locks: { - ReplicationStateTransition: { acquireCount: { w: 2 } }, - Global: { acquireCount: { r: 2 } }, - Database: { acquireCount: { r: 2 } }, - Collection: { acquireCount: { r: 2 } }, - Mutex: { acquireCount: { r: 2 } } - }, - flowControl: {}, - responseLength: 132, - protocol: 'op_msg', - millis: 1, - planSummary: 'COLLSCAN', - ts: 'ts', - client: '127.0.0.1', - appName: 'mongosh 0.2.2', - allUsers: [], - user: '' - } - ] - }, - type: 'ShowProfileResult' - })); - expect(output).to.contain('command\ttest.system.profile 1ms ts'); - expect(output).to.contain('aggregate: \'system.profile\','); + expect(output).to.contain('db.system.profile is empty'); + }); + it('returns the formatted list if not empty', () => { + const output = stripAnsiColors(format({ + value: { + count: 2, + result: [ + { + op: 'command', + ns: 'test.system.profile', + command: { + aggregate: 'system.profile', + pipeline: [ + { '$match': {} }, + { '$group': { _id: 1, n: { '$sum': 1 } } } + ], + cursor: {}, + lsid: { id: 'bin' }, + '$db': 'test' + }, + keysExamined: 0, + docsExamined: 6, + cursorExhausted: true, + numYield: 0, + nreturned: 1, + locks: { + ReplicationStateTransition: { acquireCount: { w: 2 } }, + Global: { acquireCount: { r: 2 } }, + Database: { acquireCount: { r: 2 } }, + Collection: { acquireCount: { r: 2 } }, + Mutex: { acquireCount: { r: 2 } } + }, + flowControl: {}, + responseLength: 132, + protocol: 'op_msg', + millis: 1, + planSummary: 'COLLSCAN', + ts: 'ts', + client: '127.0.0.1', + appName: 'mongosh 0.2.2', + allUsers: [], + user: '' + } + ] + }, + type: 'ShowProfileResult' + })); + expect(output).to.contain('command\ttest.system.profile 1ms ts'); + expect(output).to.contain('aggregate: \'system.profile\','); + }); }); - }); - context('when the result is Help', () => { - it('returns help text', () => { - const output = stripAnsiColors(format({ - value: { - help: 'Shell API' - }, - type: 'Help' - })); + context('when the result is Help', () => { + it('returns help text', () => { + const output = stripAnsiColors(format({ + value: { + help: 'Shell API' + }, + type: 'Help' + })); - expect(output).to.contain('Shell API'); - }); + expect(output).to.contain('Shell API'); + }); - it('returns help text, docs, name and description', () => { - const output = stripAnsiColors(format({ - value: { - help: 'Shell API', - docs: 'https://docs.mongodb.com', - attr: [{ - name: 'show dbs', - description: 'list available databases' - }] - }, - type: 'Help' - })); + it('returns help text, docs, name and description', () => { + const output = stripAnsiColors(format({ + value: { + help: 'Shell API', + docs: 'https://docs.mongodb.com', + attr: [{ + name: 'show dbs', + description: 'list available databases' + }] + }, + type: 'Help' + })); - expect(output).to.contain('list available databases'); - }); + expect(output).to.contain('list available databases'); + }); - it('does not show name, if none is defined', () => { - const output = stripAnsiColors(format({ - value: { - help: 'Shell API', - docs: 'https://docs.mongodb.com', - attr: [{ - description: 'list available databases' - }] - }, - type: 'Help' - })); + it('does not show name, if none is defined', () => { + const output = stripAnsiColors(format({ + value: { + help: 'Shell API', + docs: 'https://docs.mongodb.com', + attr: [{ + description: 'list available databases' + }] + }, + type: 'Help' + })); - expect(output).to.not.contain('show dbs'); - expect(output).to.contain('list available databases'); - }); + expect(output).to.not.contain('show dbs'); + expect(output).to.contain('list available databases'); + }); - it('does not show docs, if none are defined', () => { - const output = stripAnsiColors(format({ - value: { - help: 'Shell API', - attr: [{ - name: 'show dbs', - description: 'list available databases' - }] - }, - type: 'Help' - })); + it('does not show docs, if none are defined', () => { + const output = stripAnsiColors(format({ + value: { + help: 'Shell API', + attr: [{ + name: 'show dbs', + description: 'list available databases' + }] + }, + type: 'Help' + })); - expect(output).to.not.contain('https://docs.mongodb.com'); - expect(output).to.contain('list available databases'); + expect(output).to.not.contain('https://docs.mongodb.com'); + expect(output).to.contain('list available databases'); + }); }); }); -}); - +} diff --git a/packages/cli-repl/src/format-output.ts b/packages/cli-repl/src/format-output.ts index 1f507a03bd..72580ecb8f 100644 --- a/packages/cli-repl/src/format-output.ts +++ b/packages/cli-repl/src/format-output.ts @@ -11,6 +11,10 @@ type EvaluationResult = { type?: string; }; +type FormatOptions = { + colors: boolean; +}; + /** * Return the pretty string for the output. * @@ -22,42 +26,42 @@ type EvaluationResult = { * * @returns {string} The output. */ -export default function formatOutput(evaluationResult: EvaluationResult): string { +export default function formatOutput(evaluationResult: EvaluationResult, options: FormatOptions): string { const { value, type } = evaluationResult; if (type === 'Cursor') { - return formatCursor(value); + return formatCursor(value, options); } if (type === 'CursorIterationResult') { - return formatCursorIterationResult(value); + return formatCursorIterationResult(value, options); } if (type === 'Help') { - return formatHelp(value); + return formatHelp(value, options); } if (type === 'ShowDatabasesResult') { - return formatDatabases(value); + return formatDatabases(value, options); } if (type === 'ShowCollectionsResult') { - return formatCollections(value); + return formatCollections(value, options); } if (type === 'StatsResult') { - return formatStats(value); + return formatStats(value, options); } if (type === 'ListCommandsResult') { - return formatListCommands(value); + return formatListCommands(value, options); } if (type === 'ShowProfileResult') { if (value.count === 0) { return clr(`db.system.profile is empty. Use db.setProfilingLevel(2) will enable profiling. -Use db.getCollection('system.profile').find() to show raw profile entries.`, 'yellow'); +Use db.getCollection('system.profile').find() to show raw profile entries.`, 'yellow', options); } // direct from old shell return value.result.map(function(x) { @@ -72,7 +76,7 @@ Use db.getCollection('system.profile').find() to show raw profile entries.`, 'ye const mytype = typeof (val); if (mytype === 'object') { - l += z + ':' + formatSimpleType(val) + ' '; + l += z + ':' + formatSimpleType(val, options) + ' '; } else if (mytype === 'boolean') { l += z + ' '; } else { @@ -84,57 +88,58 @@ Use db.getCollection('system.profile').find() to show raw profile entries.`, 'ye } if (type === 'Error') { - return formatError(value); + return formatError(value, options); } - return formatSimpleType(value); + return formatSimpleType(value, options); } -function formatSimpleType(output): any { +function formatSimpleType(output, options: FormatOptions): any { if (typeof output === 'string') return output; if (typeof output === 'undefined') return ''; - return inspect(output); + return inspect(output, options); } -function formatCollections(output): string { - return clr(output.join('\n'), 'bold'); +function formatCollections(output, options: FormatOptions): string { + return clr(output.join('\n'), 'bold', options); } -function formatDatabases(output): string { +function formatDatabases(output, options: FormatOptions): string { const tableEntries = output.map( - (db) => [clr(db.name, 'bold'), prettyBytes(db.sizeOnDisk)] + (db) => [clr(db.name, 'bold', options), prettyBytes(db.sizeOnDisk)] ); return textTable(tableEntries, { align: ['l', 'r'] }); } -function formatStats(output): string { +function formatStats(output, options: FormatOptions): string { return Object.keys(output).map((c) => { - return `${clr(c, ['bold', 'yellow'])}\n${inspect(output[c])}`; + return `${clr(c, ['bold', 'yellow'], options)}\n` + + `${inspect(output[c], options)}`; }).join('\n---\n'); } -function formatListCommands(output): string { +function formatListCommands(output, options: FormatOptions): string { const tableEntries = Object.keys(output).map( (cmd) => { const val = output[cmd]; let result = Object.keys(val).filter(k => k !== 'help').reduce((str, k) => { if (val[k]) { - return `${str} ${clr(k, ['bold', 'white'])}`; + return `${str} ${clr(k, ['bold', 'white'], options)}`; } return str; - }, `${clr(cmd, ['bold', 'yellow'])}: `); - result += val.help ? `\n${clr(val.help, 'green')}` : ''; + }, `${clr(cmd, ['bold', 'yellow'], options)}: `); + result += val.help ? `\n${clr(val.help, 'green', options)}` : ''; return result; } ); return tableEntries.join('\n\n'); } -export function formatError(error): string { +export function formatError(error, options: FormatOptions): string { let result = ''; - if (error.name) result += `\r${clr(error.name, ['bold', 'red'])}: `; + if (error.name) result += `\r${clr(error.name, ['bold', 'red'], options)}: `; if (error.message) result += error.message; // leave a bit of breathing room after the syntax error message output if (error.name === 'SyntaxError') result += '\n\n'; @@ -142,38 +147,38 @@ export function formatError(error): string { return result; } -function inspect(output): any { +function inspect(output, options: FormatOptions): any { return util.inspect(output, { showProxy: false, - colors: true, + colors: options.colors ?? true, depth: 6 }); } -function formatCursor(value): any { +function formatCursor(value, options: FormatOptions): any { if (!value.length) { return ''; } - return inspect(value); + return inspect(value, options); } -function formatCursorIterationResult(value): any { +function formatCursorIterationResult(value, options: FormatOptions): any { if (!value.length) { return i18n.__('shell-api.classes.Cursor.iteration.no-cursor'); } - return inspect(value); + return inspect(value, options); } -function formatHelp(value): string { +function formatHelp(value, options: FormatOptions): string { // This is the spacing between arguments and description in mongosh --help. // Use this length for formatting consistency. const argLen = 47; let helpMenu = ''; if (value.help) { - helpMenu += `\n ${clr(`${value.help}:`, ['yellow', 'bold'])}\n\n`; + helpMenu += `\n ${clr(`${value.help}:`, ['yellow', 'bold'], options)}\n\n`; } (value.attr || []).forEach((method) => { @@ -193,7 +198,8 @@ function formatHelp(value): string { }); if (value.docs) { - helpMenu += `\n ${clr(i18n.__('cli-repl.args.moreInformation'), 'bold')} ${clr(value.docs, ['green', 'bold'])}`; + helpMenu += `\n ${clr(i18n.__('cli-repl.args.moreInformation'), 'bold', options)} ` + + `${clr(value.docs, ['green', 'bold'], options)}`; } return helpMenu; diff --git a/packages/cli-repl/test/test-shell.ts b/packages/cli-repl/test/test-shell.ts index 0d324d47bd..c63488c16c 100644 --- a/packages/cli-repl/test/test-shell.ts +++ b/packages/cli-repl/test/test-shell.ts @@ -28,10 +28,11 @@ export class TestShell { let env = options.env || process.env; + // TODO: Test (some) cases also without MONGOSH_FORCE_TERMINAL. if (process.env.MONGOSH_TEST_EXECUTABLE_PATH) { shellProcess = spawn(process.env.MONGOSH_TEST_EXECUTABLE_PATH, [...options.args], { stdio: [ 'pipe', 'pipe', 'pipe' ], - env + env: { ...env, MONGOSH_FORCE_TERMINAL: '1' } }); } else { if (options.removeSigintListeners) { @@ -46,7 +47,7 @@ export class TestShell { shellProcess = spawn('node', [path.resolve(__dirname, '..', 'bin', 'mongosh.js'), ...options.args], { stdio: [ 'pipe', 'pipe', 'pipe' ], - env + env: { ...env, MONGOSH_FORCE_TERMINAL: '1' } }); }