diff --git a/lib/utils/format-search-stream.js b/lib/utils/format-search-stream.js index fd5f6c2385cc3..021c5bd04638a 100644 --- a/lib/utils/format-search-stream.js +++ b/lib/utils/format-search-stream.js @@ -105,7 +105,7 @@ class TextOutputStream extends Minipass { description: strip(data.description ?? ''), keywords: [], name: strip(data.name), - version: data.version, + version: strip(data.version ?? ''), } if (Array.isArray(data.keywords)) { pkg.keywords = data.keywords.map(strip) diff --git a/test/lib/commands/search.js b/test/lib/commands/search.js index 97adffd8e1432..25089f598d932 100644 --- a/test/lib/commands/search.js +++ b/test/lib/commands/search.js @@ -190,6 +190,34 @@ t.test('search', t => { t.matchSnapshot(joinedOutput(), 'should have filtered expected search results') }) + t.test('strips control characters from version', async t => { + const { npm, joinedOutput } = await loadMockNpm(t) + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + }) + + const esc = String.fromCharCode(27) + registry.search({ results: [{ + name: 'foo', + scope: 'unscoped', + version: `1.0.0${esc}[31mnot-really`, + description: '', + keywords: [], + date: null, + author: { name: 'Foo', email: 'foo@npmjs.com' }, + publisher: { username: 'foo', email: 'foo@npmjs.com' }, + maintainers: [ + { username: 'foo', email: 'foo@npmjs.com' }, + ], + }] }) + + await npm.exec('search', ['foo']) + + t.notMatch(joinedOutput(), esc, 'no escape sequence reaches the terminal') + t.match(joinedOutput(), '1.0.0not-really', 'version text is preserved') + }) + t.test('empty search results', async t => { const { npm, joinedOutput } = await loadMockNpm(t) const registry = new MockRegistry({