From 06e91a86f71169e59c4e960b66eb4daa9700b31a Mon Sep 17 00:00:00 2001 From: Gar Date: Wed, 22 Jun 2022 07:58:52 -0700 Subject: [PATCH] fix: --include-workspace-root --- lib/commands/query.js | 57 ++++++++++--------- .../test/lib/commands/query.js.test.cjs | 34 +++++++++++ test/lib/commands/query.js | 37 ++++++++++++ 3 files changed, 102 insertions(+), 26 deletions(-) diff --git a/lib/commands/query.js b/lib/commands/query.js index 60ba8a0148e38..6e72b49dfb58a 100644 --- a/lib/commands/query.js +++ b/lib/commands/query.js @@ -6,6 +6,7 @@ const BaseCommand = require('../base-command.js') class QuerySelectorItem { constructor (node) { + // all enumerable properties from the target Object.assign(this, node.target.package) // append extra info @@ -19,21 +20,10 @@ class QuerySelectorItem { } } -// retrieves a normalized inventory -const convertInventoryItemsToResponses = inventory => { - const responses = [] - const responsesSeen = new Set() - for (const node of inventory) { - if (!responsesSeen.has(node.target.realpath)) { - const item = new QuerySelectorItem(node) - responses.push(item) - responsesSeen.add(item.path) - } - } - return responses -} - class Query extends BaseCommand { + #response = [] // response is the query response + #seen = new Set() // paths we've seen so we can keep response deduped + static description = 'Retrieve a filtered list of packages' static name = 'query' static usage = [''] @@ -47,7 +37,11 @@ class Query extends BaseCommand { 'include-workspace-root', ] - async exec (args, workspaces) { + get parsedResponse () { + return JSON.stringify(this.#response, null, 2) + } + + async exec (args) { // one dir up from wherever node_modules lives const where = resolve(this.npm.dir, '..') const opts = { @@ -57,14 +51,13 @@ class Query extends BaseCommand { const arb = new Arborist(opts) const tree = await arb.loadActual(opts) const items = await tree.querySelectorAll(args[0]) - const res = convertInventoryItemsToResponses(items) + this.buildResponse(items) - this.npm.output(JSON.stringify(res, null, 2)) + this.npm.output(this.parsedResponse) } async execWorkspaces (args, filters) { await this.setWorkspaces(filters) - const result = new Set() const opts = { ...this.npm.flatOptions, path: this.npm.prefix, @@ -72,16 +65,28 @@ class Query extends BaseCommand { const arb = new Arborist(opts) const tree = await arb.loadActual(opts) for (const workspacePath of this.workspacePaths) { - const [workspace] = await tree.querySelectorAll(`.workspace:path(${workspacePath})`) - const res = await workspace.querySelectorAll(args[0]) - const converted = convertInventoryItemsToResponses(res) - for (const item of converted) { - result.add(item) + let items + if (workspacePath === tree.root.path) { + // include-workspace-root + items = await tree.querySelectorAll(args[0]) + } else { + const [workspace] = await tree.querySelectorAll(`.workspace:path(${workspacePath})`) + items = await workspace.querySelectorAll(args[0]) + } + this.buildResponse(items) + } + this.npm.output(this.parsedResponse) + } + + // builds a normalized inventory + buildResponse (items) { + for (const node of items) { + if (!this.#seen.has(node.target.realpath)) { + const item = new QuerySelectorItem(node) + this.#response.push(item) + this.#seen.add(item.realpath) } } - // when running in workspaces names, make sure to key by workspace - // name the results of each value retrieved in each ws - this.npm.output(JSON.stringify([...result], null, 2)) } } diff --git a/tap-snapshots/test/lib/commands/query.js.test.cjs b/tap-snapshots/test/lib/commands/query.js.test.cjs index 430f7e143a628..c64d20f822bb0 100644 --- a/tap-snapshots/test/lib/commands/query.js.test.cjs +++ b/tap-snapshots/test/lib/commands/query.js.test.cjs @@ -22,6 +22,40 @@ exports[`test/lib/commands/query.js TAP global > should return global package 1` ] ` +exports[`test/lib/commands/query.js TAP include-workspace-root > should return workspace object and root object 1`] = ` +[ + { + "name": "project", + "workspaces": [ + "c" + ], + "dependencies": { + "a": "^1.0.0", + "b": "^1.0.0" + }, + "pkgid": "project@", + "location": "", + "path": "{CWD}/test/lib/commands/tap-testdir-query-include-workspace-root/prefix", + "realpath": "{CWD}/test/lib/commands/tap-testdir-query-include-workspace-root/prefix", + "resolved": null, + "isLink": false, + "isWorkspace": false + }, + { + "name": "c", + "version": "1.0.0", + "_id": "c@1.0.0", + "pkgid": "c@1.0.0", + "location": "c", + "path": "{CWD}/test/lib/commands/tap-testdir-query-include-workspace-root/prefix/c", + "realpath": "{CWD}/test/lib/commands/tap-testdir-query-include-workspace-root/prefix/c", + "resolved": null, + "isLink": false, + "isWorkspace": true + } +] +` + exports[`test/lib/commands/query.js TAP linked node > should return linked node res 1`] = ` [ { diff --git a/test/lib/commands/query.js b/test/lib/commands/query.js index 48b002fedac70..9b7e5256444d5 100644 --- a/test/lib/commands/query.js +++ b/test/lib/commands/query.js @@ -74,6 +74,43 @@ t.test('workspace query', async t => { t.matchSnapshot(joinedOutput(), 'should return workspace object') }) +t.test('include-workspace-root', async t => { + const { npm, joinedOutput } = await loadMockNpm(t, { + config: { + 'include-workspace-root': true, + workspaces: ['c'], + }, + prefixDir: { + node_modules: { + a: { + name: 'a', + version: '1.0.0', + }, + b: { + name: 'b', + version: '^2.0.0', + }, + c: t.fixture('symlink', '../c'), + }, + c: { + 'package.json': JSON.stringify({ + name: 'c', + version: '1.0.0', + }), + }, + 'package.json': JSON.stringify({ + name: 'project', + workspaces: ['c'], + dependencies: { + a: '^1.0.0', + b: '^1.0.0', + }, + }), + }, + }) + await npm.exec('query', [':scope'], ['c']) + t.matchSnapshot(joinedOutput(), 'should return workspace object and root object') +}) t.test('linked node', async t => { const { npm, joinedOutput } = await loadMockNpm(t, { prefixDir: {