diff --git a/lib/arborist/build-ideal-tree.js b/lib/arborist/build-ideal-tree.js index bf78d57d3..ba8101348 100644 --- a/lib/arborist/build-ideal-tree.js +++ b/lib/arborist/build-ideal-tree.js @@ -5,6 +5,7 @@ const npa = require('npm-package-arg') const pacote = require('pacote') const semver = require('semver') const pickManifest = require('npm-pick-manifest') +const mapWorkspaces = require('@npmcli/map-workspaces') const calcDepFlags = require('../calc-dep-flags.js') const Shrinkwrap = require('../shrinkwrap.js') @@ -46,6 +47,7 @@ const _nodeFromSpec = Symbol('nodeFromSpec') const _fetchManifest = Symbol('fetchManifest') const _problemEdges = Symbol('problemEdges') const _manifests = Symbol('manifests') +const _mapWorkspaces = Symbol('mapWorkspaces') const _linkFromSpec = Symbol('linkFromSpec') const _loadPeerSet = Symbol('loadPeerSet') // shared symbols so we can hit them with unit tests @@ -203,6 +205,7 @@ module.exports = cls => class IdealTreeBuilder extends Tracker(Virtual(Actual(cl .then(meta => Object.assign(root, {meta})) : this.loadVirtual({ root })) + .then(tree => this[_mapWorkspaces](tree)) .then(tree => { // null the virtual tree, because we're about to hack away at it // if you want another one, load another copy. @@ -234,9 +237,19 @@ module.exports = cls => class IdealTreeBuilder extends Tracker(Virtual(Actual(cl optional: false, global: this[_global], legacyPeerDeps: this.legacyPeerDeps, + hasWorkspaces: !!pkg.workspaces, }) } + [_mapWorkspaces] (node) { + return mapWorkspaces({ cwd: node.path, pkg: node.package }) + .then(workspaces => { + if (workspaces.size) + node.workspaces = workspaces + return node + }) + } + // process the add/rm requests by modifying the root node, and the // update.names request by queueing nodes dependent on those named. [_applyUserRequests] (options) { diff --git a/lib/arborist/load-virtual.js b/lib/arborist/load-virtual.js index 946e88d8c..0b1d0f91a 100644 --- a/lib/arborist/load-virtual.js +++ b/lib/arborist/load-virtual.js @@ -1,6 +1,7 @@ // mixin providing the loadVirtual method const {resolve} = require('path') +const mapWorkspaces = require('@npmcli/map-workspaces') const consistentResolve = require('../consistent-resolve.js') const Shrinkwrap = require('../shrinkwrap.js') @@ -15,6 +16,7 @@ const resolveLinks = Symbol('resolveLinks') const assignParentage = Symbol('assignParentage') const loadNode = Symbol('loadVirtualNode') const loadLink = Symbol('loadVirtualLink') +const loadWorkspaces = Symbol('loadWorkspaces') module.exports = cls => class VirtualLoader extends cls { constructor (options) { @@ -39,7 +41,10 @@ module.exports = cls => class VirtualLoader extends cls { // when building the ideal tree, we pass in a root node to this function // otherwise, load it from the root package in the lockfile const { - root = this[loadNode]('', s.data.packages[''] || {}) + root = this[loadWorkspaces]( + this[loadNode]('', s.data.packages[''] || {}), + s + ) } = options return this[loadFromShrinkwrap](s, root) @@ -160,6 +165,16 @@ module.exports = cls => class VirtualLoader extends cls { return node } + [loadWorkspaces] (node, s) { + const workspaces = mapWorkspaces.virtual({ + cwd: node.path, + lockfile: s.data + }) + if (workspaces.size) + node.workspaces = workspaces + return node + } + [loadLink] (location, targetLoc, target, meta) { const path = resolve(this.path, location) const link = new Link({ diff --git a/lib/edge.js b/lib/edge.js index 29003b64a..a0bb7a432 100644 --- a/lib/edge.js +++ b/lib/edge.js @@ -1,6 +1,7 @@ // An edge in the dependency graph // Represents a dependency relationship of some kind +const npa = require('npm-package-arg') const depValid = require('./dep-valid.js') const _from = Symbol('_from') const _to = Symbol('_to') @@ -18,6 +19,7 @@ const types = new Set([ 'optional', 'peer', 'peerOptional', + 'workspace' ]) class Edge { @@ -26,6 +28,10 @@ class Edge { if (typeof spec !== 'string') throw new TypeError('must provide string spec') + + if (type === 'workspace' && npa(spec).type !== 'directory') + throw new TypeError('workspace edges must be a symlink') + this[_spec] = spec if (accept !== undefined) { diff --git a/lib/node.js b/lib/node.js index b065beae2..f17e61dc5 100644 --- a/lib/node.js +++ b/lib/node.js @@ -46,6 +46,7 @@ const _fsParent = Symbol('_fsParent') const _reloadEdges = Symbol('_reloadEdges') const _loadType = Symbol('_loadType') const _loadDepType = Symbol('_loadDepType') +const _loadWorkspaces = Symbol('_loadWorkspaces') const _reloadNamedEdges = Symbol('_reloadNamedEdges') // overridden by Link class const _loadDeps = Symbol.for('Arborist.Node._loadDeps') @@ -55,6 +56,7 @@ const _refreshTopMeta = Symbol('_refreshTopMeta') const _refreshPath = Symbol('_refreshPath') const _delistFromMeta = Symbol('_delistFromMeta') const _global = Symbol.for('global') +const _workspaces = Symbol('_workspaces') const relpath = require('./relpath.js') const consistentResolve = require('./consistent-resolve.js') @@ -93,6 +95,8 @@ class Node { // true if part of a global install this[_global] = global + this[_workspaces] = null + this.errors = error ? [error] : [] const pkg = normalize(options.pkg || {}) @@ -209,6 +213,22 @@ class Node { return this.global && this.parent.isRoot } + get workspaces() { + return this[_workspaces] + } + + set workspaces(workspaces) { + // deletes edges if they already exists + if (this[_workspaces]) + for (const [name, path] of this[_workspaces].entries()) { + if (!workspaces.has(name)) this.edgesOut.get(name).detach() + } + + this[_workspaces] = workspaces + this[_loadWorkspaces]() + this[_loadDeps]() + } + get binPaths () { if (!this.parent) return [] @@ -242,6 +262,7 @@ class Node { } this[_package] = pkg + this[_loadWorkspaces]() this[_loadDeps]() // do a hard reload, since the dependents may now be valid or invalid // as a result of the package change. @@ -334,6 +355,14 @@ class Node { return this[_root] || this } + [_loadWorkspaces] () { + if (!this[_workspaces]) return + + for (const [name, path] of this[_workspaces].entries()) { + new Edge({ from: this, name, spec: `file:${path}`, type: 'workspace' }) + } + } + [_loadDeps] () { // Caveat! Order is relevant! // packages in optionalDependencies and prod/peer/dev are diff --git a/lib/shrinkwrap.js b/lib/shrinkwrap.js index 29d761d05..aa094c8e6 100644 --- a/lib/shrinkwrap.js +++ b/lib/shrinkwrap.js @@ -104,6 +104,7 @@ const pkgMetaKeys = [ 'hasInstallScript', 'bin', 'deprecated', + 'workspaces', ] const nodeMetaKeys = [ diff --git a/notes/workspace.md b/notes/workspace.md index 289705a77..d8c09e937 100644 --- a/notes/workspace.md +++ b/notes/workspace.md @@ -1,60 +1,181 @@ # workspaces -A few ways to do this: - -## Option A: link packages to root `node_modules`, install others - -This is how yarn does it. Probably better. +Conceptual install example: ``` root -+-- app (uses a, b, c, i) -| +-- node_modules -| +-- i +-- node_modules -| +-- app => root/app -| +-- a => root/pkgs/a -| +-- b => root/pkgs/b -| +-- c => root/pkgs/c +| +-- app => app +| +-- a => pkgs/a +| +-- b => pkgs/b +| +-- c => pkgs/c +| +-- x +| +-- y +| +-- z +| +-- i +| +-- n ? +| +-- j +| +-- k ++-- app +-- pkgs - +-- a (b, c, x) + +-- a (b, c, x, m@file:./m) + | +-- m (n) + | | +-- node_modules + | | +-- n ? | +-- node_modules + | +-- n ? + | +-- m => pkgs/a/m | +-- x + | +-- b => pkgs/b + | +-- c => pkgs/c +-- b (a, c, y) - | +-- node_modules - | +-- y +-- c (a, b, z) - +-- node_modules - +-- z + +-- w (nested workspace) + +-- pkgs + +-- j + +-- k ``` -## Option B: Link packages into one another +- `root/package.json`: -Kind of a mess. Not as good, but should still be supported, because that's -what pre-arborist `npm link ../foo` would generate. +```json +{ + "workspaces": [ + "pkgs/*", + "app" + ] +} +``` + +root `Node` + +- be aware it's a **Top-level workspace** +- 4 Edges in edgesOut with type=workspace, referencing workspace children + - that means we create a link node in root.children.get('app') + targetting `./app` Node, etc. +- during buildIdeal: + - need to know that app is in root's workspace + - app.wsParent = root + - root.wsChildren.add(app) + - if any dep CAN be satisfied by a named dep in the workspace, then + create a Link targetting that workspace child node + - resolving: _first_ check this.wsParent.get('dep-name'), and if + that's ok, then resolve with a link to that target. + - no hoisting by default: when doing `_canPlaceDep`, if target is + node.wsParent, AND we're not hoisting, THEN: return CONFLICT +- When setting Node.parent or Node.fsParent, set wsParent = parent.wsParent + +## Questions / Thoughts +- What a Workspace node class does? + - Add metadata to lock files + - Glob only relevant for loadActual +- maybe wsParent wsChildren +- when creating +- start with loadActual + - loadActual.loadFSNode + - on check for path is real add another check to make load from/as a workspace +- General impl ideas + - Do we support an opt-out flag? + - Do we want to add extra top-level commands to the cli? + - `npm workspaces info`: Retrieves workspaces locations (might be useful for tooling) + - What do we do with binaries? Do we only link bins for workspaces that are defined as a top-level dep? + - In order to support subsets of packages the way Wes been advocating for, instead of supporting adjacent folders with package.json defining different workspaces, what if we were to support a different workspaces config definition within the top-level package.json - maybe something that allows for definition of subsets? something in the likes of: + ``` + "workspaces": [ + "packages": { + "set-a": [ + "packages/*" + ], + "set-b": [ + "express/express-namespace", + "express/express" + ] + } + ] + ``` + - But then we'd need a way for commands to be aware of these subsets... + +## Registry vs workspace relationship: ``` -root -+-- pkgs - +-- app - | +-- node_modules - | +-- a => pkgs/a - | +-- b => pkgs/b - | +-- c => pkgs/c - | +-- i - +-- a (b, c, x) - | +-- node_modules - | +-- x - | +-- b => pkgs/b - | +-- c => pkgs/c - +-- b (a, c, y) - | +-- node_modules - | +-- y - | +-- a => pkgs/a - | +-- c => pkgs/c - +-- c (a, b, z) +given that registry has latest: a@1.1.0 + +workspace-root ++-- packages + +-- a (a@1.0.1) + +-- b (a@^1.0.0) + +npm install + +workspace-root ++-- packages + +-- a (a@1.0.1) + +-- b (a@^1.0.0) + +-- node_modules + +-- a -> ../../a + +workspaces always prefer to install a nested package if semver is satisfied +``` + +``` +given that registry has latest: a@2.0.0 + +workspace-root ++-- packages + +-- a@1.0.1 + +-- b (a@^2.0.0) + +npm install + +workspace-root ++-- packages + +-- a@1.0.1 + +-- b (a@^2.0.0) +-- node_modules - +-- z - +-- a => pkgs/a - +-- b => pkgs/b + +-- a@2.0.0 + +workspaces will try to install deps from registry if no satisfying semver version was found within its nested packages ``` + +## Implementation + +### Build Ideal Tree + +1. Read list of "workpaces" from `package.json` +2. Turn globs into actual locations, retrieve the final list of workspaces paths +3. Arborist needs to be made aware of the list of worskpaces paths + 1. Workspace info parsed (steps 1 and 2) needs to be attached before build ideal tree + 2. On building ideal tree, checks against existing workspaces to append them as child nodes + 3. Edge needs to support a `workspace` type + 4. Edge `satisfiedBy` and/or the `dep-valid` module needs to check against the available workspaces + 5. `edgesOut` with `type: workspace` +4. Represent a workspace node within a tree - is it just `node.workspace` ? + +NOTE: +- Now the build ideal tree is reading fs other than `package.json` and `package-lock` + +### Load Virtual + +1. How to figure out all the structure of workspaces form a pakcage-lock + 1. How it gets saved? + 2. How to build the virtual tree out of reading package-lock +2. maybe support a subset of glob? we need to optimize mapWorkspace regardless +3. lib/shrinkwrap.js has to be aware of workspaces and the structure + 1. Reading from lockfile might render nodes extraneous? + 2. include workspaces map into package-lock files + 3. loadVirtual reads from the lock file and put nodes in the right place + + +### Reify + +1. Correctly symlink workspaces to its dependants `node_modules` + +## Open Ended Questions + +- Maybe do not hoist workspace dependencies by default? + +## Missing: +- Nested workspaces + - Add support to `mapWorkspaces` in buildIdealTree `_linkFromSpec` + - Tests +- Test case with a mixed relationship between `file:` deps and workspaces diff --git a/package-lock.json b/package-lock.json index d309cbb41..50e8223ca 100644 --- a/package-lock.json +++ b/package-lock.json @@ -180,6 +180,17 @@ "readdir-scoped-modules": "^1.1.0" } }, + "@npmcli/map-workspaces": { + "version": "0.0.0-pre.1", + "resolved": "https://registry.npmjs.org/@npmcli/map-workspaces/-/map-workspaces-0.0.0-pre.1.tgz", + "integrity": "sha512-IovEVdr17hW/Stt0kpPjz1r0ZxRX3RGah7ww3tQpi5NtyOapJwbUffWuWETyQkOjud5soC45mnjOOBtfTggtng==", + "requires": { + "@npmcli/name-from-folder": "^1.0.1", + "glob": "^7.1.6", + "minimatch": "^3.0.4", + "read-package-json-fast": "^1.1.3" + } + }, "@npmcli/name-from-folder": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@npmcli/name-from-folder/-/name-from-folder-1.0.1.tgz", diff --git a/package.json b/package.json index e73c6f571..f9cc794b4 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,7 @@ "dependencies": { "@npmcli/installed-package-contents": "^1.0.5", "@npmcli/name-from-folder": "^1.0.1", + "@npmcli/map-workspaces": "0.0.0-pre.1", "@npmcli/run-script": "^1.3.1", "bin-links": "^2.1.2", "json-stringify-nice": "^1.1.1", diff --git a/tap-snapshots/test-arborist-build-ideal-tree.js-TAP.test.js b/tap-snapshots/test-arborist-build-ideal-tree.js-TAP.test.js index 5cf4e43be..4ee8d799f 100644 --- a/tap-snapshots/test-arborist-build-ideal-tree.js-TAP.test.js +++ b/tap-snapshots/test-arborist-build-ideal-tree.js-TAP.test.js @@ -50318,3 +50318,961 @@ Node { "resolved": null, } ` + +exports[`test/arborist/build-ideal-tree.js TAP workspaces should ignore nested node_modules folders > expect resolving Promise 1`] = ` +Node { + "children": Map { + "a" => Link { + "edgesIn": Set { + Edge { + "from": "", + "name": "a", + "spec": "file:{CWD}/test/fixtures/workspaces-ignore-nm/packages/a", + "type": "workspace", + }, + }, + "location": "node_modules/a", + "name": "a", + "resolved": "file:../packages/a", + "target": Object { + "name": "a", + "parent": null, + }, + }, + }, + "edgesOut": Map { + "a" => Edge { + "name": "a", + "spec": "file:{CWD}/test/fixtures/workspaces-ignore-nm/packages/a", + "to": "node_modules/a", + "type": "workspace", + }, + }, + "fsChildren": Set { + Node { + "location": "packages/a", + "name": "a", + "resolved": null, + }, + }, + "location": "", + "name": "workspaces-ignore-nm", + "resolved": null, +} +` + +exports[`test/arborist/build-ideal-tree.js TAP workspaces should install a simple example > expect resolving Promise 1`] = ` +Node { + "children": Map { + "a" => Link { + "edgesIn": Set { + Edge { + "from": "", + "name": "a", + "spec": "file:{CWD}/test/fixtures/workspaces-simple/a", + "type": "workspace", + }, + }, + "location": "node_modules/a", + "name": "a", + "resolved": "file:../a", + "target": Object { + "name": "a", + "parent": null, + }, + }, + "b" => Link { + "edgesIn": Set { + Edge { + "from": "", + "name": "b", + "spec": "file:{CWD}/test/fixtures/workspaces-simple/b", + "type": "workspace", + }, + Edge { + "from": "a", + "name": "b", + "spec": "^1.0.0", + "type": "prod", + }, + }, + "location": "node_modules/b", + "name": "b", + "resolved": "file:../b", + "target": Object { + "name": "b", + "parent": null, + }, + }, + }, + "edgesOut": Map { + "a" => Edge { + "name": "a", + "spec": "file:{CWD}/test/fixtures/workspaces-simple/a", + "to": "node_modules/a", + "type": "workspace", + }, + "b" => Edge { + "name": "b", + "spec": "file:{CWD}/test/fixtures/workspaces-simple/b", + "to": "node_modules/b", + "type": "workspace", + }, + }, + "fsChildren": Set { + Node { + "edgesOut": Map { + "b" => Edge { + "name": "b", + "spec": "^1.0.0", + "to": "node_modules/b", + "type": "prod", + }, + }, + "location": "a", + "name": "a", + "resolved": null, + }, + Node { + "location": "b", + "name": "b", + "resolved": null, + }, + }, + "location": "", + "name": "workspaces-simple", + "resolved": null, +} +` + +exports[`test/arborist/build-ideal-tree.js TAP workspaces should install a simple scoped pkg example > expect resolving Promise 1`] = ` +Node { + "children": Map { + "@ruyadorno/scoped-a" => Link { + "edgesIn": Set { + Edge { + "from": "", + "name": "@ruyadorno/scoped-a", + "spec": "file:{CWD}/test/fixtures/workspaces-scoped-pkg/packages/a", + "type": "workspace", + }, + }, + "location": "node_modules/@ruyadorno/scoped-a", + "name": "@ruyadorno/scoped-a", + "resolved": "file:../../packages/a", + "target": Object { + "name": "@ruyadorno/scoped-a", + "parent": null, + }, + }, + "@ruyadorno/scoped-b" => Link { + "edgesIn": Set { + Edge { + "from": "", + "name": "@ruyadorno/scoped-b", + "spec": "file:{CWD}/test/fixtures/workspaces-scoped-pkg/packages/b", + "type": "workspace", + }, + Edge { + "from": "packages/a", + "name": "@ruyadorno/scoped-b", + "spec": "^1.0.0", + "type": "prod", + }, + }, + "location": "node_modules/@ruyadorno/scoped-b", + "name": "@ruyadorno/scoped-b", + "resolved": "file:../../packages/b", + "target": Object { + "name": "@ruyadorno/scoped-b", + "parent": null, + }, + }, + }, + "edgesOut": Map { + "@ruyadorno/scoped-a" => Edge { + "name": "@ruyadorno/scoped-a", + "spec": "file:{CWD}/test/fixtures/workspaces-scoped-pkg/packages/a", + "to": "node_modules/@ruyadorno/scoped-a", + "type": "workspace", + }, + "@ruyadorno/scoped-b" => Edge { + "name": "@ruyadorno/scoped-b", + "spec": "file:{CWD}/test/fixtures/workspaces-scoped-pkg/packages/b", + "to": "node_modules/@ruyadorno/scoped-b", + "type": "workspace", + }, + }, + "fsChildren": Set { + Node { + "edgesOut": Map { + "@ruyadorno/scoped-b" => Edge { + "name": "@ruyadorno/scoped-b", + "spec": "^1.0.0", + "to": "node_modules/@ruyadorno/scoped-b", + "type": "prod", + }, + }, + "location": "packages/a", + "name": "@ruyadorno/scoped-a", + "resolved": null, + }, + Node { + "location": "packages/b", + "name": "@ruyadorno/scoped-b", + "resolved": null, + }, + }, + "location": "", + "name": "workspaces-scoped-pkg", + "resolved": null, +} +` + +exports[`test/arborist/build-ideal-tree.js TAP workspaces should install conflicting dep versions > expect resolving Promise 1`] = ` +Node { + "children": Map { + "a" => Link { + "edgesIn": Set { + Edge { + "from": "", + "name": "a", + "spec": "file:{CWD}/test/fixtures/workspaces-conflicting-versions/packages/a", + "type": "workspace", + }, + }, + "location": "node_modules/a", + "name": "a", + "resolved": "file:../packages/a", + "target": Object { + "name": "a", + "parent": null, + }, + }, + "abbrev" => Node { + "edgesIn": Set { + Edge { + "from": "", + "name": "abbrev", + "spec": "^1.1.1", + "type": "prod", + }, + }, + "location": "node_modules/abbrev", + "name": "abbrev", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + }, + "b" => Link { + "edgesIn": Set { + Edge { + "from": "", + "name": "b", + "spec": "file:{CWD}/test/fixtures/workspaces-conflicting-versions/packages/b", + "type": "workspace", + }, + }, + "location": "node_modules/b", + "name": "b", + "resolved": "file:../packages/b", + "target": Object { + "name": "b", + "parent": null, + }, + }, + }, + "edgesOut": Map { + "a" => Edge { + "name": "a", + "spec": "file:{CWD}/test/fixtures/workspaces-conflicting-versions/packages/a", + "to": "node_modules/a", + "type": "workspace", + }, + "abbrev" => Edge { + "name": "abbrev", + "spec": "^1.1.1", + "to": "node_modules/abbrev", + "type": "prod", + }, + "b" => Edge { + "name": "b", + "spec": "file:{CWD}/test/fixtures/workspaces-conflicting-versions/packages/b", + "to": "node_modules/b", + "type": "workspace", + }, + }, + "fsChildren": Set { + Node { + "children": Map { + "abbrev" => Node { + "edgesIn": Set { + Edge { + "from": "packages/a", + "name": "abbrev", + "spec": "=1.0.4", + "type": "prod", + }, + }, + "location": "packages/a/node_modules/abbrev", + "name": "abbrev", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.4.tgz", + }, + }, + "edgesOut": Map { + "abbrev" => Edge { + "name": "abbrev", + "spec": "=1.0.4", + "to": "packages/a/node_modules/abbrev", + "type": "prod", + }, + }, + "location": "packages/a", + "name": "a", + "resolved": null, + }, + Node { + "children": Map { + "abbrev" => Node { + "edgesIn": Set { + Edge { + "from": "packages/b", + "name": "abbrev", + "spec": "=1.1.0", + "type": "prod", + }, + }, + "location": "packages/b/node_modules/abbrev", + "name": "abbrev", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.0.tgz", + }, + }, + "edgesOut": Map { + "abbrev" => Edge { + "name": "abbrev", + "spec": "=1.1.0", + "to": "packages/b/node_modules/abbrev", + "type": "prod", + }, + }, + "location": "packages/b", + "name": "b", + "resolved": null, + }, + }, + "location": "", + "name": "workspaces-conflicting-versions", + "resolved": null, +} +` + +exports[`test/arborist/build-ideal-tree.js TAP workspaces should install from registry on version not satisfied > expect resolving Promise 1`] = ` +Node { + "children": Map { + "a" => Link { + "edgesIn": Set { + Edge { + "from": "", + "name": "a", + "spec": "file:{CWD}/test/fixtures/workspaces-version-unsatisfied/packages/a", + "type": "workspace", + }, + }, + "location": "node_modules/a", + "name": "a", + "resolved": "file:../packages/a", + "target": Object { + "name": "a", + "parent": null, + }, + }, + "abbrev" => Link { + "edgesIn": Set { + Edge { + "from": "", + "name": "abbrev", + "spec": "file:{CWD}/test/fixtures/workspaces-version-unsatisfied/packages/abbrev", + "type": "workspace", + }, + }, + "location": "node_modules/abbrev", + "name": "abbrev", + "resolved": "file:../packages/abbrev", + "target": Object { + "name": "abbrev", + "parent": null, + }, + }, + }, + "edgesOut": Map { + "a" => Edge { + "name": "a", + "spec": "file:{CWD}/test/fixtures/workspaces-version-unsatisfied/packages/a", + "to": "node_modules/a", + "type": "workspace", + }, + "abbrev" => Edge { + "name": "abbrev", + "spec": "file:{CWD}/test/fixtures/workspaces-version-unsatisfied/packages/abbrev", + "to": "node_modules/abbrev", + "type": "workspace", + }, + }, + "fsChildren": Set { + Node { + "children": Map { + "abbrev" => Node { + "edgesIn": Set { + Edge { + "from": "packages/a", + "name": "abbrev", + "spec": "=1.1.1", + "type": "prod", + }, + }, + "location": "packages/a/node_modules/abbrev", + "name": "abbrev", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + }, + }, + "edgesOut": Map { + "abbrev" => Edge { + "name": "abbrev", + "spec": "=1.1.1", + "to": "packages/a/node_modules/abbrev", + "type": "prod", + }, + }, + "location": "packages/a", + "name": "a", + "resolved": null, + }, + Node { + "location": "packages/abbrev", + "name": "abbrev", + "resolved": null, + }, + }, + "location": "", + "name": "workspaces-version-unsatisfied", + "resolved": null, +} +` + +exports[`test/arborist/build-ideal-tree.js TAP workspaces should install shared dependencies into root folder > expect resolving Promise 1`] = ` +Node { + "children": Map { + "a" => Link { + "edgesIn": Set { + Edge { + "from": "", + "name": "a", + "spec": "file:{CWD}/test/fixtures/workspaces-shared-deps/packages/a", + "type": "workspace", + }, + }, + "location": "node_modules/a", + "name": "a", + "resolved": "file:../packages/a", + "target": Object { + "name": "a", + "parent": null, + }, + }, + "abbrev" => Node { + "edgesIn": Set { + Edge { + "from": "packages/a", + "name": "abbrev", + "spec": "^1.1.1", + "type": "prod", + }, + Edge { + "from": "packages/b", + "name": "abbrev", + "spec": "^1.1.1", + "type": "prod", + }, + }, + "location": "node_modules/abbrev", + "name": "abbrev", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + }, + "b" => Link { + "edgesIn": Set { + Edge { + "from": "", + "name": "b", + "spec": "file:{CWD}/test/fixtures/workspaces-shared-deps/packages/b", + "type": "workspace", + }, + }, + "location": "node_modules/b", + "name": "b", + "resolved": "file:../packages/b", + "target": Object { + "name": "b", + "parent": null, + }, + }, + "c" => Link { + "edgesIn": Set { + Edge { + "from": "", + "name": "c", + "spec": "file:{CWD}/test/fixtures/workspaces-shared-deps/packages/c", + "type": "workspace", + }, + }, + "location": "node_modules/c", + "name": "c", + "resolved": "file:../packages/c", + "target": Object { + "name": "c", + "parent": null, + }, + }, + "uuid" => Node { + "edgesIn": Set { + Edge { + "from": "packages/c", + "name": "uuid", + "spec": "=3.3.3", + "type": "prod", + }, + }, + "location": "node_modules/uuid", + "name": "uuid", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz", + }, + }, + "edgesOut": Map { + "a" => Edge { + "name": "a", + "spec": "file:{CWD}/test/fixtures/workspaces-shared-deps/packages/a", + "to": "node_modules/a", + "type": "workspace", + }, + "b" => Edge { + "name": "b", + "spec": "file:{CWD}/test/fixtures/workspaces-shared-deps/packages/b", + "to": "node_modules/b", + "type": "workspace", + }, + "c" => Edge { + "name": "c", + "spec": "file:{CWD}/test/fixtures/workspaces-shared-deps/packages/c", + "to": "node_modules/c", + "type": "workspace", + }, + }, + "fsChildren": Set { + Node { + "edgesOut": Map { + "abbrev" => Edge { + "name": "abbrev", + "spec": "^1.1.1", + "to": "node_modules/abbrev", + "type": "prod", + }, + }, + "location": "packages/a", + "name": "a", + "resolved": null, + }, + Node { + "edgesOut": Map { + "abbrev" => Edge { + "name": "abbrev", + "spec": "^1.1.1", + "to": "node_modules/abbrev", + "type": "prod", + }, + }, + "location": "packages/b", + "name": "b", + "resolved": null, + }, + Node { + "edgesOut": Map { + "uuid" => Edge { + "name": "uuid", + "spec": "=3.3.3", + "to": "node_modules/uuid", + "type": "prod", + }, + }, + "location": "packages/c", + "name": "c", + "resolved": null, + }, + }, + "location": "", + "name": "workspaces-shared-deps", + "resolved": null, +} +` + +exports[`test/arborist/build-ideal-tree.js TAP workspaces should install workspace transitive dependencies > expect resolving Promise 1`] = ` +Node { + "children": Map { + "a" => Link { + "edgesIn": Set { + Edge { + "from": "", + "name": "a", + "spec": "file:{CWD}/test/fixtures/workspaces-transitive-deps/packages/a", + "type": "workspace", + }, + }, + "location": "node_modules/a", + "name": "a", + "resolved": "file:../packages/a", + "target": Object { + "name": "a", + "parent": null, + }, + }, + "once" => Node { + "dev": true, + "edgesIn": Set { + Edge { + "from": "packages/a", + "name": "once", + "spec": "^1.4.0", + "type": "dev", + }, + }, + "edgesOut": Map { + "wrappy" => Edge { + "name": "wrappy", + "spec": "1", + "to": "node_modules/wrappy", + "type": "prod", + }, + }, + "location": "node_modules/once", + "name": "once", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + }, + "wrappy" => Node { + "dev": true, + "edgesIn": Set { + Edge { + "from": "node_modules/once", + "name": "wrappy", + "spec": "1", + "type": "prod", + }, + }, + "location": "node_modules/wrappy", + "name": "wrappy", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + }, + }, + "edgesOut": Map { + "a" => Edge { + "name": "a", + "spec": "file:{CWD}/test/fixtures/workspaces-transitive-deps/packages/a", + "to": "node_modules/a", + "type": "workspace", + }, + }, + "fsChildren": Set { + Node { + "edgesOut": Map { + "once" => Edge { + "name": "once", + "spec": "^1.4.0", + "to": "node_modules/once", + "type": "dev", + }, + }, + "location": "packages/a", + "name": "a", + "resolved": null, + }, + }, + "location": "", + "name": "workspaces-transitive-deps", + "resolved": null, +} +` + +exports[`test/arborist/build-ideal-tree.js TAP workspaces should link top level nested workspaces > expect resolving Promise 1`] = ` +Node { + "children": Map { + "a" => Link { + "edgesIn": Set { + Edge { + "from": "", + "name": "a", + "spec": "file:{CWD}/test/fixtures/workspaces-top-level-link/packages/a", + "type": "workspace", + }, + }, + "location": "node_modules/a", + "name": "a", + "resolved": "file:../packages/a", + "target": Object { + "name": "a", + "parent": null, + }, + }, + }, + "edgesOut": Map { + "a" => Edge { + "name": "a", + "spec": "file:{CWD}/test/fixtures/workspaces-top-level-link/packages/a", + "to": "node_modules/a", + "type": "workspace", + }, + }, + "fsChildren": Set { + Node { + "location": "packages/a", + "name": "a", + "resolved": null, + }, + }, + "location": "", + "name": "workspaces-top-level-link", + "resolved": null, +} +` + +exports[`test/arborist/build-ideal-tree.js TAP workspaces should prefer linking nested workspaces > expect resolving Promise 1`] = ` +Node { + "children": Map { + "a" => Link { + "edgesIn": Set { + Edge { + "from": "", + "name": "a", + "spec": "file:{CWD}/test/fixtures/workspaces-prefer-linking/packages/a", + "type": "workspace", + }, + }, + "location": "node_modules/a", + "name": "a", + "resolved": "file:../packages/a", + "target": Object { + "name": "a", + "parent": null, + }, + }, + "abbrev" => Link { + "edgesIn": Set { + Edge { + "from": "", + "name": "abbrev", + "spec": "file:{CWD}/test/fixtures/workspaces-prefer-linking/packages/abbrev", + "type": "workspace", + }, + Edge { + "from": "packages/a", + "name": "abbrev", + "spec": "*", + "type": "prod", + }, + }, + "location": "node_modules/abbrev", + "name": "abbrev", + "resolved": "file:../packages/abbrev", + "target": Object { + "name": "abbrev", + "parent": null, + }, + }, + }, + "edgesOut": Map { + "a" => Edge { + "name": "a", + "spec": "file:{CWD}/test/fixtures/workspaces-prefer-linking/packages/a", + "to": "node_modules/a", + "type": "workspace", + }, + "abbrev" => Edge { + "name": "abbrev", + "spec": "file:{CWD}/test/fixtures/workspaces-prefer-linking/packages/abbrev", + "to": "node_modules/abbrev", + "type": "workspace", + }, + }, + "fsChildren": Set { + Node { + "edgesOut": Map { + "abbrev" => Edge { + "name": "abbrev", + "spec": "*", + "to": "node_modules/abbrev", + "type": "prod", + }, + }, + "location": "packages/a", + "name": "a", + "resolved": null, + }, + Node { + "location": "packages/abbrev", + "name": "abbrev", + "resolved": null, + }, + }, + "location": "", + "name": "workspaces-prefer-linking", + "resolved": null, +} +` + +exports[`test/arborist/build-ideal-tree.js TAP workspaces should work with files spec > expect resolving Promise 1`] = ` +Node { + "children": Map { + "a" => Link { + "edgesIn": Set { + Edge { + "from": "", + "name": "a", + "spec": "file:{CWD}/test/fixtures/workspaces-with-files-spec/packages/a", + "type": "workspace", + }, + }, + "location": "node_modules/a", + "name": "a", + "resolved": "file:../packages/a", + "target": Object { + "name": "a", + "parent": null, + }, + }, + "b" => Link { + "edgesIn": Set { + Edge { + "from": "", + "name": "b", + "spec": "file:{CWD}/test/fixtures/workspaces-with-files-spec/packages/b", + "type": "workspace", + }, + Edge { + "from": "d", + "name": "b", + "spec": "^1.0.0", + "type": "prod", + }, + }, + "location": "node_modules/b", + "name": "b", + "resolved": "file:../packages/b", + "target": Object { + "name": "b", + "parent": null, + }, + }, + "c" => Link { + "edgesIn": Set { + Edge { + "from": "", + "name": "c", + "spec": "file:packages/c", + "type": "prod", + }, + }, + "location": "node_modules/c", + "name": "c", + "resolved": "file:../packages/c", + "target": Object { + "name": "c", + "parent": null, + }, + }, + "d" => Link { + "edgesIn": Set { + Edge { + "from": "", + "name": "d", + "spec": "file:d", + "type": "prod", + }, + Edge { + "from": "packages/a", + "name": "d", + "spec": "^1.0.0", + "type": "prod", + }, + }, + "location": "node_modules/d", + "name": "d", + "resolved": "file:../d", + "target": Object { + "name": "d", + "parent": null, + }, + }, + }, + "edgesOut": Map { + "a" => Edge { + "name": "a", + "spec": "file:{CWD}/test/fixtures/workspaces-with-files-spec/packages/a", + "to": "node_modules/a", + "type": "workspace", + }, + "b" => Edge { + "name": "b", + "spec": "file:{CWD}/test/fixtures/workspaces-with-files-spec/packages/b", + "to": "node_modules/b", + "type": "workspace", + }, + "c" => Edge { + "name": "c", + "spec": "file:packages/c", + "to": "node_modules/c", + "type": "prod", + }, + "d" => Edge { + "name": "d", + "spec": "file:d", + "to": "node_modules/d", + "type": "prod", + }, + }, + "fsChildren": Set { + Node { + "edgesOut": Map { + "b" => Edge { + "name": "b", + "spec": "^1.0.0", + "to": "node_modules/b", + "type": "prod", + }, + }, + "location": "d", + "name": "d", + "resolved": null, + }, + Node { + "edgesOut": Map { + "d" => Edge { + "name": "d", + "spec": "^1.0.0", + "to": "node_modules/d", + "type": "prod", + }, + }, + "location": "packages/a", + "name": "a", + "resolved": null, + }, + Node { + "location": "packages/b", + "name": "b", + "resolved": null, + }, + Node { + "location": "packages/c", + "name": "c", + "resolved": null, + }, + }, + "location": "", + "name": "workspaces-with-files-spec", + "resolved": null, +} +` diff --git a/tap-snapshots/test-arborist-load-virtual.js-TAP.test.js b/tap-snapshots/test-arborist-load-virtual.js-TAP.test.js index c480aaa21..5b9f13887 100644 --- a/tap-snapshots/test-arborist-load-virtual.js-TAP.test.js +++ b/tap-snapshots/test-arborist-load-virtual.js-TAP.test.js @@ -13552,3 +13552,541 @@ Node { "resolved": null, } ` + +exports[`test/arborist/load-virtual.js TAP workspaces load a simple example > virtual tree with multiple bundles 1`] = ` +Node { + "children": Map { + "a" => Link { + "edgesIn": Set { + Edge { + "from": "", + "name": "a", + "spec": "file:{CWD}/test/fixtures/workspaces-simple-virtual/a", + "type": "workspace", + }, + }, + "location": "node_modules/a", + "name": "a", + "resolved": "file:../a", + "target": Object { + "name": "a", + "parent": undefined, + }, + }, + "b" => Link { + "edgesIn": Set { + Edge { + "from": "", + "name": "b", + "spec": "file:{CWD}/test/fixtures/workspaces-simple-virtual/b", + "type": "workspace", + }, + Edge { + "from": "a", + "name": "b", + "spec": "^1.0.0", + "type": "prod", + }, + }, + "location": "node_modules/b", + "name": "b", + "resolved": "file:../b", + "target": Object { + "name": "b", + "parent": undefined, + }, + }, + }, + "edgesOut": Map { + "a" => Edge { + "name": "a", + "spec": "file:{CWD}/test/fixtures/workspaces-simple-virtual/a", + "to": "node_modules/a", + "type": "workspace", + }, + "b" => Edge { + "name": "b", + "spec": "file:{CWD}/test/fixtures/workspaces-simple-virtual/b", + "to": "node_modules/b", + "type": "workspace", + }, + }, + "location": "", + "name": "workspaces-simple-virtual", + "resolved": null, +} +` + +exports[`test/arborist/load-virtual.js TAP workspaces load conflicting dep versions example > virtual tree with resolved conflicting dependencies 1`] = ` +Node { + "children": Map { + "a" => Link { + "edgesIn": Set { + Edge { + "from": "", + "name": "a", + "spec": "file:{CWD}/test/fixtures/workspaces-conflicting-versions-virtual/packages/a", + "type": "workspace", + }, + }, + "location": "node_modules/a", + "name": "a", + "resolved": "file:../packages/a", + "target": Object { + "name": "a", + "parent": undefined, + }, + }, + "abbrev" => Node { + "edgesIn": Set { + Edge { + "from": "", + "name": "abbrev", + "spec": "^1.1.1", + "type": "prod", + }, + Edge { + "error": "INVALID", + "from": "packages/a", + "name": "abbrev", + "spec": "=1.0.4", + "type": "prod", + }, + Edge { + "error": "INVALID", + "from": "packages/b", + "name": "abbrev", + "spec": "=1.1.0", + "type": "prod", + }, + }, + "location": "node_modules/abbrev", + "name": "abbrev", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + }, + "b" => Link { + "edgesIn": Set { + Edge { + "from": "", + "name": "b", + "spec": "file:{CWD}/test/fixtures/workspaces-conflicting-versions-virtual/packages/b", + "type": "workspace", + }, + }, + "location": "node_modules/b", + "name": "b", + "resolved": "file:../packages/b", + "target": Object { + "name": "b", + "parent": undefined, + }, + }, + }, + "edgesOut": Map { + "a" => Edge { + "name": "a", + "spec": "file:{CWD}/test/fixtures/workspaces-conflicting-versions-virtual/packages/a", + "to": "node_modules/a", + "type": "workspace", + }, + "abbrev" => Edge { + "name": "abbrev", + "spec": "^1.1.1", + "to": "node_modules/abbrev", + "type": "prod", + }, + "b" => Edge { + "name": "b", + "spec": "file:{CWD}/test/fixtures/workspaces-conflicting-versions-virtual/packages/b", + "to": "node_modules/b", + "type": "workspace", + }, + }, + "location": "", + "name": "workspaces-conflicting-versions-virtual", + "resolved": null, +} +` + +exports[`test/arborist/load-virtual.js TAP workspaces load installed from registry on version not satisfied > virtual tree with deduped dep 1`] = ` +Node { + "children": Map { + "a" => Link { + "edgesIn": Set { + Edge { + "from": "", + "name": "a", + "spec": "file:{CWD}/test/fixtures/workspaces-version-unsatisfied-virtual/packages/a", + "type": "workspace", + }, + }, + "location": "node_modules/a", + "name": "a", + "resolved": "file:../packages/a", + "target": Object { + "name": "a", + "parent": undefined, + }, + }, + "abbrev" => Link { + "edgesIn": Set { + Edge { + "from": "", + "name": "abbrev", + "spec": "file:{CWD}/test/fixtures/workspaces-version-unsatisfied-virtual/packages/abbrev", + "type": "workspace", + }, + Edge { + "error": "INVALID", + "from": "packages/a", + "name": "abbrev", + "spec": "=1.1.1", + "type": "prod", + }, + }, + "location": "node_modules/abbrev", + "name": "abbrev", + "resolved": "file:../packages/abbrev", + "target": Object { + "name": "abbrev", + "parent": undefined, + }, + }, + }, + "edgesOut": Map { + "a" => Edge { + "name": "a", + "spec": "file:{CWD}/test/fixtures/workspaces-version-unsatisfied-virtual/packages/a", + "to": "node_modules/a", + "type": "workspace", + }, + "abbrev" => Edge { + "name": "abbrev", + "spec": "file:{CWD}/test/fixtures/workspaces-version-unsatisfied-virtual/packages/abbrev", + "to": "node_modules/abbrev", + "type": "workspace", + }, + }, + "location": "", + "name": "workspaces-version-unsatisfied-virtual", + "resolved": null, +} +` + +exports[`test/arborist/load-virtual.js TAP workspaces load installed tree with ignored nested node_modules folders > virtual tree ignoring nested node_modules 1`] = ` +Node { + "children": Map { + "a" => Link { + "edgesIn": Set { + Edge { + "from": "", + "name": "a", + "spec": "file:{CWD}/test/fixtures/workspaces-ignore-nm-virtual/packages/a", + "type": "workspace", + }, + }, + "location": "node_modules/a", + "name": "a", + "resolved": "file:../packages/a", + "target": Object { + "name": "a", + "parent": undefined, + }, + }, + }, + "edgesOut": Map { + "a" => Edge { + "name": "a", + "spec": "file:{CWD}/test/fixtures/workspaces-ignore-nm-virtual/packages/a", + "to": "node_modules/a", + "type": "workspace", + }, + }, + "location": "", + "name": "workspaces-ignore-nm-virtual", + "resolved": null, +} +` + +exports[`test/arborist/load-virtual.js TAP workspaces load installed workspace with transitive dependencies > virtual tree with transitive deps 1`] = ` +Node { + "children": Map { + "a" => Link { + "edgesIn": Set { + Edge { + "from": "", + "name": "a", + "spec": "file:{CWD}/test/fixtures/workspaces-transitive-deps-virtual/packages/a", + "type": "workspace", + }, + }, + "location": "node_modules/a", + "name": "a", + "resolved": "file:../packages/a", + "target": Object { + "name": "a", + "parent": undefined, + }, + }, + "once" => Node { + "dev": true, + "edgesIn": Set { + Edge { + "from": "packages/a", + "name": "once", + "spec": "^1.4.0", + "type": "dev", + }, + }, + "edgesOut": Map { + "wrappy" => Edge { + "name": "wrappy", + "spec": "1", + "to": "node_modules/wrappy", + "type": "prod", + }, + }, + "location": "node_modules/once", + "name": "once", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + }, + "wrappy" => Node { + "dev": true, + "edgesIn": Set { + Edge { + "from": "node_modules/once", + "name": "wrappy", + "spec": "1", + "type": "prod", + }, + }, + "location": "node_modules/wrappy", + "name": "wrappy", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + }, + }, + "edgesOut": Map { + "a" => Edge { + "name": "a", + "spec": "file:{CWD}/test/fixtures/workspaces-transitive-deps-virtual/packages/a", + "to": "node_modules/a", + "type": "workspace", + }, + }, + "location": "", + "name": "workspaces-transitive-deps-virtual", + "resolved": null, +} +` + +exports[`test/arborist/load-virtual.js TAP workspaces load linked top level nested workspaces > virtual tree top level dep 1`] = ` +Node { + "children": Map { + "a" => Link { + "edgesIn": Set { + Edge { + "from": "", + "name": "a", + "spec": "file:{CWD}/test/fixtures/workspaces-top-level-link-virtual/packages/a", + "type": "workspace", + }, + }, + "location": "node_modules/a", + "name": "a", + "resolved": "file:../packages/a", + "target": Object { + "name": "a", + "parent": undefined, + }, + }, + }, + "edgesOut": Map { + "a" => Edge { + "name": "a", + "spec": "file:{CWD}/test/fixtures/workspaces-top-level-link-virtual/packages/a", + "to": "node_modules/a", + "type": "workspace", + }, + }, + "location": "", + "name": "workspaces-top-level-link-virtual", + "resolved": null, +} +` + +exports[`test/arborist/load-virtual.js TAP workspaces load prefer linking nested workspaces > virtual tree linking to local workspaces 1`] = ` +Node { + "children": Map { + "a" => Link { + "edgesIn": Set { + Edge { + "from": "", + "name": "a", + "spec": "file:{CWD}/test/fixtures/workspaces-prefer-linking-virtual/packages/a", + "type": "workspace", + }, + }, + "location": "node_modules/a", + "name": "a", + "resolved": "file:../packages/a", + "target": Object { + "name": "a", + "parent": undefined, + }, + }, + "abbrev" => Link { + "edgesIn": Set { + Edge { + "from": "", + "name": "abbrev", + "spec": "file:{CWD}/test/fixtures/workspaces-prefer-linking-virtual/packages/abbrev", + "type": "workspace", + }, + Edge { + "from": "packages/a", + "name": "abbrev", + "spec": "*", + "type": "prod", + }, + }, + "location": "node_modules/abbrev", + "name": "abbrev", + "resolved": "file:../packages/abbrev", + "target": Object { + "name": "abbrev", + "parent": undefined, + }, + }, + }, + "edgesOut": Map { + "a" => Edge { + "name": "a", + "spec": "file:{CWD}/test/fixtures/workspaces-prefer-linking-virtual/packages/a", + "to": "node_modules/a", + "type": "workspace", + }, + "abbrev" => Edge { + "name": "abbrev", + "spec": "file:{CWD}/test/fixtures/workspaces-prefer-linking-virtual/packages/abbrev", + "to": "node_modules/abbrev", + "type": "workspace", + }, + }, + "location": "", + "name": "workspaces-prefer-linking-virtual", + "resolved": null, +} +` + +exports[`test/arborist/load-virtual.js TAP workspaces load shared dependencies example > virtual tree with shared dependencies 1`] = ` +Node { + "children": Map { + "a" => Link { + "edgesIn": Set { + Edge { + "from": "", + "name": "a", + "spec": "file:{CWD}/test/fixtures/workspaces-shared-deps-virtual/packages/a", + "type": "workspace", + }, + }, + "location": "node_modules/a", + "name": "a", + "resolved": "file:../packages/a", + "target": Object { + "name": "a", + "parent": undefined, + }, + }, + "abbrev" => Node { + "edgesIn": Set { + Edge { + "from": "packages/a", + "name": "abbrev", + "spec": "^1.1.1", + "type": "prod", + }, + Edge { + "from": "packages/b", + "name": "abbrev", + "spec": "^1.1.1", + "type": "prod", + }, + }, + "location": "node_modules/abbrev", + "name": "abbrev", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + }, + "b" => Link { + "edgesIn": Set { + Edge { + "from": "", + "name": "b", + "spec": "file:{CWD}/test/fixtures/workspaces-shared-deps-virtual/packages/b", + "type": "workspace", + }, + }, + "location": "node_modules/b", + "name": "b", + "resolved": "file:../packages/b", + "target": Object { + "name": "b", + "parent": undefined, + }, + }, + "c" => Link { + "edgesIn": Set { + Edge { + "from": "", + "name": "c", + "spec": "file:{CWD}/test/fixtures/workspaces-shared-deps-virtual/packages/c", + "type": "workspace", + }, + }, + "location": "node_modules/c", + "name": "c", + "resolved": "file:../packages/c", + "target": Object { + "name": "c", + "parent": undefined, + }, + }, + "uuid" => Node { + "edgesIn": Set { + Edge { + "from": "packages/c", + "name": "uuid", + "spec": "=3.3.3", + "type": "prod", + }, + }, + "location": "node_modules/uuid", + "name": "uuid", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz", + }, + }, + "edgesOut": Map { + "a" => Edge { + "name": "a", + "spec": "file:{CWD}/test/fixtures/workspaces-shared-deps-virtual/packages/a", + "to": "node_modules/a", + "type": "workspace", + }, + "b" => Edge { + "name": "b", + "spec": "file:{CWD}/test/fixtures/workspaces-shared-deps-virtual/packages/b", + "to": "node_modules/b", + "type": "workspace", + }, + "c" => Edge { + "name": "c", + "spec": "file:{CWD}/test/fixtures/workspaces-shared-deps-virtual/packages/c", + "to": "node_modules/c", + "type": "workspace", + }, + }, + "location": "", + "name": "workspaces-shared-deps-virtual", + "resolved": null, +} +` diff --git a/tap-snapshots/test-arborist-reify.js-TAP.test.js b/tap-snapshots/test-arborist-reify.js-TAP.test.js index c564bb5b5..2fe428037 100644 --- a/tap-snapshots/test-arborist-reify.js-TAP.test.js +++ b/tap-snapshots/test-arborist-reify.js-TAP.test.js @@ -33323,3 +33323,201 @@ Node { "resolved": null, } ` + +exports[`test/arborist/reify.js TAP workspaces reify simple-workspaces > should reify simple workspaces 1`] = ` +Node { + "children": Map { + "a" => Link { + "edgesIn": Set { + Edge { + "from": "", + "name": "a", + "spec": "file:{CWD}/test/arborist/reify-workspaces-reify-simple-workspaces/a", + "type": "workspace", + }, + }, + "location": "node_modules/a", + "name": "a", + "resolved": "file:../a", + "target": Object { + "name": "a", + "parent": null, + }, + }, + "b" => Link { + "edgesIn": Set { + Edge { + "from": "", + "name": "b", + "spec": "file:{CWD}/test/arborist/reify-workspaces-reify-simple-workspaces/b", + "type": "workspace", + }, + Edge { + "from": "a", + "name": "b", + "spec": "^1.0.0", + "type": "prod", + }, + }, + "location": "node_modules/b", + "name": "b", + "resolved": "file:../b", + "target": Object { + "name": "b", + "parent": null, + }, + }, + }, + "edgesOut": Map { + "a" => Edge { + "name": "a", + "spec": "file:{CWD}/test/arborist/reify-workspaces-reify-simple-workspaces/a", + "to": "node_modules/a", + "type": "workspace", + }, + "b" => Edge { + "name": "b", + "spec": "file:{CWD}/test/arborist/reify-workspaces-reify-simple-workspaces/b", + "to": "node_modules/b", + "type": "workspace", + }, + }, + "fsChildren": Set { + Node { + "edgesOut": Map { + "b" => Edge { + "name": "b", + "spec": "^1.0.0", + "to": "node_modules/b", + "type": "prod", + }, + }, + "location": "a", + "name": "a", + "resolved": null, + }, + Node { + "location": "b", + "name": "b", + "resolved": null, + }, + }, + "location": "", + "name": "reify-workspaces-reify-simple-workspaces", + "resolved": null, +} +` + +exports[`test/arborist/reify.js TAP workspaces reify workspaces bin files > expect resolving Promise 1`] = ` +Node { + "children": Map { + "a" => Link { + "edgesIn": Set { + Edge { + "from": "", + "name": "a", + "spec": "file:{CWD}/test/arborist/reify-workspaces-reify-workspaces-bin-files/packages/a", + "type": "workspace", + }, + }, + "location": "node_modules/a", + "name": "a", + "resolved": "file:../packages/a", + "target": Object { + "name": "a", + "parent": null, + }, + }, + "b" => Link { + "edgesIn": Set { + Edge { + "from": "", + "name": "b", + "spec": "file:{CWD}/test/arborist/reify-workspaces-reify-workspaces-bin-files/packages/b", + "type": "workspace", + }, + }, + "location": "node_modules/b", + "name": "b", + "resolved": "file:../packages/b", + "target": Object { + "name": "b", + "parent": null, + }, + }, + }, + "edgesOut": Map { + "a" => Edge { + "name": "a", + "spec": "file:{CWD}/test/arborist/reify-workspaces-reify-workspaces-bin-files/packages/a", + "to": "node_modules/a", + "type": "workspace", + }, + "b" => Edge { + "name": "b", + "spec": "file:{CWD}/test/arborist/reify-workspaces-reify-workspaces-bin-files/packages/b", + "to": "node_modules/b", + "type": "workspace", + }, + }, + "fsChildren": Set { + Node { + "location": "packages/a", + "name": "a", + "resolved": null, + }, + Node { + "location": "packages/b", + "name": "b", + "resolved": null, + }, + }, + "location": "", + "name": "reify-workspaces-reify-workspaces-bin-files", + "resolved": null, +} +` + +exports[`test/arborist/reify.js TAP workspaces reify workspaces lockfile > should lock workspaces config 1`] = ` +Object { + "dependencies": Object { + "a": Object { + "version": "file:a", + }, + "b": Object { + "version": "file:b", + }, + }, + "lockfileVersion": 2, + "name": "workspace-simple", + "packages": Object { + "": Object { + "name": "workspace-simple", + "workspaces": Array [ + "a", + "b", + ], + }, + "a": Object { + "dependencies": Object { + "b": "^1.0.0", + }, + "name": "a", + "version": "1.0.0", + }, + "b": Object { + "name": "b", + "version": "1.0.0", + }, + "node_modules/a": Object { + "link": true, + "resolved": "a", + }, + "node_modules/b": Object { + "link": true, + "resolved": "b", + }, + }, + "requires": true, +} +` diff --git a/tap-snapshots/test-node.js-TAP.test.js b/tap-snapshots/test-node.js-TAP.test.js index 810e2e99a..7de4940de 100644 --- a/tap-snapshots/test-node.js-TAP.test.js +++ b/tap-snapshots/test-node.js-TAP.test.js @@ -31,6 +31,35 @@ Node { } ` +exports[`test/node.js TAP set workspaces > should setup edges out for each workspace 1`] = ` +Node { + "children": Map {}, + "dev": true, + "devOptional": true, + "edgesIn": Set {}, + "edgesOut": Map { + "foo" => Edge {}, + "bar" => Edge {}, + }, + "errors": Array [], + "extraneous": true, + "fsChildren": Set {}, + "hasShrinkwrap": false, + "integrity": null, + "inventory": Inventory {}, + "legacyPeerDeps": false, + "linksIn": Set {}, + "location": "", + "meta": undefined, + "name": "workspaces_root", + "optional": true, + "path": "/home/user/projects/workspaces_root", + "peer": true, + "realpath": "/home/user/projects/workspaces_root", + "resolved": null, +} +` + exports[`test/node.js TAP testing with dep tree with meta > add new meta under prod 1`] = ` Node { "children": Map { diff --git a/test/arborist/build-ideal-tree.js b/test/arborist/build-ideal-tree.js index 743e8b093..14a550752 100644 --- a/test/arborist/build-ideal-tree.js +++ b/test/arborist/build-ideal-tree.js @@ -1015,3 +1015,64 @@ t.test('no fix available, linked top package', async t => { "'cd ./mkdirp-unfixable' and run 'npm audit' for details." ]]) }) + +t.test('workspaces', t => { + t.test('should install a simple example', t => { + const path = resolve(__dirname, '../fixtures/workspaces-simple') + return t.resolveMatchSnapshot(printIdeal(path)) + }) + + t.test('should install a simple scoped pkg example', t => { + const path = resolve(__dirname, '../fixtures/workspaces-scoped-pkg') + return t.resolveMatchSnapshot(printIdeal(path)) + }) + + t.test('should not work with duplicate names', t => { + const path = resolve(__dirname, '../fixtures/workspaces-duplicate') + return t.rejects(printIdeal(path), { code: 'EDUPLICATEWORKSPACE' }, 'throws EDUPLICATEWORKSPACE error') + }) + + t.test('should install shared dependencies into root folder', t => { + const path = resolve(__dirname, '../fixtures/workspaces-shared-deps') + return t.resolveMatchSnapshot(printIdeal(path)) + }) + + t.test('should install conflicting dep versions', t => { + const path = resolve(__dirname, '../fixtures/workspaces-conflicting-versions') + return t.resolveMatchSnapshot(printIdeal(path)) + }) + + t.test('should prefer linking nested workspaces', t => { + const path = resolve(__dirname, '../fixtures/workspaces-prefer-linking') + return t.resolveMatchSnapshot(printIdeal(path)) + }) + + t.test('should install from registry on version not satisfied', t => { + const path = resolve(__dirname, '../fixtures/workspaces-version-unsatisfied') + return t.resolveMatchSnapshot(printIdeal(path)) + }) + + t.test('should link top level nested workspaces', t => { + const path = resolve(__dirname, '../fixtures/workspaces-top-level-link') + return t.resolveMatchSnapshot(printIdeal(path)) + }) + + t.test('should install workspace transitive dependencies', t => { + const path = resolve(__dirname, '../fixtures/workspaces-transitive-deps') + return t.resolveMatchSnapshot(printIdeal(path)) + }) + + t.test('should ignore nested node_modules folders', t => { + // packages/a/node_modules/nested-workspaces should not be installed + const path = resolve(__dirname, '../fixtures/workspaces-ignore-nm') + return t.resolveMatchSnapshot(printIdeal(path)) + }) + + t.test('should work with files spec', t => { + const path = resolve(__dirname, '../fixtures/workspaces-with-files-spec') + return t.resolveMatchSnapshot(printIdeal(path)) + }) + + t.end() +}) + diff --git a/test/arborist/load-virtual.js b/test/arborist/load-virtual.js index d870090d2..4abff3b82 100644 --- a/test/arborist/load-virtual.js +++ b/test/arborist/load-virtual.js @@ -146,3 +146,56 @@ t.test('load a tree with a bunch of bundles', t => t.test('load a tree with an empty dep set and a lockfile', t => loadVirtual(emptyFixture).then(tree => t.matchSnapshot(printTree(tree), 'virtual tree with no deps'))) + +t.test('workspaces', t => { + t.test('load a simple example', t => + loadVirtual( + resolve(__dirname, '../fixtures/workspaces-simple-virtual') + ).then(tree => + t.matchSnapshot(printTree(tree), 'virtual tree with multiple bundles'))) + + t.test('load shared dependencies example', t => + loadVirtual( + resolve(__dirname, '../fixtures/workspaces-shared-deps-virtual') + ).then(tree => + t.matchSnapshot(printTree(tree), 'virtual tree with shared dependencies'))) + + t.test('load conflicting dep versions example', t => + loadVirtual( + resolve(__dirname, '../fixtures/workspaces-conflicting-versions-virtual') + ).then(tree => + t.matchSnapshot(printTree(tree), 'virtual tree with resolved conflicting dependencies'))) + + t.test('load prefer linking nested workspaces', t => + loadVirtual( + resolve(__dirname, '../fixtures/workspaces-prefer-linking-virtual') + ).then(tree => + t.matchSnapshot(printTree(tree), 'virtual tree linking to local workspaces'))) + + t.test('load installed from registry on version not satisfied', t => + loadVirtual( + resolve(__dirname, '../fixtures/workspaces-version-unsatisfied-virtual') + ).then(tree => + t.matchSnapshot(printTree(tree), 'virtual tree with deduped dep'))) + + + t.test('load linked top level nested workspaces', t => + loadVirtual( + resolve(__dirname, '../fixtures/workspaces-top-level-link-virtual') + ).then(tree => + t.matchSnapshot(printTree(tree), 'virtual tree top level dep'))) + + t.test('load installed workspace with transitive dependencies', t => + loadVirtual( + resolve(__dirname, '../fixtures/workspaces-transitive-deps-virtual') + ).then(tree => + t.matchSnapshot(printTree(tree), 'virtual tree with transitive deps'))) + + t.test('load installed tree with ignored nested node_modules folders', t => + loadVirtual( + resolve(__dirname, '../fixtures/workspaces-ignore-nm-virtual') + ).then(tree => + t.matchSnapshot(printTree(tree), 'virtual tree ignoring nested node_modules'))) + + t.end() +}) diff --git a/test/arborist/reify.js b/test/arborist/reify.js index 3494c8218..3b92cd8e9 100644 --- a/test/arborist/reify.js +++ b/test/arborist/reify.js @@ -886,3 +886,38 @@ t.test('global', t => { t.end() }) + +t.test('workspaces', t => { + t.test('reify simple-workspaces', t => + t.resolveMatchSnapshot(printReified(fixture(t, 'workspaces-simple')), 'should reify simple workspaces')) + + t.test('reify workspaces lockfile', t => { + const path = fixture(t, 'workspaces-simple') + reify(path).then(() => { + t.matchSnapshot(require(path + '/package-lock.json'), 'should lock workspaces config') + t.end() + }) + }) + + t.test('reify workspaces bin files', t => { + const path = fixture(t, 'workspaces-link-bin') + + const bins = [ + resolve(path, 'node_modules/.bin/a'), + resolve(path, 'node_modules/.bin/b'), + ] + + const checkBin = () => { + for (const bin of bins) + if (process.platform === 'win32') + t.ok(fs.statSync(bin + '.cmd').isFile(), 'created shim') + else + t.ok(fs.lstatSync(bin).isSymbolicLink(), 'created symlink') + } + + return t.resolveMatchSnapshot(printReified(path, {})) + .then(checkBin) + }) + + t.end() +}) diff --git a/test/edge.js b/test/edge.js index 3a23c6216..10fdfb925 100644 --- a/test/edge.js +++ b/test/edge.js @@ -278,3 +278,9 @@ t.throws(() => new Edge({ name: 'foo', spec: '', }), new TypeError('must provide "from" node')) + +t.throws(() => new Edge({ + type: 'workspace', + name: 'foo', + spec: '*', +}), new TypeError('workspace edges must be a symlink')) diff --git a/test/fixtures/reify-cases/workspaces-link-bin.js b/test/fixtures/reify-cases/workspaces-link-bin.js new file mode 100644 index 000000000..52a8158e8 --- /dev/null +++ b/test/fixtures/reify-cases/workspaces-link-bin.js @@ -0,0 +1,38 @@ +// generated from test/fixtures/workspaces-link-bin +module.exports = t => ({ + "foo.js": "", + "package.json": JSON.stringify({ + "name": "workspace-duplicate", + "bin": "foo.js", + "workspaces": [ + "packages/*" + ], + "dependencies": { + "a": "*" + } + }), + "packages": { + "a": { + "file.js": "", + "package.json": JSON.stringify({ + "name": "a", + "version": "1.0.0", + "files": [ + "file.js" + ], + "bin": "file.js" + }) + }, + "b": { + "file.js": "", + "package.json": JSON.stringify({ + "name": "b", + "version": "1.0.0", + "files": [ + "file.js" + ], + "bin": "file.js" + }) + } + } +}) diff --git a/test/fixtures/reify-cases/workspaces-simple.js b/test/fixtures/reify-cases/workspaces-simple.js new file mode 100644 index 000000000..bc0f0e256 --- /dev/null +++ b/test/fixtures/reify-cases/workspaces-simple.js @@ -0,0 +1,25 @@ +// generated from test/fixtures/workspaces-simple +module.exports = t => ({ + "a": { + "package.json": JSON.stringify({ + "name": "a", + "version": "1.0.0", + "dependencies": { + "b": "^1.0.0" + } + }) + }, + "b": { + "package.json": JSON.stringify({ + "name": "b", + "version": "1.0.0" + }) + }, + "package.json": JSON.stringify({ + "name": "workspace-simple", + "workspaces": [ + "a", + "b" + ] + }) +}) diff --git a/test/fixtures/workspaces-conflicting-versions-virtual/package-lock.json b/test/fixtures/workspaces-conflicting-versions-virtual/package-lock.json new file mode 100644 index 000000000..03986615a --- /dev/null +++ b/test/fixtures/workspaces-conflicting-versions-virtual/package-lock.json @@ -0,0 +1,91 @@ +{ + "name": "workspaces-conflicting-deps", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "workspaces-conflicting-deps", + "version": "1.0.0", + "dependencies": { + "abbrev": "^1.1.1" + }, + "workspaces": { + "packages": [ + "packages/*" + ] + } + }, + "node_modules/a": { + "resolved": "packages/a", + "link": true + }, + "node_modules/abbrev": { + "name": "abbrev", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, + "node_modules/b": { + "resolved": "packages/b", + "link": true + }, + "packages/a": { + "name": "a", + "version": "1.0.0", + "dependencies": { + "abbrev": "=1.0.4" + } + }, + "packages/a/node_modules/abbrev": { + "name": "abbrev", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.4.tgz", + "integrity": "sha1-vVWuXkE7oXIu5Mq6H26hBBSlns0=" + }, + "packages/b": { + "name": "b", + "version": "1.0.0", + "dependencies": { + "abbrev": "=1.1.0" + } + }, + "packages/b/node_modules/abbrev": { + "name": "abbrev", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.0.tgz", + "integrity": "sha1-0FVMIlZjbi9W58LlrRg/hZQo2B8=" + } + }, + "dependencies": { + "a": { + "version": "file:packages/a" + }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, + "b": { + "version": "file:packages/b" + }, + "packages/a": { + "dependencies": { + "abbrev": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.4.tgz", + "integrity": "sha1-vVWuXkE7oXIu5Mq6H26hBBSlns0=" + } + } + }, + "packages/b": { + "dependencies": { + "abbrev": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.0.tgz", + "integrity": "sha1-0FVMIlZjbi9W58LlrRg/hZQo2B8=" + } + } + } + } +} diff --git a/test/fixtures/workspaces-conflicting-versions-virtual/package.json b/test/fixtures/workspaces-conflicting-versions-virtual/package.json new file mode 100644 index 000000000..651d43b5b --- /dev/null +++ b/test/fixtures/workspaces-conflicting-versions-virtual/package.json @@ -0,0 +1,10 @@ +{ + "name": "workspaces-conflicting-deps", + "version": "1.0.0", + "workspaces": [ + "packages/*" + ], + "dependencies": { + "abbrev": "^1.1.1" + } +} diff --git a/test/fixtures/workspaces-conflicting-versions/package.json b/test/fixtures/workspaces-conflicting-versions/package.json new file mode 100644 index 000000000..447380094 --- /dev/null +++ b/test/fixtures/workspaces-conflicting-versions/package.json @@ -0,0 +1,11 @@ +{ + "name": "workspaces-conflicting-deps", + "version": "1.0.0", + "workspaces": [ + "packages/*" + ], + "dependencies": { + "abbrev": "^1.1.1" + } +} + diff --git a/test/fixtures/workspaces-conflicting-versions/packages/a/package.json b/test/fixtures/workspaces-conflicting-versions/packages/a/package.json new file mode 100644 index 000000000..f9904d309 --- /dev/null +++ b/test/fixtures/workspaces-conflicting-versions/packages/a/package.json @@ -0,0 +1,7 @@ +{ + "name": "a", + "version": "1.0.0", + "dependencies": { + "abbrev": "=1.0.4" + } +} diff --git a/test/fixtures/workspaces-conflicting-versions/packages/b/package.json b/test/fixtures/workspaces-conflicting-versions/packages/b/package.json new file mode 100644 index 000000000..a3440f267 --- /dev/null +++ b/test/fixtures/workspaces-conflicting-versions/packages/b/package.json @@ -0,0 +1,7 @@ +{ + "name": "b", + "version": "1.0.0", + "dependencies": { + "abbrev": "=1.1.0" + } +} diff --git a/test/fixtures/workspaces-duplicate/package.json b/test/fixtures/workspaces-duplicate/package.json new file mode 100644 index 000000000..985971c00 --- /dev/null +++ b/test/fixtures/workspaces-duplicate/package.json @@ -0,0 +1,6 @@ +{ + "name": "workspace-duplicate", + "workspaces": [ + "packages/*" + ] +} diff --git a/test/fixtures/workspaces-duplicate/packages/a/package.json b/test/fixtures/workspaces-duplicate/packages/a/package.json new file mode 100644 index 000000000..9113c2528 --- /dev/null +++ b/test/fixtures/workspaces-duplicate/packages/a/package.json @@ -0,0 +1,4 @@ +{ + "name": "a", + "version": "1.0.0" +} diff --git a/test/fixtures/workspaces-duplicate/packages/b/package.json b/test/fixtures/workspaces-duplicate/packages/b/package.json new file mode 100644 index 000000000..9113c2528 --- /dev/null +++ b/test/fixtures/workspaces-duplicate/packages/b/package.json @@ -0,0 +1,4 @@ +{ + "name": "a", + "version": "1.0.0" +} diff --git a/test/fixtures/workspaces-ignore-nm-virtual/package-lock.json b/test/fixtures/workspaces-ignore-nm-virtual/package-lock.json new file mode 100644 index 000000000..c56b75472 --- /dev/null +++ b/test/fixtures/workspaces-ignore-nm-virtual/package-lock.json @@ -0,0 +1,28 @@ +{ + "name": "workspace-ignore-nm", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "workspace-ignore-nm", + "workspaces": { + "packages": [ + "packages/**" + ] + } + }, + "node_modules/a": { + "resolved": "packages/a", + "link": true + }, + "packages/a": { + "name": "a", + "version": "1.0.0" + } + }, + "dependencies": { + "a": { + "version": "file:packages/a" + } + } +} diff --git a/test/fixtures/workspaces-ignore-nm-virtual/package.json b/test/fixtures/workspaces-ignore-nm-virtual/package.json new file mode 100644 index 000000000..5d63a1514 --- /dev/null +++ b/test/fixtures/workspaces-ignore-nm-virtual/package.json @@ -0,0 +1,6 @@ +{ + "name": "workspace-ignore-nm", + "workspaces": [ + "packages/**" + ] +} diff --git a/test/fixtures/workspaces-ignore-nm/package.json b/test/fixtures/workspaces-ignore-nm/package.json new file mode 100644 index 000000000..be7d871a6 --- /dev/null +++ b/test/fixtures/workspaces-ignore-nm/package.json @@ -0,0 +1,7 @@ +{ + "name": "workspace-ignore-nm", + "workspaces": [ + "packages/**" + ] +} + diff --git a/test/fixtures/workspaces-ignore-nm/packages/a/node_modules/c/package.json b/test/fixtures/workspaces-ignore-nm/packages/a/node_modules/c/package.json new file mode 100644 index 000000000..abd338493 --- /dev/null +++ b/test/fixtures/workspaces-ignore-nm/packages/a/node_modules/c/package.json @@ -0,0 +1,4 @@ +{ + "name": "c", + "version": "1.0.0" +} diff --git a/test/fixtures/workspaces-ignore-nm/packages/a/node_modules/nested-workspace/d/package.json b/test/fixtures/workspaces-ignore-nm/packages/a/node_modules/nested-workspace/d/package.json new file mode 100644 index 000000000..ebbfbae0d --- /dev/null +++ b/test/fixtures/workspaces-ignore-nm/packages/a/node_modules/nested-workspace/d/package.json @@ -0,0 +1,7 @@ +{ + "name": "d", + "version": "1.0.0", + "dependencies": { + "abbrev": "^1.1.1" + } +} diff --git a/test/fixtures/workspaces-ignore-nm/packages/a/node_modules/nested-workspace/package.json b/test/fixtures/workspaces-ignore-nm/packages/a/node_modules/nested-workspace/package.json new file mode 100644 index 000000000..b156dca8f --- /dev/null +++ b/test/fixtures/workspaces-ignore-nm/packages/a/node_modules/nested-workspace/package.json @@ -0,0 +1,7 @@ +{ + "name": "nested-workspace", + "version": "1.0.0", + "workspaces": [ + "./d" + ] +} diff --git a/test/fixtures/workspaces-ignore-nm/packages/a/package.json b/test/fixtures/workspaces-ignore-nm/packages/a/package.json new file mode 100644 index 000000000..8fe98232f --- /dev/null +++ b/test/fixtures/workspaces-ignore-nm/packages/a/package.json @@ -0,0 +1,5 @@ +{ + "name": "a", + "version": "1.0.0" +} + diff --git a/test/fixtures/workspaces-link-bin/foo.js b/test/fixtures/workspaces-link-bin/foo.js new file mode 100644 index 000000000..e69de29bb diff --git a/test/fixtures/workspaces-link-bin/package.json b/test/fixtures/workspaces-link-bin/package.json new file mode 100644 index 000000000..d3560fc73 --- /dev/null +++ b/test/fixtures/workspaces-link-bin/package.json @@ -0,0 +1,10 @@ +{ + "name": "workspace-duplicate", + "bin": "foo.js", + "workspaces": [ + "packages/*" + ], + "dependencies": { + "a": "*" + } +} diff --git a/test/fixtures/workspaces-link-bin/packages/a/file.js b/test/fixtures/workspaces-link-bin/packages/a/file.js new file mode 100644 index 000000000..e69de29bb diff --git a/test/fixtures/workspaces-link-bin/packages/a/package.json b/test/fixtures/workspaces-link-bin/packages/a/package.json new file mode 100644 index 000000000..c8fa2d1d7 --- /dev/null +++ b/test/fixtures/workspaces-link-bin/packages/a/package.json @@ -0,0 +1,6 @@ +{ + "name": "a", + "version": "1.0.0", + "files": ["file.js"], + "bin": "file.js" +} diff --git a/test/fixtures/workspaces-link-bin/packages/b/file.js b/test/fixtures/workspaces-link-bin/packages/b/file.js new file mode 100644 index 000000000..e69de29bb diff --git a/test/fixtures/workspaces-link-bin/packages/b/package.json b/test/fixtures/workspaces-link-bin/packages/b/package.json new file mode 100644 index 000000000..52a65b6fa --- /dev/null +++ b/test/fixtures/workspaces-link-bin/packages/b/package.json @@ -0,0 +1,6 @@ +{ + "name": "b", + "version": "1.0.0", + "files": ["file.js"], + "bin": "file.js" +} diff --git a/test/fixtures/workspaces-prefer-linking-virtual/package-lock.json b/test/fixtures/workspaces-prefer-linking-virtual/package-lock.json new file mode 100644 index 000000000..53b4e2d51 --- /dev/null +++ b/test/fixtures/workspaces-prefer-linking-virtual/package-lock.json @@ -0,0 +1,42 @@ +{ + "name": "workspaces-prefer-linking", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "workspaces-prefer-linking", + "version": "1.0.0", + "workspaces": [ + "packages/*" + ] + }, + "node_modules/a": { + "resolved": "packages/a", + "link": true + }, + "node_modules/abbrev": { + "resolved": "packages/abbrev", + "link": true + }, + "packages/a": { + "name": "a", + "version": "1.0.0", + "dependencies": { + "abbrev": "*" + } + }, + "packages/abbrev": { + "name": "abbrev", + "version": "2.0.0" + } + }, + "dependencies": { + "a": { + "version": "file:packages/a" + }, + "abbrev": { + "version": "file:packages/abbrev" + } + } +} diff --git a/test/fixtures/workspaces-prefer-linking-virtual/package.json b/test/fixtures/workspaces-prefer-linking-virtual/package.json new file mode 100644 index 000000000..6a15efe53 --- /dev/null +++ b/test/fixtures/workspaces-prefer-linking-virtual/package.json @@ -0,0 +1,7 @@ +{ + "name": "workspaces-prefer-linking", + "version": "1.0.0", + "workspaces": [ + "packages/*" + ] +} diff --git a/test/fixtures/workspaces-prefer-linking/package.json b/test/fixtures/workspaces-prefer-linking/package.json new file mode 100644 index 000000000..6a15efe53 --- /dev/null +++ b/test/fixtures/workspaces-prefer-linking/package.json @@ -0,0 +1,7 @@ +{ + "name": "workspaces-prefer-linking", + "version": "1.0.0", + "workspaces": [ + "packages/*" + ] +} diff --git a/test/fixtures/workspaces-prefer-linking/packages/a/package.json b/test/fixtures/workspaces-prefer-linking/packages/a/package.json new file mode 100644 index 000000000..7d15acabe --- /dev/null +++ b/test/fixtures/workspaces-prefer-linking/packages/a/package.json @@ -0,0 +1,7 @@ +{ + "name": "a", + "version": "1.0.0", + "dependencies": { + "abbrev": "*" + } +} diff --git a/test/fixtures/workspaces-prefer-linking/packages/abbrev/package.json b/test/fixtures/workspaces-prefer-linking/packages/abbrev/package.json new file mode 100644 index 000000000..36b0d44ae --- /dev/null +++ b/test/fixtures/workspaces-prefer-linking/packages/abbrev/package.json @@ -0,0 +1,6 @@ +{ + "name": "abbrev", + "version": "2.0.0", + "description": "Like ruby's abbrev module, but in js", + "author": "Isaac Z. Schlueter " +} diff --git a/test/fixtures/workspaces-scoped-pkg/package.json b/test/fixtures/workspaces-scoped-pkg/package.json new file mode 100644 index 000000000..695f4a49e --- /dev/null +++ b/test/fixtures/workspaces-scoped-pkg/package.json @@ -0,0 +1,6 @@ +{ + "name": "workspace-simple", + "workspaces": [ + "packages/*" + ] +} diff --git a/test/fixtures/workspaces-scoped-pkg/packages/a/package.json b/test/fixtures/workspaces-scoped-pkg/packages/a/package.json new file mode 100644 index 000000000..cc566d017 --- /dev/null +++ b/test/fixtures/workspaces-scoped-pkg/packages/a/package.json @@ -0,0 +1,7 @@ +{ + "name": "@ruyadorno/scoped-a", + "version": "1.0.0", + "dependencies": { + "@ruyadorno/scoped-b": "^1.0.0" + } +} diff --git a/test/fixtures/workspaces-scoped-pkg/packages/b/package.json b/test/fixtures/workspaces-scoped-pkg/packages/b/package.json new file mode 100644 index 000000000..3b48f952e --- /dev/null +++ b/test/fixtures/workspaces-scoped-pkg/packages/b/package.json @@ -0,0 +1,4 @@ +{ + "name": "@ruyadorno/scoped-b", + "version": "1.0.0" +} diff --git a/test/fixtures/workspaces-shared-deps-virtual/package-lock.json b/test/fixtures/workspaces-shared-deps-virtual/package-lock.json new file mode 100644 index 000000000..3d77c2f42 --- /dev/null +++ b/test/fixtures/workspaces-shared-deps-virtual/package-lock.json @@ -0,0 +1,86 @@ +{ + "name": "workspaces-shared-deps", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "workspaces-shared-deps", + "version": "1.0.0", + "workspaces": { + "packages": [ + "packages/*" + ] + } + }, + "node_modules/a": { + "resolved": "packages/a", + "link": true + }, + "node_modules/abbrev": { + "name": "abbrev", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, + "node_modules/b": { + "resolved": "packages/b", + "link": true + }, + "node_modules/c": { + "resolved": "packages/c", + "link": true + }, + "node_modules/uuid": { + "name": "uuid", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz", + "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==", + "bin": { + "uuid": "bin/uuid" + } + }, + "packages/a": { + "name": "a", + "version": "1.0.0", + "dependencies": { + "abbrev": "^1.1.1" + } + }, + "packages/b": { + "name": "b", + "version": "1.0.0", + "dependencies": { + "abbrev": "^1.1.1" + } + }, + "packages/c": { + "name": "c", + "version": "1.0.0", + "dependencies": { + "uuid": "=3.3.3" + } + } + }, + "dependencies": { + "a": { + "version": "file:packages/a" + }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, + "b": { + "version": "file:packages/b" + }, + "c": { + "version": "file:packages/c" + }, + "uuid": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz", + "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==" + } + } +} diff --git a/test/fixtures/workspaces-shared-deps-virtual/package.json b/test/fixtures/workspaces-shared-deps-virtual/package.json new file mode 100644 index 000000000..4c634a1e0 --- /dev/null +++ b/test/fixtures/workspaces-shared-deps-virtual/package.json @@ -0,0 +1,7 @@ +{ + "name": "workspaces-shared-deps", + "version": "1.0.0", + "workspaces": [ + "packages/*" + ] +} diff --git a/test/fixtures/workspaces-shared-deps/package.json b/test/fixtures/workspaces-shared-deps/package.json new file mode 100644 index 000000000..4c634a1e0 --- /dev/null +++ b/test/fixtures/workspaces-shared-deps/package.json @@ -0,0 +1,7 @@ +{ + "name": "workspaces-shared-deps", + "version": "1.0.0", + "workspaces": [ + "packages/*" + ] +} diff --git a/test/fixtures/workspaces-shared-deps/packages/a/package.json b/test/fixtures/workspaces-shared-deps/packages/a/package.json new file mode 100644 index 000000000..7a2d0d4df --- /dev/null +++ b/test/fixtures/workspaces-shared-deps/packages/a/package.json @@ -0,0 +1,7 @@ +{ + "name": "a", + "version": "1.0.0", + "dependencies": { + "abbrev": "^1.1.1" + } +} diff --git a/test/fixtures/workspaces-shared-deps/packages/b/package.json b/test/fixtures/workspaces-shared-deps/packages/b/package.json new file mode 100644 index 000000000..4c9154387 --- /dev/null +++ b/test/fixtures/workspaces-shared-deps/packages/b/package.json @@ -0,0 +1,7 @@ +{ + "name": "b", + "version": "1.0.0", + "dependencies": { + "abbrev": "^1.1.1" + } +} diff --git a/test/fixtures/workspaces-shared-deps/packages/c/package.json b/test/fixtures/workspaces-shared-deps/packages/c/package.json new file mode 100644 index 000000000..7f017b6a5 --- /dev/null +++ b/test/fixtures/workspaces-shared-deps/packages/c/package.json @@ -0,0 +1,7 @@ +{ + "name": "c", + "version": "1.0.0", + "dependencies": { + "uuid": "=3.3.3" + } +} diff --git a/test/fixtures/workspaces-simple-virtual/a/package.json b/test/fixtures/workspaces-simple-virtual/a/package.json new file mode 100644 index 000000000..0dd22e08b --- /dev/null +++ b/test/fixtures/workspaces-simple-virtual/a/package.json @@ -0,0 +1,7 @@ +{ + "name": "a", + "version": "1.0.0", + "dependencies": { + "b": "^1.0.0" + } +} diff --git a/test/fixtures/workspaces-simple-virtual/b/package.json b/test/fixtures/workspaces-simple-virtual/b/package.json new file mode 100644 index 000000000..c2d84cc12 --- /dev/null +++ b/test/fixtures/workspaces-simple-virtual/b/package.json @@ -0,0 +1,4 @@ +{ + "name": "b", + "version": "1.0.0" +} diff --git a/test/fixtures/workspaces-simple-virtual/package-lock.json b/test/fixtures/workspaces-simple-virtual/package-lock.json new file mode 100644 index 000000000..dc8021e80 --- /dev/null +++ b/test/fixtures/workspaces-simple-virtual/package-lock.json @@ -0,0 +1,43 @@ +{ + "name": "workspace-simple", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "workspace-simple", + "workspaces": { + "packages": [ + "a", + "b" + ] + } + }, + "a": { + "name": "a", + "version": "1.0.0", + "dependencies": { + "b": "^1.0.0" + } + }, + "b": { + "name": "b", + "version": "1.0.0" + }, + "node_modules/a": { + "resolved": "a", + "link": true + }, + "node_modules/b": { + "resolved": "b", + "link": true + } + }, + "dependencies": { + "a": { + "version": "file:a" + }, + "b": { + "version": "file:b" + } + } +} diff --git a/test/fixtures/workspaces-simple-virtual/package.json b/test/fixtures/workspaces-simple-virtual/package.json new file mode 100644 index 000000000..6fb34c3f2 --- /dev/null +++ b/test/fixtures/workspaces-simple-virtual/package.json @@ -0,0 +1,7 @@ +{ + "name": "workspace-simple", + "workspaces": [ + "a", + "b" + ] +} diff --git a/test/fixtures/workspaces-simple/a/package.json b/test/fixtures/workspaces-simple/a/package.json new file mode 100644 index 000000000..0dd22e08b --- /dev/null +++ b/test/fixtures/workspaces-simple/a/package.json @@ -0,0 +1,7 @@ +{ + "name": "a", + "version": "1.0.0", + "dependencies": { + "b": "^1.0.0" + } +} diff --git a/test/fixtures/workspaces-simple/b/package.json b/test/fixtures/workspaces-simple/b/package.json new file mode 100644 index 000000000..c2d84cc12 --- /dev/null +++ b/test/fixtures/workspaces-simple/b/package.json @@ -0,0 +1,4 @@ +{ + "name": "b", + "version": "1.0.0" +} diff --git a/test/fixtures/workspaces-simple/package.json b/test/fixtures/workspaces-simple/package.json new file mode 100644 index 000000000..6fb34c3f2 --- /dev/null +++ b/test/fixtures/workspaces-simple/package.json @@ -0,0 +1,7 @@ +{ + "name": "workspace-simple", + "workspaces": [ + "a", + "b" + ] +} diff --git a/test/fixtures/workspaces-top-level-link-virtual/package-lock.json b/test/fixtures/workspaces-top-level-link-virtual/package-lock.json new file mode 100644 index 000000000..1114c807c --- /dev/null +++ b/test/fixtures/workspaces-top-level-link-virtual/package-lock.json @@ -0,0 +1,33 @@ +{ + "name": "workspaces-top-level-link", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "workspaces-top-level-link", + "version": "1.0.0", + "dependencies": { + "a": "^1.0.0" + }, + "workspaces": { + "packages": [ + "packages/*" + ] + } + }, + "node_modules/a": { + "resolved": "packages/a", + "link": true + }, + "packages/a": { + "name": "a", + "version": "1.0.0" + } + }, + "dependencies": { + "a": { + "version": "file:packages/a" + } + } +} diff --git a/test/fixtures/workspaces-top-level-link-virtual/package.json b/test/fixtures/workspaces-top-level-link-virtual/package.json new file mode 100644 index 000000000..2d2564945 --- /dev/null +++ b/test/fixtures/workspaces-top-level-link-virtual/package.json @@ -0,0 +1,10 @@ +{ + "name": "workspaces-top-level-link", + "version": "1.0.0", + "workspaces": [ + "packages/*" + ], + "dependencies": { + "a": "^1.0.0" + } +} diff --git a/test/fixtures/workspaces-top-level-link/package.json b/test/fixtures/workspaces-top-level-link/package.json new file mode 100644 index 000000000..aaa2088e4 --- /dev/null +++ b/test/fixtures/workspaces-top-level-link/package.json @@ -0,0 +1,11 @@ +{ + "name": "workspaces-top-level-link", + "version": "1.0.0", + "workspaces": [ + "packages/*" + ], + "dependencies": { + "a": "^1.0.0" + } +} + diff --git a/test/fixtures/workspaces-top-level-link/packages/a/package.json b/test/fixtures/workspaces-top-level-link/packages/a/package.json new file mode 100644 index 000000000..8fe98232f --- /dev/null +++ b/test/fixtures/workspaces-top-level-link/packages/a/package.json @@ -0,0 +1,5 @@ +{ + "name": "a", + "version": "1.0.0" +} + diff --git a/test/fixtures/workspaces-transitive-deps-virtual/package-lock.json b/test/fixtures/workspaces-transitive-deps-virtual/package-lock.json new file mode 100644 index 000000000..8e939d83e --- /dev/null +++ b/test/fixtures/workspaces-transitive-deps-virtual/package-lock.json @@ -0,0 +1,63 @@ +{ + "name": "workspaces-transitive-deps", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "workspaces-transitive-deps", + "version": "1.0.0", + "workspaces": [ + "packages/*" + ] + }, + "node_modules/a": { + "resolved": "packages/a", + "link": true + }, + "node_modules/once": { + "name": "once", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/wrappy": { + "name": "wrappy", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "packages/a": { + "name": "a", + "version": "1.0.0", + "devDependencies": { + "once": "^1.4.0" + } + } + }, + "dependencies": { + "a": { + "version": "file:packages/a" + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + } + } +} diff --git a/test/fixtures/workspaces-transitive-deps-virtual/package.json b/test/fixtures/workspaces-transitive-deps-virtual/package.json new file mode 100644 index 000000000..91c627055 --- /dev/null +++ b/test/fixtures/workspaces-transitive-deps-virtual/package.json @@ -0,0 +1,7 @@ +{ + "name": "workspaces-transitive-deps", + "version": "1.0.0", + "workspaces": [ + "packages/*" + ] +} diff --git a/test/fixtures/workspaces-transitive-deps/package.json b/test/fixtures/workspaces-transitive-deps/package.json new file mode 100644 index 000000000..91c627055 --- /dev/null +++ b/test/fixtures/workspaces-transitive-deps/package.json @@ -0,0 +1,7 @@ +{ + "name": "workspaces-transitive-deps", + "version": "1.0.0", + "workspaces": [ + "packages/*" + ] +} diff --git a/test/fixtures/workspaces-transitive-deps/packages/a/package.json b/test/fixtures/workspaces-transitive-deps/packages/a/package.json new file mode 100644 index 000000000..b1d8baa8c --- /dev/null +++ b/test/fixtures/workspaces-transitive-deps/packages/a/package.json @@ -0,0 +1,7 @@ +{ + "name": "a", + "version": "1.0.0", + "devDependencies": { + "once": "^1.4.0" + } +} diff --git a/test/fixtures/workspaces-version-unsatisfied-virtual/package-lock.json b/test/fixtures/workspaces-version-unsatisfied-virtual/package-lock.json new file mode 100644 index 000000000..eeca401bd --- /dev/null +++ b/test/fixtures/workspaces-version-unsatisfied-virtual/package-lock.json @@ -0,0 +1,59 @@ +{ + "name": "workspaces-version-unsatisfied", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "workspaces-version-unsatisfied", + "version": "1.0.0", + "workspaces": { + "packages": [ + "packages/*" + ] + } + }, + "node_modules/a": { + "resolved": "packages/a", + "link": true + }, + "node_modules/abbrev": { + "resolved": "packages/abbrev", + "link": true + }, + "packages/a": { + "name": "a", + "version": "1.0.0", + "dependencies": { + "abbrev": "=1.1.1" + } + }, + "packages/a/node_modules/abbrev": { + "name": "abbrev", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, + "packages/abbrev": { + "name": "abbrev", + "version": "2.0.0" + } + }, + "dependencies": { + "a": { + "version": "file:packages/a" + }, + "abbrev": { + "version": "file:packages/abbrev" + }, + "packages/a": { + "dependencies": { + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + } + } + } + } +} diff --git a/test/fixtures/workspaces-version-unsatisfied-virtual/package.json b/test/fixtures/workspaces-version-unsatisfied-virtual/package.json new file mode 100644 index 000000000..6622e0690 --- /dev/null +++ b/test/fixtures/workspaces-version-unsatisfied-virtual/package.json @@ -0,0 +1,7 @@ +{ + "name": "workspaces-version-unsatisfied", + "version": "1.0.0", + "workspaces": [ + "packages/*" + ] +} diff --git a/test/fixtures/workspaces-version-unsatisfied/package.json b/test/fixtures/workspaces-version-unsatisfied/package.json new file mode 100644 index 000000000..48a2cffa1 --- /dev/null +++ b/test/fixtures/workspaces-version-unsatisfied/package.json @@ -0,0 +1,8 @@ +{ + "name": "workspaces-version-unsatisfied", + "version": "1.0.0", + "workspaces": [ + "packages/*" + ] +} + diff --git a/test/fixtures/workspaces-version-unsatisfied/packages/a/package.json b/test/fixtures/workspaces-version-unsatisfied/packages/a/package.json new file mode 100644 index 000000000..925ed61e5 --- /dev/null +++ b/test/fixtures/workspaces-version-unsatisfied/packages/a/package.json @@ -0,0 +1,7 @@ +{ + "name": "a", + "version": "1.0.0", + "dependencies": { + "abbrev": "=1.1.1" + } +} diff --git a/test/fixtures/workspaces-version-unsatisfied/packages/abbrev/package.json b/test/fixtures/workspaces-version-unsatisfied/packages/abbrev/package.json new file mode 100644 index 000000000..36b0d44ae --- /dev/null +++ b/test/fixtures/workspaces-version-unsatisfied/packages/abbrev/package.json @@ -0,0 +1,6 @@ +{ + "name": "abbrev", + "version": "2.0.0", + "description": "Like ruby's abbrev module, but in js", + "author": "Isaac Z. Schlueter " +} diff --git a/test/fixtures/workspaces-with-files-spec/d/package.json b/test/fixtures/workspaces-with-files-spec/d/package.json new file mode 100644 index 000000000..391cb7e1e --- /dev/null +++ b/test/fixtures/workspaces-with-files-spec/d/package.json @@ -0,0 +1,7 @@ +{ + "name": "d", + "version": "1.0.0", + "dependencies": { + "b": "^1.0.0" + } +} diff --git a/test/fixtures/workspaces-with-files-spec/package.json b/test/fixtures/workspaces-with-files-spec/package.json new file mode 100644 index 000000000..55838a6c9 --- /dev/null +++ b/test/fixtures/workspaces-with-files-spec/package.json @@ -0,0 +1,11 @@ +{ + "name": "workspaces-with-files-spec", + "workspaces": [ + "packages/*", + "!packages/c" + ], + "dependencies": { + "c": "file:packages/c", + "d": "file:d" + } +} diff --git a/test/fixtures/workspaces-with-files-spec/packages/a/package.json b/test/fixtures/workspaces-with-files-spec/packages/a/package.json new file mode 100644 index 000000000..e3dcbda8f --- /dev/null +++ b/test/fixtures/workspaces-with-files-spec/packages/a/package.json @@ -0,0 +1,7 @@ +{ + "name": "a", + "version": "1.0.0", + "dependencies": { + "d": "^1.0.0" + } +} diff --git a/test/fixtures/workspaces-with-files-spec/packages/b/package.json b/test/fixtures/workspaces-with-files-spec/packages/b/package.json new file mode 100644 index 000000000..c2d84cc12 --- /dev/null +++ b/test/fixtures/workspaces-with-files-spec/packages/b/package.json @@ -0,0 +1,4 @@ +{ + "name": "b", + "version": "1.0.0" +} diff --git a/test/fixtures/workspaces-with-files-spec/packages/c/package.json b/test/fixtures/workspaces-with-files-spec/packages/c/package.json new file mode 100644 index 000000000..abd338493 --- /dev/null +++ b/test/fixtures/workspaces-with-files-spec/packages/c/package.json @@ -0,0 +1,4 @@ +{ + "name": "c", + "version": "1.0.0" +} diff --git a/test/node.js b/test/node.js index 389e6e3c4..d824c5f67 100644 --- a/test/node.js +++ b/test/node.js @@ -1134,6 +1134,7 @@ t.test('has install script', t => { t.end() }) + t.test('legacy peer dependencies', t => { const root = new Node({ pkg: { @@ -1162,3 +1163,75 @@ t.test('legacy peer dependencies', t => { t.equal(root.edgesOut.size, 0, 'should have no edges out') t.end() }) + +t.test('set workspaces', t => { + const root = new Node({ + pkg: { name: 'workspaces_root' }, + path: '/home/user/projects/workspaces_root', + realpath: '/home/user/projects/workspaces_root', + }) + + root.workspaces = new Map([ + ['foo', '/home/user/projects/workspaces_root/foo'], + ['bar', '/home/user/projects/workspaces_root/bar'], + ]) + + t.matchSnapshot(root, 'should setup edges out for each workspace') + t.end() +}) + +t.test('get workspaces', t => { + const root = new Node({ + pkg: { name: 'workspaces_root' }, + path: '/home/user/projects/workspaces_root', + realpath: '/home/user/projects/workspaces_root', + }) + + t.equal(root.workspaces, null, 'should default to null when no workspaces defined') + + const ws = new Map() + root.workspaces = ws + + t.equal(root.workspaces, ws, 'should match set value') + t.end() +}) + +t.test('replace workspaces', t => { + const root = new Node({ + pkg: { name: 'workspaces_root' }, + path: '/home/user/projects/workspaces_root', + realpath: '/home/user/projects/workspaces_root', + }) + + root.workspaces = new Map([ + ['foo', '/home/user/projects/workspaces_root/foo'], + ['bar', '/home/user/projects/workspaces_root/bar'], + ]) + + const ws = new Map() + root.workspaces = ws + + t.equal(root.workspaces, ws, 'should remove previously set workspaces') + t.end() +}) + +t.test('replace workspaces keeping existing edges out', t => { + const root = new Node({ + pkg: { name: 'workspaces_root' }, + path: '/home/user/projects/workspaces_root', + realpath: '/home/user/projects/workspaces_root', + }) + + root.workspaces = new Map([ + ['foo', '/home/user/projects/workspaces_root/foo'], + ]) + + const ws = new Map([ + ['foo', '/home/user/projects/workspaces_root/foo'], + ['bar', '/home/user/projects/workspaces_root/bar'], + ]) + root.workspaces = ws + + t.equal(root.workspaces, ws, 'should keep existing edges out') + t.end() +})