diff --git a/.circleci/config.yml b/.circleci/config.yml index 8ae1926ed5..0a97ac23ce 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -117,7 +117,6 @@ jobs: command: | brew uninstall --ignore-dependencies node HOMEBREW_NO_AUTO_UPDATE=1 brew install node@8 - yarn global add node-gyp - *attach_workspace - *test_build - *test_run @@ -130,7 +129,6 @@ jobs: brew uninstall --ignore-dependencies node HOMEBREW_NO_AUTO_UPDATE=1 brew install node@6 brew link --force node@6 - yarn global add node-gyp - *attach_workspace - *test_build - *test_run diff --git a/__tests__/__mocks__/npm-registry.js b/__tests__/__mocks__/npm-registry.js new file mode 100644 index 0000000000..c5f54cb2a7 --- /dev/null +++ b/__tests__/__mocks__/npm-registry.js @@ -0,0 +1,10 @@ +/* @flow */ + +import Registry from '../../src/registries/base-registry.js'; +import type {RegistryRequestOptions} from '../../src/registries/base-registry.js'; + +export default class NpmRegistry extends Registry { + request(pathname: string, opts?: RegistryRequestOptions = {}, packageName: ?string): Promise<*> { + return new Promise(resolve => resolve()); + } +} diff --git a/__tests__/__snapshots__/index.js.snap b/__tests__/__snapshots__/index.js.snap new file mode 100644 index 0000000000..c7154dd81b --- /dev/null +++ b/__tests__/__snapshots__/index.js.snap @@ -0,0 +1,78 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`should add lockfile package 1`] = ` +Array [ + "info No lockfile found.", + "[1/4] Resolving packages...", + "[2/4] Fetching packages...", + "[3/4] Linking dependencies...", + "[4/4] Building fresh packages...", + "success Saved lockfile.", + "success Saved 1 new dependency.", + "info Direct dependencies", + "└─ lockfile@1.0.3", + "info All dependencies", + "└─ lockfile@1.0.3", +] +`; + +exports[`should add package 1`] = ` +Array [ + "info No lockfile found.", + "[1/4] Resolving packages...", + "[2/4] Fetching packages...", + "[3/4] Linking dependencies...", + "[4/4] Building fresh packages...", + "success Saved lockfile.", + "success Saved 1 new dependency.", + "info Direct dependencies", + "└─ left-pad@1.2.0", + "info All dependencies", + "└─ left-pad@1.2.0", +] +`; + +exports[`should add package with frozen-lockfile option 1`] = ` +Array [ + "info No lockfile found.", + "[1/4] Resolving packages...", + "[2/4] Fetching packages...", + "[3/4] Linking dependencies...", + "[4/4] Building fresh packages...", + "success Saved 1 new dependency.", + "info Direct dependencies", + "└─ repeating@3.0.0", + "info All dependencies", + "└─ repeating@3.0.0", +] +`; + +exports[`should add package with no-lockfile option 1`] = ` +Array [ + "info No lockfile found.", + "[1/4] Resolving packages...", + "[2/4] Fetching packages...", + "[3/4] Linking dependencies...", + "[4/4] Building fresh packages...", + "success Saved 1 new dependency.", + "info Direct dependencies", + "└─ repeating@3.0.0", + "info All dependencies", + "└─ repeating@3.0.0", +] +`; + +exports[`should add package with no-lockfile option in front 1`] = ` +Array [ + "info No lockfile found.", + "[1/4] Resolving packages...", + "[2/4] Fetching packages...", + "[3/4] Linking dependencies...", + "[4/4] Building fresh packages...", + "success Saved 1 new dependency.", + "info Direct dependencies", + "└─ split-lines@1.1.0", + "info All dependencies", + "└─ split-lines@1.1.0", +] +`; diff --git a/__tests__/__snapshots__/integration.js.snap b/__tests__/__snapshots__/integration.js.snap index 88b894d032..e736395656 100644 --- a/__tests__/__snapshots__/integration.js.snap +++ b/__tests__/__snapshots__/integration.js.snap @@ -8,5 +8,8 @@ exports[`yarnrc-args 1`] = ` {\\"type\\":\\"step\\",\\"data\\":{\\"message\\":\\"Building fresh packages\\",\\"current\\":4,\\"total\\":4}} {\\"type\\":\\"success\\",\\"data\\":\\"Saved lockfile.\\"} {\\"type\\":\\"success\\",\\"data\\":\\"Saved 1 new dependency.\\"} -{\\"type\\":\\"tree\\",\\"data\\":{\\"type\\":\\"newDependencies\\",\\"trees\\":[{\\"name\\":\\"left-pad@1.1.3\\",\\"children\\":[],\\"hint\\":null,\\"color\\":null,\\"depth\\":0}]}}" +{\\"type\\":\\"info\\",\\"data\\":\\"Direct dependencies\\"} +{\\"type\\":\\"tree\\",\\"data\\":{\\"type\\":\\"newDirectDependencies\\",\\"trees\\":[{\\"name\\":\\"left-pad@1.1.3\\",\\"children\\":[],\\"hint\\":null,\\"color\\":null,\\"depth\\":0}]}} +{\\"type\\":\\"info\\",\\"data\\":\\"All dependencies\\"} +{\\"type\\":\\"tree\\",\\"data\\":{\\"type\\":\\"newAllDependencies\\",\\"trees\\":[{\\"name\\":\\"left-pad@1.1.3\\",\\"children\\":[],\\"hint\\":null,\\"color\\":null,\\"depth\\":0}]}}" `; diff --git a/__tests__/commands/__snapshots__/licenses.js.snap b/__tests__/commands/__snapshots__/licenses.js.snap index 594ed7e2e8..f8b7ffdf8f 100644 --- a/__tests__/commands/__snapshots__/licenses.js.snap +++ b/__tests__/commands/__snapshots__/licenses.js.snap @@ -3,7 +3,7 @@ exports[`lists all licenses of the dependencies with the --json argument 1`] = ` "{\\"type\\":\\"warning\\",\\"data\\":\\"package.json: No license field\\"} {\\"type\\":\\"warning\\",\\"data\\":\\"No license field\\"} -{\\"type\\":\\"tree\\",\\"data\\":{\\"type\\":\\"licenses\\",\\"trees\\":[{\\"name\\":\\"is-plain-obj@1.1.0\\",\\"children\\":[{\\"name\\":\\"License: MIT\\"},{\\"name\\":\\"URL: https://github.com/sindresorhus/is-plain-obj.git\\"}]}]}} +{\\"type\\":\\"tree\\",\\"data\\":{\\"type\\":\\"licenses\\",\\"trees\\":[{\\"name\\":\\"MIT\\",\\"children\\":[{\\"name\\":\\"is-plain-obj@1.1.0\\",\\"children\\":[{\\"name\\":\\"URL: https://github.com/sindresorhus/is-plain-obj.git\\"},{\\"name\\":\\"VendorUrl: sindresorhus.com\\"},{\\"name\\":\\"VendorName: Sindre Sorhus\\"}]}]}]}} " `; diff --git a/__tests__/commands/add.js b/__tests__/commands/add.js index 308f7729c3..632019a902 100644 --- a/__tests__/commands/add.js +++ b/__tests__/commands/add.js @@ -96,27 +96,27 @@ test.concurrent('adds any new package to the current workspace, but install from expect(await fs.exists(`${config.cwd}/yarn.lock`)).toEqual(true); expect(await fs.exists(`${config.cwd}/packages/package-b/yarn.lock`)).toEqual(false); - await add(await makeConfigFromDirectory(`${config.cwd}/non-packages/package-c`, reporter), reporter, {}, [ + await add(await makeConfigFromDirectory(`${config.cwd}/non-package/package-c`, reporter), reporter, {}, [ 'isarray', ]); expect(await fs.exists(`${config.cwd}/node_modules/isarray`)).toEqual(false); - expect(await fs.exists(`${config.cwd}/non-packages/package-c/node_modules/isarray`)).toEqual(true); + expect(await fs.exists(`${config.cwd}/non-package/package-c/node_modules/isarray`)).toEqual(true); - expect(await fs.exists(`${config.cwd}/non-packages/package-c/yarn.lock`)).toEqual(true); + expect(await fs.exists(`${config.cwd}/non-package/package-c/yarn.lock`)).toEqual(true); }); }); -test.concurrent('install with arg', (): Promise => { - return runAdd(['is-online'], {}, 'install-with-arg'); +test.concurrent('install with arg', async () => { + await runAdd(['is-online'], {}, 'install-with-arg'); }); -test.concurrent('install from github', (): Promise => { - return runAdd(['substack/node-mkdirp#master'], {}, 'install-github'); +test.concurrent('install from github', async () => { + await runAdd(['substack/node-mkdirp#master'], {}, 'install-github'); }); -test.concurrent('install with --dev flag', (): Promise => { - return runAdd(['left-pad@1.1.0'], {dev: true}, 'add-with-flag', async config => { +test.concurrent('install with --dev flag', async () => { + await runAdd(['left-pad@1.1.0'], {dev: true}, 'add-with-flag', async config => { const lockfile = explodeLockfile(await fs.readFile(path.join(config.cwd, 'yarn.lock'))); const pkg = await fs.readJson(path.join(config.cwd, 'package.json')); @@ -126,8 +126,8 @@ test.concurrent('install with --dev flag', (): Promise => { }); }); -test.concurrent('install with --peer flag', (): Promise => { - return runAdd(['left-pad@1.1.0'], {peer: true}, 'add-with-flag', async config => { +test.concurrent('install with --peer flag', async () => { + await runAdd(['left-pad@1.1.0'], {peer: true}, 'add-with-flag', async config => { const lockfile = explodeLockfile(await fs.readFile(path.join(config.cwd, 'yarn.lock'))); const pkg = await fs.readJson(path.join(config.cwd, 'package.json')); @@ -137,8 +137,8 @@ test.concurrent('install with --peer flag', (): Promise => { }); }); -test.concurrent('install with --optional flag', (): Promise => { - return runAdd(['left-pad@1.1.0'], {optional: true}, 'add-with-flag', async config => { +test.concurrent('install with --optional flag', async () => { + await runAdd(['left-pad@1.1.0'], {optional: true}, 'add-with-flag', async config => { const lockfile = explodeLockfile(await fs.readFile(path.join(config.cwd, 'yarn.lock'))); const pkg = await fs.readJson(path.join(config.cwd, 'package.json')); @@ -183,8 +183,8 @@ const moduleAlreadyInManifestChecker = ({expectWarnings}: {expectWarnings: boole ).toEqual(expectWarnings); }; -test.concurrent('warns when adding a devDependency as dependency', (): Promise => { - return buildRun( +test.concurrent('warns when adding a devDependency as dependency', async () => { + await buildRun( reporters.BufferReporter, fixturesLoc, moduleAlreadyInManifestChecker({expectWarnings: true}), @@ -194,8 +194,8 @@ test.concurrent('warns when adding a devDependency as dependency', (): Promise => { - return buildRun( +test.concurrent("doesn't warn when adding a devDependency as devDependency", async () => { + await buildRun( reporters.BufferReporter, fixturesLoc, moduleAlreadyInManifestChecker({expectWarnings: false}), @@ -205,8 +205,8 @@ test.concurrent("doesn't warn when adding a devDependency as devDependency", (): ); }); -test.concurrent('warns when adding a dependency as devDependency', (): Promise => { - return buildRun( +test.concurrent('warns when adding a dependency as devDependency', async () => { + await buildRun( reporters.BufferReporter, fixturesLoc, moduleAlreadyInManifestChecker({expectWarnings: true}), @@ -216,8 +216,8 @@ test.concurrent('warns when adding a dependency as devDependency', (): Promise => { - return buildRun( +test.concurrent("doesn't warn when adding a dependency as dependency", async () => { + await buildRun( reporters.BufferReporter, fixturesLoc, moduleAlreadyInManifestChecker({expectWarnings: false}), @@ -227,8 +227,8 @@ test.concurrent("doesn't warn when adding a dependency as dependency", (): Promi ); }); -test.concurrent('install with link: specifier', (): Promise => { - return runAdd(['link:../left-pad'], {dev: true}, 'add-with-flag', async config => { +test.concurrent('install with link: specifier', async () => { + await runAdd(['link:../left-pad'], {dev: true}, 'add-with-flag', async config => { const lockfile = explodeLockfile(await fs.readFile(path.join(config.cwd, 'yarn.lock'))); const pkg = await fs.readJson(path.join(config.cwd, 'package.json')); @@ -243,22 +243,22 @@ test.concurrent('install with link: specifier', (): Promise => { }); }); -test.concurrent('install with arg that has binaries', (): Promise => { - return runAdd(['react-native-cli'], {}, 'install-with-arg-and-bin'); +test.concurrent('install with arg that has binaries', async () => { + await runAdd(['react-native-cli'], {}, 'install-with-arg-and-bin'); }); -test.concurrent('add with no manifest creates blank manifest', (): Promise => { - return runAdd(['lodash'], {}, 'add-with-no-manifest', async config => { +test.concurrent('add with no manifest creates blank manifest', async () => { + await runAdd(['lodash'], {}, 'add-with-no-manifest', async config => { expect(await fs.exists(path.join(config.cwd, 'package.json'))).toBe(true); }); }); -test.concurrent('add should ignore cache', (): Promise => { +test.concurrent('add should ignore cache', async () => { // left-pad@1.1.0 gets installed without --save // left-pad@1.1.0 gets installed with --save // files in mirror, yarn.lock, package.json and node_modules should reflect that - return runAdd(['left-pad@1.1.0'], {}, 'install-save-to-mirror-when-cached', async (config, reporter) => { + await runAdd(['left-pad@1.1.0'], {}, 'install-save-to-mirror-when-cached', async (config, reporter) => { expect(await getPackageVersion(config, 'left-pad')).toEqual('1.1.0'); const lockfile = await createLockfile(config.cwd); @@ -286,8 +286,8 @@ test.concurrent('add should ignore cache', (): Promise => { }); }); -test.concurrent('add should not make package.json strict', (): Promise => { - return runAdd(['left-pad@^1.1.0'], {}, 'install-no-strict', async config => { +test.concurrent('add should not make package.json strict', async () => { + await runAdd(['left-pad@^1.1.0'], {}, 'install-no-strict', async config => { const lockfile = explodeLockfile(await fs.readFile(path.join(config.cwd, 'yarn.lock'))); expect(lockfile.indexOf('left-pad@^1.1.0:')).toBeGreaterThanOrEqual(0); @@ -298,8 +298,8 @@ test.concurrent('add should not make package.json strict', (): Promise => }); }); -test.concurrent('add --save-exact should not make all package.json strict', (): Promise => { - return runAdd(['left-pad@1.1.0'], {saveExact: true}, 'install-no-strict-all', async config => { +test.concurrent('add --save-exact should not make all package.json strict', async () => { + await runAdd(['left-pad@1.1.0'], {saveExact: true}, 'install-no-strict-all', async config => { const lockfile = explodeLockfile(await fs.readFile(path.join(config.cwd, 'yarn.lock'))); expect(lockfile.indexOf('left-pad@1.1.0:')).toEqual(0); @@ -310,8 +310,8 @@ test.concurrent('add --save-exact should not make all package.json strict', (): }); }); -test.concurrent('add save-prefix should not expand ~ to home dir', (): Promise => { - return runAdd(['left-pad'], {}, 'install-no-home-expand', async config => { +test.concurrent('add save-prefix should not expand ~ to home dir', async () => { + await runAdd(['left-pad'], {}, 'install-no-home-expand', async config => { const lockfile = explodeLockfile(await fs.readFile(path.join(config.cwd, 'yarn.lock'))); expect(lockfile[0]).toMatch(/^left-pad@~\d+\.\d+\.\d+:$/); expect(JSON.parse(await fs.readFile(path.join(config.cwd, 'package.json'))).dependencies['left-pad']).toMatch( @@ -320,8 +320,8 @@ test.concurrent('add save-prefix should not expand ~ to home dir', (): Promise => { - return runAdd(['left-pad'], {}, 'install-strict-all', async config => { +test.concurrent('add save-exact should make all package.json strict', async () => { + await runAdd(['left-pad'], {}, 'install-strict-all', async config => { const lockfile = explodeLockfile(await fs.readFile(path.join(config.cwd, 'yarn.lock'))); expect(lockfile[0]).toMatch(/^left-pad@\d+\.\d+\.\d+:$/); @@ -331,8 +331,8 @@ test.concurrent('add save-exact should make all package.json strict', (): Promis }); }); -test.concurrent('add with new dependency should be deterministic 3', (): Promise => { - return runAdd([], {}, 'install-should-cleanup-when-package-json-changed-3', async (config, reporter) => { +test.concurrent('add with new dependency should be deterministic 3', async () => { + await runAdd([], {}, 'install-should-cleanup-when-package-json-changed-3', async (config, reporter) => { // expecting yarn check after installation not to fail await fs.copy(path.join(config.cwd, 'yarn.lock.after'), path.join(config.cwd, 'yarn.lock'), reporter); @@ -352,12 +352,12 @@ test.concurrent('add with new dependency should be deterministic 3', (): Promise }); }); -test.concurrent('install --initMirror should add init mirror deps from package.json', (): Promise => { +test.concurrent('install --initMirror should add init mirror deps from package.json', async () => { const mirrorPath = 'mirror-for-offline'; const fixture = 'install-init-mirror'; // initMirror gets converted to save flag in cli/install.js - return runAdd([], {}, fixture, async config => { + await runAdd([], {}, fixture, async config => { expect(await getPackageVersion(config, 'mime-types')).toEqual('2.0.0'); expect(semver.satisfies(await getPackageVersion(config, 'mime-db'), '~1.0.1')).toEqual(true); @@ -374,18 +374,18 @@ test.concurrent('install --initMirror should add init mirror deps from package.j }); }); -test.concurrent('add with new dependency should be deterministic', (): Promise => { +test.concurrent('add with new dependency should be deterministic', async () => { // mime-types@2.0.0->mime-db@1.0.3 is saved in local mirror and is deduped // install mime-db@1.23.0 should move mime-db@1.0.3 deep into mime-types const mirrorPath = 'mirror-for-offline'; const fixture = 'install-deterministic'; - return runInstall({}, path.join('..', 'add', fixture), async (config): Promise => { + await runInstall({}, path.join('..', 'add', fixture), async (config): Promise => { expect(semver.satisfies(await getPackageVersion(config, 'mime-db'), '~1.0.1')).toBe(true); expect(await getPackageVersion(config, 'mime-types')).toEqual('2.0.0'); - return runAdd(['mime-db@1.23.0'], {}, fixture, async config => { + await runAdd(['mime-db@1.23.0'], {}, fixture, async config => { expect(semver.satisfies(await getPackageVersion(config, 'mime-db'), '1.23.0')).toEqual(true); expect(await getPackageVersion(config, 'mime-types')).toEqual('2.0.0'); @@ -412,19 +412,19 @@ test.concurrent('add with new dependency should be deterministic', (): Promise => { +test.concurrent('add with new dependency should be deterministic 2', async () => { // mime-types@2.0.0->mime-db@1.0.1 is saved in local mirror and is deduped // install mime-db@1.0.3 should replace mime-db@1.0.1 in root const mirrorPath = 'mirror-for-offline'; const fixture = 'install-deterministic-2'; - return runInstall({}, path.join('..', 'add', fixture), async (config): Promise => { + await runInstall({}, path.join('..', 'add', fixture), async (config): Promise => { expect(await getPackageVersion(config, 'mime-db')).toEqual('1.0.1'); expect(await getPackageVersion(config, 'mime-types')).toEqual('2.0.0'); - return runAdd(['mime-db@1.0.3'], {}, fixture, async config => { + await runAdd(['mime-db@1.0.3'], {}, fixture, async config => { expect(await getPackageVersion(config, 'mime-db')).toEqual('1.0.3'); expect(await getPackageVersion(config, 'mime-types')).toEqual('2.0.0'); @@ -448,9 +448,9 @@ test.concurrent('add with new dependency should be deterministic 2', (): Promise }); }); -test.concurrent('add with offline mirror', (): Promise => { +test.concurrent('add with offline mirror', async () => { const mirrorPath = 'mirror-for-offline'; - return runAdd(['is-array@^1.0.1'], {}, 'install-with-save-offline-mirror', async config => { + await runAdd(['is-array@^1.0.1'], {}, 'install-with-save-offline-mirror', async config => { const allFiles = await fs.walk(config.cwd); expect( @@ -469,10 +469,10 @@ test.concurrent('add with offline mirror', (): Promise => { }); // broken https://github.com/yarnpkg/yarn/issues/2333 -test.skip('add-then-install git+ssh from offline mirror', (): Promise => { +test.skip('add-then-install git+ssh from offline mirror', async () => { const mirrorPath = 'mirror-for-offline'; - return runAdd( + await runAdd( ['mime-db@git+ssh://git@github.com/jshttp/mime-db.git#1.24.0'], {}, 'install-git-ssh-mirror', @@ -511,9 +511,9 @@ test.skip('add-then-install git+ssh from offline mirror', (): Promise => { ); }); -test.concurrent('install with --save and without offline mirror', (): Promise => { +test.concurrent('install with --save and without offline mirror', async () => { const mirrorPath = 'mirror-for-offline'; - return runAdd(['is-array@^1.0.1'], {}, 'install-with-save-no-offline-mirror', async config => { + await runAdd(['is-array@^1.0.1'], {}, 'install-with-save-no-offline-mirror', async config => { const allFiles = await fs.walk(config.cwd); expect( @@ -531,13 +531,13 @@ test.concurrent('install with --save and without offline mirror', (): Promise => { +test.concurrent('upgrade scenario', async () => { // left-pad first installed 0.0.9 then updated to 1.1.0 // files in mirror, yarn.lock, package.json and node_modules should reflect that const mirrorPath = 'mirror-for-offline'; - return runAdd(['left-pad@0.0.9'], {}, 'install-upgrade-scenario', async (config, reporter): Promise => { + await runAdd(['left-pad@0.0.9'], {}, 'install-upgrade-scenario', async (config, reporter): Promise => { expect(await getPackageVersion(config, 'left-pad')).toEqual('0.0.9'); expect(JSON.parse(await fs.readFile(path.join(config.cwd, 'package.json'))).dependencies).toEqual({ @@ -580,19 +580,19 @@ test.concurrent('upgrade scenario', (): Promise => { }); }); -test.concurrent('upgrade scenario 2 (with sub dependencies)', (): Promise => { +test.concurrent('upgrade scenario 2 (with sub dependencies)', async () => { // mime-types@2.0.0 is saved in local mirror and gets updated to mime-types@2.1.11 // files in mirror, yarn.lock, package.json and node_modules should reflect that const mirrorPath = 'mirror-for-offline'; const fixture = 'install-upgrade-scenario-2'; - return runInstall({}, path.join('..', 'add', fixture), async (config): Promise => { + await runInstall({}, path.join('..', 'add', fixture), async (config): Promise => { expect(semver.satisfies(await getPackageVersion(config, 'mime-db'), '~1.0.1')).toEqual(true); expect(await getPackageVersion(config, 'mime-types')).toEqual('2.0.0'); - return runAdd(['mime-types@2.1.11'], {}, fixture, async config => { + await runAdd(['mime-types@2.1.11'], {}, fixture, async config => { expect(semver.satisfies(await getPackageVersion(config, 'mime-db'), '~1.23.0')).toEqual(true); expect(await getPackageVersion(config, 'mime-types')).toEqual('2.1.11'); @@ -641,11 +641,11 @@ test.concurrent('install another fork of an existing package', (): Promise }); }); -test.concurrent('downgrade scenario', (): Promise => { +test.concurrent('downgrade scenario', async () => { // left-pad first installed 1.1.0 then downgraded to 0.0.9 // files in mirror, yarn.lock, package.json and node_modules should reflect that - return runAdd(['left-pad@1.1.0'], {}, 'install-downgrade-scenario', async (config, reporter): Promise => { + await runAdd(['left-pad@1.1.0'], {}, 'install-downgrade-scenario', async (config, reporter): Promise => { expect(await getPackageVersion(config, 'left-pad')).toEqual('1.1.0'); expect(JSON.parse(await fs.readFile(path.join(config.cwd, 'package.json'))).dependencies).toEqual({ @@ -689,12 +689,12 @@ test.concurrent('downgrade scenario', (): Promise => { }); // https://github.com/yarnpkg/yarn/issues/318 -test.concurrent('modules resolved multiple times should save to mirror correctly', (): Promise => { +test.concurrent('modules resolved multiple times should save to mirror correctly', async () => { // the package.json in this fixture has 4 transitive dependants on module which that should resolve to // which@^1.0.5, which@^1.1.1, which@^1.2.8, which@^1.2.9: // version "1.2.11" // resolved which-1.2.11.tgz#c8b2eeea6b8c1659fa7c1dd4fdaabe9533dc5e8b - return runAdd([], {}, 'no-mirror-remote-when-duplicates', async (config): Promise => { + await runAdd([], {}, 'no-mirror-remote-when-duplicates', async (config): Promise => { const mirrorPath = 'mirror-for-offline'; // check that which module was downloaded to mirror @@ -714,10 +714,10 @@ test.concurrent('modules resolved multiple times should save to mirror correctly }); }); -test.concurrent('add should put a git dependency to mirror', (): Promise => { +test.concurrent('add should put a git dependency to mirror', async () => { const mirrorPath = 'mirror-for-offline'; - return runAdd( + await runAdd( ['mime-db@https://github.com/jshttp/mime-db.git#1.24.0'], {}, 'install-git-mirror', @@ -750,8 +750,8 @@ test.concurrent('add should put a git dependency to mirror', (): Promise = ); }); -test.concurrent('add should store latest version in lockfile', (): Promise => { - return runAdd(['max-safe-integer'], {}, 'latest-version-in-lockfile', async config => { +test.concurrent('add should store latest version in lockfile', async () => { + await runAdd(['max-safe-integer'], {}, 'latest-version-in-lockfile', async config => { const lockfile = explodeLockfile(await fs.readFile(path.join(config.cwd, 'yarn.lock'))); const pkg = await fs.readJson(path.join(config.cwd, 'package.json')); @@ -762,8 +762,8 @@ test.concurrent('add should store latest version in lockfile', (): Promise }); }); -test.concurrent('add should generate correct integrity file', (): Promise => { - return runAdd(['mime-db@1.24.0'], {}, 'integrity-check', async (config, reporter) => { +test.concurrent('add should generate correct integrity file', async () => { + await runAdd(['mime-db@1.24.0'], {}, 'integrity-check', async (config, reporter) => { let allCorrect = true; try { await check(config, reporter, {integrity: true}, []); @@ -784,7 +784,7 @@ test.concurrent('add should generate correct integrity file', (): Promise }); }); -test.concurrent('add infers line endings from existing win32 manifest file', async (): Promise => { +test.concurrent('add infers line endings from existing win32 manifest file', async () => { await runAdd( ['is-online'], {}, @@ -801,7 +801,7 @@ test.concurrent('add infers line endings from existing win32 manifest file', asy ); }); -test.concurrent('add infers line endings from existing unix manifest file', async (): Promise => { +test.concurrent('add infers line endings from existing unix manifest file', async () => { await runAdd( ['is-online'], {}, @@ -819,7 +819,7 @@ test.concurrent('add infers line endings from existing unix manifest file', asyn }); // broken https://github.com/yarnpkg/yarn/issues/2466 -test.skip('add asks for correct package version if user passes an incorrect one', async (): Promise => { +test.skip('add asks for correct package version if user passes an incorrect one', async () => { let chosenVersion = null; await runAdd( ['is-array@100'], @@ -847,8 +847,8 @@ test.skip('add asks for correct package version if user passes an incorrect one' ); }); -test.concurrent('install with latest tag', (): Promise => { - return runAdd(['left-pad@latest'], {}, 'latest-version-in-package', async config => { +test.concurrent('install with latest tag', async () => { + await runAdd(['left-pad@latest'], {}, 'latest-version-in-package', async config => { const lockfile = explodeLockfile(await fs.readFile(path.join(config.cwd, 'yarn.lock'))); const pkg = await fs.readJson(path.join(config.cwd, 'package.json')); const version = await getPackageVersion(config, 'left-pad'); @@ -858,8 +858,8 @@ test.concurrent('install with latest tag', (): Promise => { }); }); -test.concurrent('install with latest tag and --offline flag', (): Promise => { - return runAdd(['left-pad@latest'], {}, 'latest-version-in-package', async (config, reporter, previousAdd) => { +test.concurrent('install with latest tag and --offline flag', async () => { + await runAdd(['left-pad@latest'], {}, 'latest-version-in-package', async (config, reporter, previousAdd) => { config.offline = true; const add = new Add(['left-pad@latest'], {}, config, reporter, previousAdd.lockfile); await add.init(); @@ -871,8 +871,8 @@ test.concurrent('install with latest tag and --offline flag', (): Promise }); }); -test.concurrent('install with latest tag and --prefer-offline flag', (): Promise => { - return runAdd(['left-pad@1.1.0'], {}, 'latest-version-in-package', async (config, reporter, previousAdd) => { +test.concurrent('install with latest tag and --prefer-offline flag', async () => { + await runAdd(['left-pad@1.1.0'], {}, 'latest-version-in-package', async (config, reporter, previousAdd) => { config.preferOffline = true; const add = new Add(['left-pad@latest'], {}, config, reporter, previousAdd.lockfile); await add.init(); @@ -885,8 +885,8 @@ test.concurrent('install with latest tag and --prefer-offline flag', (): Promise }); }); -test.concurrent("doesn't warn when peer dependency is met during add", (): Promise => { - return buildRun( +test.concurrent("doesn't warn when peer dependency is met during add", async () => { + await buildRun( reporters.BufferReporter, fixturesLoc, async (args, flags, config, reporter, lockfile): Promise => { @@ -914,8 +914,8 @@ test.concurrent("doesn't warn when peer dependency is met during add", (): Promi ); }); -test.concurrent('warns when peer dependency is not met during add', (): Promise => { - return buildRun( +test.concurrent('warns when peer dependency is not met during add', async () => { + await buildRun( reporters.BufferReporter, fixturesLoc, async (args, flags, config, reporter, lockfile): Promise => { @@ -937,8 +937,8 @@ test.concurrent('warns when peer dependency is not met during add', (): Promise< ); }); -test.concurrent('warns when peer dependency is incorrect during add', (): Promise => { - return buildRun( +test.concurrent('warns when peer dependency is incorrect during add', async () => { + await buildRun( reporters.BufferReporter, fixturesLoc, async (args, flags, config, reporter, lockfile): Promise => { @@ -960,8 +960,8 @@ test.concurrent('warns when peer dependency is incorrect during add', (): Promis ); }); -test.concurrent('should only refer to higher levels to satisfy peer dependency', (): Promise => { - return buildRun( +test.concurrent('should only refer to higher levels to satisfy peer dependency', async () => { + await buildRun( reporters.BufferReporter, fixturesLoc, async (args, flags, config, reporter, lockfile): Promise => { @@ -978,8 +978,8 @@ test.concurrent('should only refer to higher levels to satisfy peer dependency', ); }); -test.concurrent('should refer to deeper dependencies to satisfy peer dependency', (): Promise => { - return buildRun( +test.concurrent('should refer to deeper dependencies to satisfy peer dependency', async () => { + await buildRun( reporters.BufferReporter, fixturesLoc, async (args, flags, config, reporter, lockfile): Promise => { @@ -996,8 +996,8 @@ test.concurrent('should refer to deeper dependencies to satisfy peer dependency' ); }); -test.concurrent('should retain build artifacts after add when missing integrity file', (): Promise => { - return buildRun( +test.concurrent('should retain build artifacts after add when missing integrity file', async () => { + await buildRun( reporters.BufferReporter, fixturesLoc, async (args, flags, config, reporter): Promise => { @@ -1027,8 +1027,8 @@ test.concurrent('should retain build artifacts after add when missing integrity ); }); -test.concurrent('should retain build artifacts after add', (): Promise => { - return buildRun( +test.concurrent('should retain build artifacts after add', async () => { + await buildRun( reporters.BufferReporter, fixturesLoc, async (args, flags, config, reporter, lockfile): Promise => { @@ -1053,10 +1053,10 @@ test.concurrent('should retain build artifacts after add', (): Promise => ); }); -test.concurrent('installing with --pure-lockfile and then adding should keep build artifacts', (): Promise => { +test.concurrent('installing with --pure-lockfile and then adding should keep build artifacts', async () => { const fixture = 'integrity-pure-lockfile'; - return runInstall({pureLockfile: true}, path.join('..', 'add', fixture), async (config, reporter): Promise => { + await runInstall({pureLockfile: true}, path.join('..', 'add', fixture), async (config, reporter): Promise => { expect(await fs.exists(path.join(config.cwd, 'node_modules', '.yarn-integrity'))).toBe(true); expect(await fs.exists(path.join(config.cwd, 'node_modules', 'package-a', 'temp.txt'))).toBe(true); const add = new Add(['left-pad@1.1.0'], {}, config, reporter, await Lockfile.fromDirectory(config.cwd)); @@ -1094,7 +1094,7 @@ test.concurrent('preserves unaffected bin links after adding to workspace packag }); }); -test.concurrent('installs "latest" instead of maxSatisfying if it satisfies requested pattern', (): Promise => { +test.concurrent('installs "latest" instead of maxSatisfying if it satisfies requested pattern', async () => { // Scenario: // If a registry contains versions [1.0.0, 1.0.1, 1.0.2] and latest:1.0.1 // (note that "latest" is not the "newest" version) @@ -1105,7 +1105,7 @@ test.concurrent('installs "latest" instead of maxSatisfying if it satisfies requ // * https://git.io/vFmau // // In this test, `ui-select` has a max version of `0.20.0` but a `latest:0.19.8` - return runAdd(['ui-select@^0.X'], {}, 'latest-version-in-package', async (config, reporter, previousAdd) => { + await runAdd(['ui-select@^0.X'], {}, 'latest-version-in-package', async (config, reporter, previousAdd) => { const lockfile = explodeLockfile(await fs.readFile(path.join(config.cwd, 'yarn.lock'))); const patternIndex = lockfile.indexOf('ui-select@^0.X:'); const versionIndex = patternIndex + 1; @@ -1115,14 +1115,14 @@ test.concurrent('installs "latest" instead of maxSatisfying if it satisfies requ }); }); -test.concurrent('installs "latest" instead of maxSatisfying if no requested pattern', (): Promise => { +test.concurrent('installs "latest" instead of maxSatisfying if no requested pattern', async () => { // Scenario: // If a registry contains versions [1.0.0, 1.0.1, 1.0.2] and latest:1.0.1 // If `yarn add` is run, it should choose `1.0.1` because it is "latest", not `1.0.2` even though it is newer. // In other words, when no range is explicitely given, Yarn should choose "latest". // // In this test, `ui-select` has a max version of `0.20.0` but a `latest:0.19.8` - return runAdd(['ui-select'], {}, 'latest-version-in-package', async (config, reporter, previousAdd) => { + await runAdd(['ui-select'], {}, 'latest-version-in-package', async (config, reporter, previousAdd) => { const lockfile = explodeLockfile(await fs.readFile(path.join(config.cwd, 'yarn.lock'))); const patternIndex = lockfile.indexOf('ui-select@^0.19.8:'); const versionIndex = patternIndex + 1; @@ -1131,3 +1131,51 @@ test.concurrent('installs "latest" instead of maxSatisfying if no requested patt expect(actualVersion).toContain('0.19.8'); }); }); + +describe('nohoist', () => { + test.concurrent('can add nohoist pacakge from workspace', async () => { + await runInstall({}, 'workspaces-install-nohoist-across-versions', async (config): Promise => { + const reporter = new ConsoleReporter({}); + + // workspace-2 has b and c since the root has nohoist = ['a', 'b', 'c'] + expect(await fs.exists(`${config.cwd}/packages/workspace-2/node_modules/b`)).toEqual(true); + expect(await fs.exists(`${config.cwd}/packages/workspace-2/node_modules/c`)).toEqual(true); + + // prove package a does not exist in workspace-2 nor in root + expect(await fs.exists(`${config.cwd}/packages/workspace-2/node_modules/a`)).toEqual(false); + expect(await fs.exists(`${config.cwd}/node_modules/a`)).toEqual(false); + expect(await fs.exists(`${config.cwd}/node_modules/b`)).toEqual(false); + expect(await fs.exists(`${config.cwd}/node_modules/c`)).toEqual(false); + + // add package 'a' to workspace-2 + const childConfig = await makeConfigFromDirectory(`${config.cwd}/packages/workspace-2`, reporter, {}); + await add(childConfig, reporter, {}, ['file:a']); + + // now package a should exist in workspace-2 + expect(await fs.exists(`${config.cwd}/packages/workspace-2/node_modules/a`)).toEqual(true); + expect(await fs.exists(`${config.cwd}/packages/workspace-2/node_modules/b`)).toEqual(true); + expect(await fs.exists(`${config.cwd}/packages/workspace-2/node_modules/c`)).toEqual(true); + + // make sure workspace-2 dependencies didn't get hoisted to root + expect(await fs.exists(`${config.cwd}/node_modules/a`)).toEqual(false); + expect(await fs.exists(`${config.cwd}/node_modules/b`)).toEqual(false); + expect(await fs.exists(`${config.cwd}/node_modules/c`)).toEqual(false); + }); + }); + test.concurrent('can add nohoist pacakge from root', async () => { + await runInstall({}, 'workspaces-install-nohoist-across-versions', async (config): Promise => { + const reporter = new ConsoleReporter({}); + + // prove package a does not exist in workspace-2 nor in root + expect(await fs.exists(`${config.cwd}/packages/workspace-2/node_modules/a`)).toEqual(false); + expect(await fs.exists(`${config.cwd}/node_modules/a`)).toEqual(false); + + // add package 'a' to root package + await add(config, reporter, {ignoreWorkspaceRootCheck: true}, ['file:a']); + + // now package a should exist in workspace-2 + expect(await fs.exists(`${config.cwd}/packages/workspace-2/node_modules/a`)).toEqual(false); + expect(await fs.exists(`${config.cwd}/node_modules/a`)).toEqual(true); + }); + }); +}); diff --git a/__tests__/commands/install/bin-links.js b/__tests__/commands/install/bin-links.js index 3e78a5c4ab..59208a058d 100644 --- a/__tests__/commands/install/bin-links.js +++ b/__tests__/commands/install/bin-links.js @@ -145,6 +145,17 @@ test('first dep is installed when same level and reference count and one is a de }); }); +// Scenario: Transitive dependency having bin link with a name that's conflicting with that of a direct dependency. +// Behavior: a-dep and b-dep is linked in node_modules/.bin rather than c-dep and d-dep +test('direct dependency is linked when bin name conflicts with transitive dependency', (): Promise => { + return runInstall({binLinks: true}, 'install-bin-links-conflicting-names', async config => { + const stdout1 = await execCommand(config.cwd, ['node_modules', '.bin', 'binlink1'], []); + const stdout2 = await execCommand(config.cwd, ['node_modules', '.bin', 'binlink2'], []); + expect(stdout1[0]).toEqual('direct a-dep'); + expect(stdout2[0]).toEqual('direct f-dep'); + }); +}); + // fixes https://github.com/yarnpkg/yarn/issues/3535 // quite a heavy test, did not find a way to isolate test('Only top level (after hoisting) bin links should be linked', (): Promise => { diff --git a/__tests__/commands/install/integration.js b/__tests__/commands/install/integration.js index e12ff5b0f6..b606e04a9e 100644 --- a/__tests__/commands/install/integration.js +++ b/__tests__/commands/install/integration.js @@ -1177,3 +1177,22 @@ test.concurrent('install will not overwrite linked dependencies', async (): Prom }); }); }); + +// There was a warning being generated when a peerDep existed at a deeper level, and at the top level. +// See https://github.com/yarnpkg/yarn/issues/4743 +// +// package.json +// |- b +// | |- caniuse-api +// | |- caniuse-lite +// |- caniuse-lite +// +// When `b` also has a peerDep on `caniuse-lite` then Yarn was issuing a warning that the dep was missing. +test.concurrent('install will not warn for missing peerDep when both shallower and deeper', (): Promise => { + return runInstall({}, 'peer-dep-included-at-2-levels', (config, reporter, install, getStdout) => { + const stdout = getStdout(); + const messageParts = reporter.lang('unmetPeer').split('undefined'); + const warningMessage = messageParts.every(part => stdout.includes(part)); + expect(warningMessage).toBe(false); + }); +}); diff --git a/__tests__/commands/install/workspaces-install.js b/__tests__/commands/install/workspaces-install.js index 55ed6ce173..0afe5971ff 100644 --- a/__tests__/commands/install/workspaces-install.js +++ b/__tests__/commands/install/workspaces-install.js @@ -4,7 +4,8 @@ import {run as check} from '../../../src/cli/commands/check.js'; import {Install, run as install} from '../../../src/cli/commands/install.js'; import * as reporters from '../../../src/reporters/index.js'; import * as fs from '../../../src/util/fs.js'; -import {runInstall, run as buildRun, makeConfigFromDirectory} from '../_helpers.js'; +import type ConfigType from '../../../src/config.js'; +import {runInstall, run as buildRun, makeConfigFromDirectory, isPackagePresent} from '../_helpers.js'; jasmine.DEFAULT_TIMEOUT_INTERVAL = 150000; @@ -272,3 +273,119 @@ test.concurrent('install should link binaries properly when run from child works }); // TODO need more thorough tests for all kinds of checks: integrity, verify-tree + +describe('nohoist', () => { + async function checkPackage(config: ConfigType, path: string, shouldPresent: boolean): Promise { + const isPresent = await isPackagePresent(config, path); + try { + expect(isPresent).toEqual(shouldPresent); + } catch (e) { + throw new Error(`error: ${path} should ${shouldPresent ? '' : 'NOT'} exist`); + } + } + + test.concurrent('exclude packages by workspace', (): Promise => { + return runInstall({}, 'workspaces-install-nohoist-by-ws', async (config): Promise => { + const existingPackages = [ + 'workspace-disable-a', + 'workspace-disable-all', + 'workspace-hoist-all', + 'workspace-disable-all/c', + 'workspace-disable-all/b', + 'workspace-disable-all/d', + 'workspace-disable-a/a', + 'workspace-disable-a/b', + 'workspace-disable-all/workspace-hoist-all', + 'b', + 'c', + 'd', + ]; + const notExistingPackages = ['a', 'workspace-hoist-all/b', 'workspace-hoist-all/d']; + + for (const p of existingPackages) { + await checkPackage(config, p, true); + } + for (const p of notExistingPackages) { + await checkPackage(config, p, false); + } + }); + }); + + test.concurrent('disable all hoist for every workspace', (): Promise => { + return runInstall({}, 'workspaces-install-nohoist-all-from-root', async config => { + const existingPackages = [ + 'workspace-disable-a', + 'workspace-disable-all', + 'workspace-hoist-all', + 'workspace-disable-all/c', + 'workspace-disable-all/b', + 'workspace-disable-all/d', + 'workspace-disable-a/a', + 'workspace-disable-a/b', + 'workspace-disable-a/d', + 'workspace-hoist-all/b', + 'workspace-hoist-all/d', + ]; + const notExistingPackages = ['a', 'b', 'c', 'd']; + + for (const p of existingPackages) { + await checkPackage(config, p, true); + } + for (const p of notExistingPackages) { + await checkPackage(config, p, false); + } + }); + }); + test.concurrent('disable some hoist for every workspace', (): Promise => { + return runInstall({}, 'workspaces-install-nohoist-some-from-root', async config => { + const existingPackages = [ + 'workspace-disable-a', + 'workspace-disable-all', + 'workspace-hoist-all', + 'workspace-disable-all/c', + 'workspace-disable-all/b', + 'workspace-disable-all/d', + 'workspace-disable-a/a', + 'workspace-disable-a/b', + 'workspace-disable-a/d', + 'workspace-hoist-all/d', + 'c', + 'b', + ]; + const notExistingPackages = ['a', 'd']; + + for (const p of existingPackages) { + await checkPackage(config, p, true); + } + for (const p of notExistingPackages) { + await checkPackage(config, p, false); + } + }); + }); + test.concurrent('disable hoisting package across versions', (): Promise => { + return runInstall({}, 'workspaces-install-nohoist-across-versions', async config => { + const existingPackages = [ + 'workspace-1', + 'workspace-2', + 'workspace-3', + 'workspace-1/c', + 'workspace-1/b', + 'workspace-1/a', + 'workspace-2/b', + 'workspace-2/c', + 'workspace-2/b', + 'workspace-2/c/b', + 'workspace-3/b', + 'd', + ]; + const notExistingPackages = ['a', 'b', 'c', 'workspace-3/d']; + + for (const p of existingPackages) { + await checkPackage(config, p, true); + } + for (const p of notExistingPackages) { + await checkPackage(config, p, false); + } + }); + }); +}); diff --git a/__tests__/commands/list.js b/__tests__/commands/list.js index b134d40652..37ca00e629 100644 --- a/__tests__/commands/list.js +++ b/__tests__/commands/list.js @@ -171,6 +171,16 @@ describe('list', () => { }); }); + test('does not error listing dependencies when production and no devDependencies exist', async (): Promise => { + let thrown = false; + try { + await runList([], {production: true}, 'no-dev-deps-production'); + } catch (e) { + thrown = true; + } + expect(thrown).toEqual(false); + }); + test('getParent should extract a parent object from a hash, if the parent key exists', () => { const mockTreesByKey = {}; diff --git a/__tests__/commands/publish.js b/__tests__/commands/publish.js new file mode 100644 index 0000000000..aaee892112 --- /dev/null +++ b/__tests__/commands/publish.js @@ -0,0 +1,101 @@ +/* @flow */ + +import {run as buildRun} from './_helpers.js'; +import {run as publish} from '../../src/cli/commands/publish.js'; +import {ConsoleReporter} from '../../src/reporters/index.js'; + +const path = require('path'); + +const fixturesLoc = path.join(__dirname, '..', 'fixtures', 'publish'); + +const setupMocks = function(config) { + // Mock actual network request so that no package is actually published. + // $FlowFixMe + config.registries.npm.request = jest.fn(); + config.registries.npm.request.mockReturnValue( + new Promise(resolve => { + resolve({status: 200}); + }), + ); + + // Mock the npm login name. Otherwise yarn will prompt for it and break CI. + // $FlowFixMe + config.registries.npm.getAuth = jest.fn(); + config.registries.npm.getAuth.mockReturnValue('test'); +}; + +const runPublish = buildRun.bind( + null, + ConsoleReporter, + fixturesLoc, + async (args, flags, config, reporter, lockfile, getStdout): Promise => { + setupMocks(config); + await publish(config, reporter, flags, args); + return getStdout(); + }, +); + +test.concurrent('publish should default access to undefined', () => { + return runPublish([], {newVersion: '0.0.1'}, 'minimal', config => { + expect(config.registries.npm.request).toBeCalledWith( + expect.any(String), + expect.objectContaining({ + body: expect.objectContaining({ + access: undefined, + }), + }), + ); + }); +}); + +test.concurrent('publish should accept `--access restricted` argument', () => { + return runPublish([], {newVersion: '0.0.1', access: 'restricted'}, 'minimal', config => { + expect(config.registries.npm.request).toBeCalledWith( + expect.any(String), + expect.objectContaining({ + body: expect.objectContaining({ + access: 'restricted', + }), + }), + ); + }); +}); + +test.concurrent('publish should accept `--access public` argument', () => { + return runPublish([], {newVersion: '0.0.1', access: 'public'}, 'minimal', config => { + expect(config.registries.npm.request).toBeCalledWith( + expect.any(String), + expect.objectContaining({ + body: expect.objectContaining({ + access: 'public', + }), + }), + ); + }); +}); + +test.concurrent('publish should use publishConfig.access in package manifest', () => { + return runPublish([], {newVersion: '0.0.1'}, 'public', config => { + expect(config.registries.npm.request).toBeCalledWith( + expect.any(String), + expect.objectContaining({ + body: expect.objectContaining({ + access: 'public', + }), + }), + ); + }); +}); + +test.concurrent('publish should allow `--access` to override publishConfig.access', () => { + return runPublish([], {newVersion: '0.0.1', access: 'restricted'}, 'public', config => { + expect(config.registries.npm.request).toBeCalledWith( + expect.any(String), + expect.objectContaining({ + body: expect.objectContaining({ + access: 'restricted', + }), + }), + ); + }); +}); diff --git a/__tests__/commands/run.js b/__tests__/commands/run.js index 6f692c4231..2f4a238249 100644 --- a/__tests__/commands/run.js +++ b/__tests__/commands/run.js @@ -37,6 +37,18 @@ const runRunInWorkspacePackage = function(cwd, ...args): Promise { return retVal; })(...args); }; +const runRunWithCustomShell = function(customShell, ...args): Promise { + return buildRun.bind(null, BufferReporter, fixturesLoc, (args, flags, config, reporter): Promise => { + const yarnRegistry = config.registries.yarn; + const originalCustomShell = yarnRegistry.config['script-shell']; + yarnRegistry.config['script-shell'] = customShell; + const retVal = run(config, reporter, flags, args); + retVal.then(() => { + yarnRegistry.config['script-shell'] = originalCustomShell; + }); + return retVal; + })(...args); +}; test('lists all available commands with no arguments', (): Promise => { return runRun([], {}, 'no-args', (config, reporter): ?Promise => { @@ -63,7 +75,7 @@ test('lists all available commands with no arguments', (): Promise => { test('runs script containing spaces', (): Promise => { return runRun(['build'], {}, 'spaces', async (config): ?Promise => { const pkg = await fs.readJson(path.join(config.cwd, 'package.json')); - // The command get's called with a space appended + // The command gets called with a space appended const args = ['build', config, pkg.scripts.build, config.cwd]; expect(execCommand).toBeCalledWith(...args); @@ -167,3 +179,13 @@ test('adds workspace root node_modules/.bin to path when in a workspace', (): Pr expect(envPaths).toContain(path.join(config.cwd, 'packages', 'pkg1', 'node_modules', '.bin')); }); }); + +test('runs script with custom script-shell', (): Promise => { + return runRunWithCustomShell('/usr/bin/dummy', ['start'], {}, 'script-shell', async (config): ?Promise => { + const pkg = await fs.readJson(path.join(config.cwd, 'package.json')); + // The command gets called with the provided customShell + const args = ['start', config, pkg.scripts.start, config.cwd, '/usr/bin/dummy']; + + expect(execCommand).toBeCalledWith(...args); + }); +}); diff --git a/__tests__/commands/upgrade.js b/__tests__/commands/upgrade.js index c70a3272cf..07be7d78be 100644 --- a/__tests__/commands/upgrade.js +++ b/__tests__/commands/upgrade.js @@ -275,6 +275,34 @@ test.concurrent('upgrades optional dependency packages not in registry', (): Pro }); }); +test.concurrent('informs the type of dependency after upgrade', (): Promise => { + return buildRun( + reporters.BufferReporter, + fixturesLoc, + async (args, flags, config, reporter): Promise => { + await upgrade(config, reporter, flags, args); + + const output = reporter.getBuffer(); + const infos = output.filter(({type}) => type === 'info'); + const getTreeInfo = pkgName => + output.filter( + ({type, data: {trees = []}}) => type === 'tree' && trees.some(({name}) => name.indexOf(pkgName) > -1), + ); + + expect( + infos.some(info => { + return info.data.toString().indexOf('Direct dependencies') > -1; + }), + ).toEqual(true); + expect(getTreeInfo('async')).toHaveLength(2); + expect(getTreeInfo('lodash')).toHaveLength(1); + }, + ['async'], + {latest: true}, + 'direct-dependency', + ); +}); + test.concurrent('warns when peer dependency is not met after upgrade', (): Promise => { return buildRun( reporters.BufferReporter, diff --git a/__tests__/commands/why.js b/__tests__/commands/why.js index e1464d4178..88a86c44a8 100644 --- a/__tests__/commands/why.js +++ b/__tests__/commands/why.js @@ -1,10 +1,14 @@ /* @flow */ import {BufferReporter} from '../../src/reporters/index.js'; -import {run as why} from '../../src/cli/commands/why.js'; +import {run as why, queryWhy} from '../../src/cli/commands/why.js'; import * as reporters from '../../src/reporters/index.js'; import Config from '../../src/config.js'; import path from 'path'; +import {HoistManifest} from '../../src/package-hoister.js'; +import type {Manifest} from '../../src/types.js'; +import type {HoistManifestTuple, HoistManifestTuples} from '../../src/package-hoister.js'; +import type {LanguageKeys} from '../../src/reporters/lang/en.js'; jasmine.DEFAULT_TIMEOUT_INTERVAL = 90000; @@ -15,9 +19,10 @@ async function runWhy( args: Array, name: string, checkSteps?: ?(config: Config, reporter: BufferReporter) => ?Promise, + _reporter?: reporters.BufferReporter, ): Promise { const cwd = path.join(fixturesLoc, name); - const reporter = new reporters.BufferReporter({stdout: null, stdin: null}); + const reporter = _reporter || new reporters.BufferReporter({stdout: null, stdin: null}); try { const config = await Config.create({cwd}, reporter); @@ -94,7 +99,7 @@ test.concurrent('should determine that the module installed because it is in dev test.concurrent('should determine that the module installed because mime-types depend on it', (): Promise => { return runWhy({}, ['mime-db'], 'basic', (config, reporter) => { const report = reporter.getBuffer(); - expect(report[report.length - 1].data).toEqual(reporter.lang('whyDependedOnSimple', 'mime-types')); + expect((report[report.length - 1].data: any).items).toContainEqual(reporter.lang('whyDependedOn', 'mime-types')); }); }); @@ -106,3 +111,159 @@ test.concurrent('should determine that the module installed because it is hoiste expect(report[report.length - 2].data).toEqual(reporter.lang('whyHoistedTo', 'glob#minimatch')); }); }); + +test('should report when a module is included multiple times including the root', (): Promise => { + return runWhy({}, ['caniuse-lite'], 'dep-included-at-2-levels', (config, reporter) => { + const report = reporter.getBuffer(); + const reasons = report + .filter(entry => entry.type === 'list' && entry.data.type === 'reasons') + .map(entry => entry.data.items)[0]; + + expect(reasons).toEqual([ + 'Specified in "dependencies"', + 'Hoisted from "b#caniuse-api#caniuse-lite"', + 'Hoisted from "b#caniuse-api#browserslist#caniuse-lite"', + ]); + }); +}); + +class MockReporter extends reporters.BufferReporter { + _lang = jest.fn(); + lang(key: LanguageKeys, ...args: Array): string { + this._lang(key, args); + return super.lang(key, args); + } + + findCalls(key: string): Array> { + return this._lang.mock.calls.filter(call => { + return call[0] === key; + }); + } +} + +describe('reports multiple occurrences', () => { + function setupTest( + target: string, + checkSteps: (config: Config, reporter: MockReporter) => ?Promise, + ): Promise { + const _reporter = new MockReporter({stdout: null, stdin: null}); + return runWhy( + {includeWorkspaceDeps: true}, + [target], + 'workspaces-nohoist', + (config, reporter) => checkSteps(config, _reporter), + _reporter, + ); + } + test.concurrent('due to nohoist', (): Promise => { + const target = 'mime-types'; + return setupTest(target, (config, reporter) => { + // check packages matched + let calls = reporter.findCalls('whyMatch'); + expect(calls.length).toEqual(2); + + const found: [boolean, boolean] = [false, false]; + calls.forEach(call => { + const pkg: string = call[1][0]; + if (pkg.indexOf(target) === 0) { + found[0] = true; + } else if (pkg.indexOf(`#${target}`) > 0) { + found[1] = true; + } + }); + expect(found[0]).toEqual(true); + expect(found[1]).toEqual(true); + + // check reasons: should have both hoist and nohoist + calls = reporter.findCalls('whyHoistedTo'); + expect(calls.length).toEqual(1); + expect(calls[0][1][0]).toEqual(target); + + calls = reporter.findCalls('whyNotHoisted'); + expect(calls.length).toEqual(1); + const nohoistList = calls[0][1][0]; + let found2 = false; + for (const p of nohoistList) { + if (p.indexOf(target) >= 0) { + found2 = true; + break; + } + } + expect(found2).toBeTruthy(); + }); + }); + test.concurrent('due to version conflict', (): Promise => { + const target = 'uglifyify'; + return setupTest(target, (config, reporter) => { + // check packages matched + let calls = reporter.findCalls('whyMatch'); + expect(calls.length).toEqual(2); + + const found: [boolean, boolean] = [false, false]; + calls.forEach(call => { + const pkg: string = call[1][0]; + if (pkg.indexOf(target) === 0) { + found[0] = true; + } else if (pkg.indexOf(`#${target}`) > 0) { + found[1] = true; + } + }); + expect(found[0]).toEqual(true); + expect(found[1]).toEqual(true); + + // check reasons: should have both hoist and nohoist + calls = reporter.findCalls('whySpecified'); + expect(calls.length).toEqual(2); + }); + }); +}); + +describe('queryWhy', () => { + function mockManifest(name: string): Manifest { + return { + name, + version: '1.0.0', + _uid: '', + }; + } + + function mockHoistManifestTuple(name: string, key: string, previousPaths: Array): HoistManifestTuple { + const hm = new HoistManifest(key, [], mockManifest(name), '', false, true, false); + return ['', hm]; + } + + function validateMatch(matches: Array, expected: Array) { + expect(matches.length).toEqual(expected.length); + for (let i = 0; i < matches.length; i++) { + expect(matches[i][1].key).toEqual(expected[i]); + } + } + + test('can determine a nohoist module', () => { + const hoisted: HoistManifestTuples = [ + mockHoistManifestTuple('b', 'b', ['workspace-1#b']), + mockHoistManifestTuple('a', 'workspace-1#a', []), + ]; + validateMatch(queryWhy('a', hoisted), ['workspace-1#a']); + validateMatch(queryWhy('b', hoisted), ['b']); + }); + test('can determine a deep nohoist module', () => { + const hoisted: HoistManifestTuples = [ + mockHoistManifestTuple('b', 'b', ['workspace-1#b']), + mockHoistManifestTuple('c', 'workspace-1#a#c', []), + mockHoistManifestTuple('a', 'workspace-1#a', []), + ]; + validateMatch(queryWhy('a', hoisted), ['workspace-1#a']); + validateMatch(queryWhy('c', hoisted), ['workspace-1#a#c']); + validateMatch(queryWhy('a#c', hoisted), ['workspace-1#a#c']); + }); + test('can return multiple matches', () => { + const hoisted: HoistManifestTuples = [ + mockHoistManifestTuple('b', 'b', ['workspace-1#b']), + mockHoistManifestTuple('b', 'c#b', []), + mockHoistManifestTuple('a', 'workspace-1#a', []), + mockHoistManifestTuple('c', 'c', ['workspace-1#c']), + ]; + validateMatch(queryWhy('b', hoisted), ['b', 'c#b']); + }); +}); diff --git a/__tests__/config.js b/__tests__/config.js index b188305c10..8c52a3ba1a 100644 --- a/__tests__/config.js +++ b/__tests__/config.js @@ -1,7 +1,8 @@ /* @flow */ -import Config from '../src/config.js'; -import {ConsoleReporter} from '../src/reporters/index.js'; +import Config, {extractWorkspaces} from '../src/config.js'; +import {ConsoleReporter, BufferReporter} from '../src/reporters/index.js'; +import type {WorkspacesConfig, Manifest} from '../src/types.js'; const stream = require('stream'); @@ -42,3 +43,181 @@ test('getOption does not change empty-string when resolve=false', async () => { config.registries.yarn.config.cafile = ''; expect(config.getOption('cafile', false)).toEqual(''); }); + +describe('workspaces config', () => { + function createWorkspaceManifest(packages: Array, nohoist: Array): Manifest { + const workspaces: WorkspacesConfig = { + packages, + nohoist, + }; + const manifest: Manifest = { + _uid: 'whatever', + version: '1.0', + name: 'whatever', + private: true, + workspaces, + }; + + return manifest; + } + function validateWS(expected: ?WorkspacesConfig, actual: ?WorkspacesConfig) { + if (!expected) { + expect(actual).toBeUndefined(); + return; + } + if (!actual) { + expect(actual).not.toBeUndefined(); + return; + } + + expect(actual.packages).toEqual(expected.packages); + expect(actual.nohoist).toEqual(expected.nohoist); + } + test('accessing workspaces config requires explicit enabling', async () => { + const config = await initConfig({}); + const packages = ['w1', 'w2']; + const nohoist = ['a']; + const manifest = createWorkspaceManifest(packages, nohoist); + + config.workspacesEnabled = false; + expect(config.getWorkspaces(manifest)).toBeUndefined(); + + config.workspacesEnabled = true; + const ws = config.getWorkspaces(manifest); + if (!ws) { + expect(ws).not.toBeUndefined(); + } else { + expect(ws.packages).toEqual(packages); + expect(ws.nohoist).toEqual(nohoist); + } + }); + + test('can adapt legacy workspaces to new format', () => { + const packages = ['w1', 'w2']; + const nohoist = ['a']; + const manifest = createWorkspaceManifest(packages, nohoist); + + const expected: WorkspacesConfig = { + packages, + nohoist, + }; + + // manifest.workspaces = newWorkspaces; + validateWS(expected, extractWorkspaces(manifest)); + + manifest.workspaces = packages; + expected.nohoist = undefined; + validateWS(expected, extractWorkspaces(manifest)); + + manifest.workspaces = undefined; + validateWS(undefined, extractWorkspaces(manifest)); + + manifest.workspaces = {}; + validateWS(undefined, extractWorkspaces(manifest)); + }); + test('workspaces is eligibile only for private packages', async () => { + const config = await initConfig({}); + const packages = ['w1', 'w2']; + const nohoist = ['a']; + const manifest = createWorkspaceManifest(packages, nohoist); + config.workspacesEnabled = true; + expect(config.getWorkspaces(manifest)).not.toBeUndefined(); + + manifest.private = false; + expect(config.getWorkspaces(manifest)).toBeUndefined(); + }); + test('nohoist is eligibile only for private packages and workspacesNohoistEnabled', async () => { + const config = await initConfig({}); + const packages = ['w1', 'w2']; + const nohoist = ['a']; + const manifest = createWorkspaceManifest(packages, nohoist); + + // any one of these flag would turn off nohoist + function testNohoistEligibility(isPrivate: boolean, workspacesNohoistEnabled: boolean, expectEligibility: boolean) { + manifest.private = isPrivate; + config.workspacesNohoistEnabled = workspacesNohoistEnabled; + const ws = config.getWorkspaces(manifest); + if (ws) { + if (!expectEligibility) { + expect(ws.nohoist).toBeUndefined(); + } else { + expect(ws.nohoist).toEqual(nohoist); + } + } else { + if (expectEligibility) { + expect(ws).not.toBeUndefined(); + } + } + } + + testNohoistEligibility(true, false, false); + testNohoistEligibility(false, true, false); + testNohoistEligibility(true, true, true); + }); + test('can throw exception for eligibility violation', async () => { + const config = await initConfig({}); + const packages = ['w1', 'w2']; + const nohoist = ['a']; + const manifest = createWorkspaceManifest(packages, nohoist); + + manifest.private = false; + const ws = config.getWorkspaces(manifest); + expect(ws).toBeUndefined(); + + try { + config.getWorkspaces(manifest, true); + expect(`exception to be thrown`).toEqual('but it did not...'); + } catch (e) { + // ok + } + + // should not thrown if manifest is eligibile + manifest.private = true; + expect(config.getWorkspaces(manifest, true)).not.toBeUndefined(); + }); + test('can report eligibility warnings', async () => { + const config = await initConfig({}); + const nohoist = ['a']; + const manifest = createWorkspaceManifest([], nohoist); + + function getNohoist(ws: ?WorkspacesConfig): ?Array { + return ws ? ws.nohoist : undefined; + } + + const mockReporter = new MockReporter(); + config.reporter = mockReporter; + + // when everything is fine, reporter should be empty + expect(getNohoist(config.getWorkspaces(manifest, false))).not.toBeUndefined(); + expect(mockReporter.numberOfCalls()).toEqual(0); + + config.workspacesNohoistEnabled = false; + expect(getNohoist(config.getWorkspaces(manifest, false))).toBeUndefined(); + expect(mockReporter.numberOfCalls()).toEqual(1); + expect(mockReporter.findCalls('workspacesNohoistDisabled').length).toEqual(1); + + mockReporter.reset(); + + config.workspacesNohoistEnabled = true; + manifest.private = false; + expect(getNohoist(config.getWorkspaces(manifest, false))).toBeUndefined(); + expect(mockReporter.numberOfCalls()).toEqual(1); + expect(mockReporter.findCalls('workspacesNohoistRequirePrivatePackages').length).toEqual(1); + }); +}); + +class MockReporter extends BufferReporter { + lang = jest.fn(); + + findCalls(key: string): Array> { + return this.lang.mock.calls.filter(call => { + return call[0] === key; + }); + } + numberOfCalls(): number { + return this.lang.mock.calls.length; + } + reset() { + this.lang.mockReset(); + } +} diff --git a/__tests__/fixtures/install/install-bin-links-conflicting-names/a-dep/bin b/__tests__/fixtures/install/install-bin-links-conflicting-names/a-dep/bin new file mode 100755 index 0000000000..d993532d9a --- /dev/null +++ b/__tests__/fixtures/install/install-bin-links-conflicting-names/a-dep/bin @@ -0,0 +1,2 @@ +#!/usr/bin/env node +console.log('direct a-dep'); diff --git a/__tests__/fixtures/install/install-bin-links-conflicting-names/a-dep/c-dep/bin b/__tests__/fixtures/install/install-bin-links-conflicting-names/a-dep/c-dep/bin new file mode 100755 index 0000000000..3953becac0 --- /dev/null +++ b/__tests__/fixtures/install/install-bin-links-conflicting-names/a-dep/c-dep/bin @@ -0,0 +1,2 @@ +#!/usr/bin/env node +console.log('transient c-dep'); diff --git a/__tests__/fixtures/install/install-bin-links-conflicting-names/a-dep/c-dep/package.json b/__tests__/fixtures/install/install-bin-links-conflicting-names/a-dep/c-dep/package.json new file mode 100644 index 0000000000..f0b4669749 --- /dev/null +++ b/__tests__/fixtures/install/install-bin-links-conflicting-names/a-dep/c-dep/package.json @@ -0,0 +1,7 @@ +{ + "name": "c-dep", + "version": "0.0.1", + "bin": { + "binlink2": "./bin" + } +} diff --git a/__tests__/fixtures/install/install-bin-links-conflicting-names/a-dep/package.json b/__tests__/fixtures/install/install-bin-links-conflicting-names/a-dep/package.json new file mode 100644 index 0000000000..6be8db4d09 --- /dev/null +++ b/__tests__/fixtures/install/install-bin-links-conflicting-names/a-dep/package.json @@ -0,0 +1,10 @@ +{ + "name": "a-dep", + "version": "0.0.1", + "bin": { + "binlink1": "./bin" + }, + "dependencies": { + "c-dep": "file:c-dep" + } +} diff --git a/__tests__/fixtures/install/install-bin-links-conflicting-names/f-dep/bin b/__tests__/fixtures/install/install-bin-links-conflicting-names/f-dep/bin new file mode 100755 index 0000000000..526ad3e3f2 --- /dev/null +++ b/__tests__/fixtures/install/install-bin-links-conflicting-names/f-dep/bin @@ -0,0 +1,2 @@ +#!/usr/bin/env node +console.log('direct f-dep'); diff --git a/__tests__/fixtures/install/install-bin-links-conflicting-names/f-dep/d-dep/bin b/__tests__/fixtures/install/install-bin-links-conflicting-names/f-dep/d-dep/bin new file mode 100755 index 0000000000..856f0d437a --- /dev/null +++ b/__tests__/fixtures/install/install-bin-links-conflicting-names/f-dep/d-dep/bin @@ -0,0 +1,2 @@ +#!/usr/bin/env node +console.log('transient d-dep'); diff --git a/__tests__/fixtures/install/install-bin-links-conflicting-names/f-dep/d-dep/package.json b/__tests__/fixtures/install/install-bin-links-conflicting-names/f-dep/d-dep/package.json new file mode 100644 index 0000000000..725f563fea --- /dev/null +++ b/__tests__/fixtures/install/install-bin-links-conflicting-names/f-dep/d-dep/package.json @@ -0,0 +1,7 @@ +{ + "name": "d-dep", + "version": "0.0.1", + "bin": { + "binlink1": "./bin" + } +} diff --git a/__tests__/fixtures/install/install-bin-links-conflicting-names/f-dep/package.json b/__tests__/fixtures/install/install-bin-links-conflicting-names/f-dep/package.json new file mode 100644 index 0000000000..16c62e620f --- /dev/null +++ b/__tests__/fixtures/install/install-bin-links-conflicting-names/f-dep/package.json @@ -0,0 +1,10 @@ +{ + "name": "b-dep", + "version": "0.0.1", + "bin": { + "binlink2": "./bin" + }, + "dependencies": { + "d-dep": "file:d-dep" + } +} diff --git a/__tests__/fixtures/install/install-bin-links-conflicting-names/package.json b/__tests__/fixtures/install/install-bin-links-conflicting-names/package.json new file mode 100644 index 0000000000..4862ab982b --- /dev/null +++ b/__tests__/fixtures/install/install-bin-links-conflicting-names/package.json @@ -0,0 +1,6 @@ +{ + "dependencies": { + "a-dep": "file:a-dep", + "f-dep": "file:f-dep" + } +} diff --git a/__tests__/fixtures/install/peer-dep-included-at-2-levels/b/package.json b/__tests__/fixtures/install/peer-dep-included-at-2-levels/b/package.json new file mode 100644 index 0000000000..c8773ac8fa --- /dev/null +++ b/__tests__/fixtures/install/peer-dep-included-at-2-levels/b/package.json @@ -0,0 +1,11 @@ +{ + "name": "b", + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "caniuse-api": "^2.0.0" + }, + "peerDependencies": { + "caniuse-lite": "^1.0.30000697" + } +} diff --git a/__tests__/fixtures/install/peer-dep-included-at-2-levels/package.json b/__tests__/fixtures/install/peer-dep-included-at-2-levels/package.json new file mode 100644 index 0000000000..190b600fc8 --- /dev/null +++ b/__tests__/fixtures/install/peer-dep-included-at-2-levels/package.json @@ -0,0 +1,9 @@ +{ + "name": "a", + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "b": "file:./b", + "caniuse-lite": "^1.0.0" + } +} diff --git a/__tests__/fixtures/install/workspaces-install-nohoist-across-versions/a/package.json b/__tests__/fixtures/install/workspaces-install-nohoist-across-versions/a/package.json new file mode 100644 index 0000000000..0f628dcd04 --- /dev/null +++ b/__tests__/fixtures/install/workspaces-install-nohoist-across-versions/a/package.json @@ -0,0 +1,7 @@ +{ + "name": "a", + "version": "0.0.0", + "dependencies": { + "b": "file:../b" + } +} diff --git a/__tests__/fixtures/install/workspaces-install-nohoist-across-versions/b-2/package.json b/__tests__/fixtures/install/workspaces-install-nohoist-across-versions/b-2/package.json new file mode 100644 index 0000000000..57549744f3 --- /dev/null +++ b/__tests__/fixtures/install/workspaces-install-nohoist-across-versions/b-2/package.json @@ -0,0 +1,4 @@ +{ + "name": "b", + "version": "2.0.0" +} diff --git a/__tests__/fixtures/install/workspaces-install-nohoist-across-versions/b/package.json b/__tests__/fixtures/install/workspaces-install-nohoist-across-versions/b/package.json new file mode 100644 index 0000000000..64fa5bdefa --- /dev/null +++ b/__tests__/fixtures/install/workspaces-install-nohoist-across-versions/b/package.json @@ -0,0 +1,7 @@ +{ + "name": "b", + "version": "0.0.0", + "dependencies": { + "c": "file:../c" + } +} diff --git a/__tests__/fixtures/install/workspaces-install-nohoist-across-versions/c/package.json b/__tests__/fixtures/install/workspaces-install-nohoist-across-versions/c/package.json new file mode 100644 index 0000000000..0c0656c6d6 --- /dev/null +++ b/__tests__/fixtures/install/workspaces-install-nohoist-across-versions/c/package.json @@ -0,0 +1,7 @@ +{ + "name": "c", + "version": "0.0.0", + "dependencies": { + "b": "file:../b-2" + } +} diff --git a/__tests__/fixtures/install/workspaces-install-nohoist-across-versions/d/package.json b/__tests__/fixtures/install/workspaces-install-nohoist-across-versions/d/package.json new file mode 100644 index 0000000000..38bc130e4d --- /dev/null +++ b/__tests__/fixtures/install/workspaces-install-nohoist-across-versions/d/package.json @@ -0,0 +1,4 @@ +{ + "name": "d", + "version": "0.0.0" +} diff --git a/__tests__/fixtures/install/workspaces-install-nohoist-across-versions/package.json b/__tests__/fixtures/install/workspaces-install-nohoist-across-versions/package.json new file mode 100644 index 0000000000..e214916309 --- /dev/null +++ b/__tests__/fixtures/install/workspaces-install-nohoist-across-versions/package.json @@ -0,0 +1,8 @@ +{ + "name": "my-project", + "private": true, + "workspaces": { + "packages": ["packages/*"], + "nohoist": ["**/a", "**/b", "**/c"] + } +} diff --git a/__tests__/fixtures/install/workspaces-install-nohoist-across-versions/packages/workspace-1/package.json b/__tests__/fixtures/install/workspaces-install-nohoist-across-versions/packages/workspace-1/package.json new file mode 100644 index 0000000000..0cc3ae718d --- /dev/null +++ b/__tests__/fixtures/install/workspaces-install-nohoist-across-versions/packages/workspace-1/package.json @@ -0,0 +1,9 @@ +{ + "name": "workspace-1", + "version": "1.0.0", + "private": true, + "dependencies": { + "a": "file:../../a", + "c": "file:../../c" + } +} diff --git a/__tests__/fixtures/install/workspaces-install-nohoist-across-versions/packages/workspace-2/package.json b/__tests__/fixtures/install/workspaces-install-nohoist-across-versions/packages/workspace-2/package.json new file mode 100644 index 0000000000..bb344c7f76 --- /dev/null +++ b/__tests__/fixtures/install/workspaces-install-nohoist-across-versions/packages/workspace-2/package.json @@ -0,0 +1,9 @@ +{ + "name": "workspace-2", + "version": "1.0.0", + "private": true, + "dependencies": { + "b": "file:../../b", + "c": "file:../../c" + } +} diff --git a/__tests__/fixtures/install/workspaces-install-nohoist-across-versions/packages/workspace-3/package.json b/__tests__/fixtures/install/workspaces-install-nohoist-across-versions/packages/workspace-3/package.json new file mode 100644 index 0000000000..1f89e05677 --- /dev/null +++ b/__tests__/fixtures/install/workspaces-install-nohoist-across-versions/packages/workspace-3/package.json @@ -0,0 +1,9 @@ +{ + "name": "workspace-3", + "version": "1.0.0", + "private": true, + "dependencies": { + "b": "file:../../b-2", + "d": "file:../../d" + } +} diff --git a/__tests__/fixtures/install/workspaces-install-nohoist-all-from-root/a/package.json b/__tests__/fixtures/install/workspaces-install-nohoist-all-from-root/a/package.json new file mode 100644 index 0000000000..0f628dcd04 --- /dev/null +++ b/__tests__/fixtures/install/workspaces-install-nohoist-all-from-root/a/package.json @@ -0,0 +1,7 @@ +{ + "name": "a", + "version": "0.0.0", + "dependencies": { + "b": "file:../b" + } +} diff --git a/__tests__/fixtures/install/workspaces-install-nohoist-all-from-root/b-2/package.json b/__tests__/fixtures/install/workspaces-install-nohoist-all-from-root/b-2/package.json new file mode 100644 index 0000000000..57549744f3 --- /dev/null +++ b/__tests__/fixtures/install/workspaces-install-nohoist-all-from-root/b-2/package.json @@ -0,0 +1,4 @@ +{ + "name": "b", + "version": "2.0.0" +} diff --git a/__tests__/fixtures/install/workspaces-install-nohoist-all-from-root/b/package.json b/__tests__/fixtures/install/workspaces-install-nohoist-all-from-root/b/package.json new file mode 100644 index 0000000000..64fa5bdefa --- /dev/null +++ b/__tests__/fixtures/install/workspaces-install-nohoist-all-from-root/b/package.json @@ -0,0 +1,7 @@ +{ + "name": "b", + "version": "0.0.0", + "dependencies": { + "c": "file:../c" + } +} diff --git a/__tests__/fixtures/install/workspaces-install-nohoist-all-from-root/c/package.json b/__tests__/fixtures/install/workspaces-install-nohoist-all-from-root/c/package.json new file mode 100644 index 0000000000..0c0656c6d6 --- /dev/null +++ b/__tests__/fixtures/install/workspaces-install-nohoist-all-from-root/c/package.json @@ -0,0 +1,7 @@ +{ + "name": "c", + "version": "0.0.0", + "dependencies": { + "b": "file:../b-2" + } +} diff --git a/__tests__/fixtures/install/workspaces-install-nohoist-all-from-root/d/package.json b/__tests__/fixtures/install/workspaces-install-nohoist-all-from-root/d/package.json new file mode 100644 index 0000000000..38bc130e4d --- /dev/null +++ b/__tests__/fixtures/install/workspaces-install-nohoist-all-from-root/d/package.json @@ -0,0 +1,4 @@ +{ + "name": "d", + "version": "0.0.0" +} diff --git a/__tests__/fixtures/install/workspaces-install-nohoist-all-from-root/package.json b/__tests__/fixtures/install/workspaces-install-nohoist-all-from-root/package.json new file mode 100644 index 0000000000..27c227f3e0 --- /dev/null +++ b/__tests__/fixtures/install/workspaces-install-nohoist-all-from-root/package.json @@ -0,0 +1,8 @@ +{ + "name": "my-project", + "private": true, + "workspaces": { + "packages": ["packages/*"], + "nohoist": ["**"] + } +} diff --git a/__tests__/fixtures/install/workspaces-install-nohoist-all-from-root/packages/workspace-disable-a/package.json b/__tests__/fixtures/install/workspaces-install-nohoist-all-from-root/packages/workspace-disable-a/package.json new file mode 100644 index 0000000000..0016f8be81 --- /dev/null +++ b/__tests__/fixtures/install/workspaces-install-nohoist-all-from-root/packages/workspace-disable-a/package.json @@ -0,0 +1,12 @@ +{ + "name": "workspace-disable-a", + "version": "1.0.0", + "private": true, + "dependencies": { + "a": "file:../../a", + "d": "file:../../d" + }, + "workspaces": { + "nohoist": ["a"] + } +} diff --git a/__tests__/fixtures/install/workspaces-install-nohoist-all-from-root/packages/workspace-disable-all/package.json b/__tests__/fixtures/install/workspaces-install-nohoist-all-from-root/packages/workspace-disable-all/package.json new file mode 100644 index 0000000000..49120d2521 --- /dev/null +++ b/__tests__/fixtures/install/workspaces-install-nohoist-all-from-root/packages/workspace-disable-all/package.json @@ -0,0 +1,12 @@ +{ + "name": "workspace-disable-all", + "version": "1.0.0", + "private": true, + "dependencies": { + "c": "file:../../c", + "d": "file:../../d" + }, + "workspaces": { + "nohoist": ["**"] + } +} diff --git a/__tests__/fixtures/install/workspaces-install-nohoist-all-from-root/packages/workspace-hoist-all/package.json b/__tests__/fixtures/install/workspaces-install-nohoist-all-from-root/packages/workspace-hoist-all/package.json new file mode 100644 index 0000000000..47168c950c --- /dev/null +++ b/__tests__/fixtures/install/workspaces-install-nohoist-all-from-root/packages/workspace-hoist-all/package.json @@ -0,0 +1,9 @@ +{ + "name": "workspace-hoist-all", + "version": "1.0.0", + "private": true, + "dependencies": { + "b": "file:../../b-2", + "d": "file:../../d" + } +} diff --git a/__tests__/fixtures/install/workspaces-install-nohoist-by-ws/a/package.json b/__tests__/fixtures/install/workspaces-install-nohoist-by-ws/a/package.json new file mode 100644 index 0000000000..0f628dcd04 --- /dev/null +++ b/__tests__/fixtures/install/workspaces-install-nohoist-by-ws/a/package.json @@ -0,0 +1,7 @@ +{ + "name": "a", + "version": "0.0.0", + "dependencies": { + "b": "file:../b" + } +} diff --git a/__tests__/fixtures/install/workspaces-install-nohoist-by-ws/b-2/package.json b/__tests__/fixtures/install/workspaces-install-nohoist-by-ws/b-2/package.json new file mode 100644 index 0000000000..57549744f3 --- /dev/null +++ b/__tests__/fixtures/install/workspaces-install-nohoist-by-ws/b-2/package.json @@ -0,0 +1,4 @@ +{ + "name": "b", + "version": "2.0.0" +} diff --git a/__tests__/fixtures/install/workspaces-install-nohoist-by-ws/b/package.json b/__tests__/fixtures/install/workspaces-install-nohoist-by-ws/b/package.json new file mode 100644 index 0000000000..64fa5bdefa --- /dev/null +++ b/__tests__/fixtures/install/workspaces-install-nohoist-by-ws/b/package.json @@ -0,0 +1,7 @@ +{ + "name": "b", + "version": "0.0.0", + "dependencies": { + "c": "file:../c" + } +} diff --git a/__tests__/fixtures/install/workspaces-install-nohoist-by-ws/c/package.json b/__tests__/fixtures/install/workspaces-install-nohoist-by-ws/c/package.json new file mode 100644 index 0000000000..0c0656c6d6 --- /dev/null +++ b/__tests__/fixtures/install/workspaces-install-nohoist-by-ws/c/package.json @@ -0,0 +1,7 @@ +{ + "name": "c", + "version": "0.0.0", + "dependencies": { + "b": "file:../b-2" + } +} diff --git a/__tests__/fixtures/install/workspaces-install-nohoist-by-ws/d/package.json b/__tests__/fixtures/install/workspaces-install-nohoist-by-ws/d/package.json new file mode 100644 index 0000000000..38bc130e4d --- /dev/null +++ b/__tests__/fixtures/install/workspaces-install-nohoist-by-ws/d/package.json @@ -0,0 +1,4 @@ +{ + "name": "d", + "version": "0.0.0" +} diff --git a/__tests__/fixtures/install/workspaces-install-nohoist-by-ws/package.json b/__tests__/fixtures/install/workspaces-install-nohoist-by-ws/package.json new file mode 100644 index 0000000000..8d9019a1f3 --- /dev/null +++ b/__tests__/fixtures/install/workspaces-install-nohoist-by-ws/package.json @@ -0,0 +1,7 @@ +{ + "name": "my-project", + "private": true, + "workspaces": { + "packages": ["packages/*"] + } +} diff --git a/__tests__/fixtures/install/workspaces-install-nohoist-by-ws/packages/workspace-disable-a/package.json b/__tests__/fixtures/install/workspaces-install-nohoist-by-ws/packages/workspace-disable-a/package.json new file mode 100644 index 0000000000..0016f8be81 --- /dev/null +++ b/__tests__/fixtures/install/workspaces-install-nohoist-by-ws/packages/workspace-disable-a/package.json @@ -0,0 +1,12 @@ +{ + "name": "workspace-disable-a", + "version": "1.0.0", + "private": true, + "dependencies": { + "a": "file:../../a", + "d": "file:../../d" + }, + "workspaces": { + "nohoist": ["a"] + } +} diff --git a/__tests__/fixtures/install/workspaces-install-nohoist-by-ws/packages/workspace-disable-all/package.json b/__tests__/fixtures/install/workspaces-install-nohoist-by-ws/packages/workspace-disable-all/package.json new file mode 100644 index 0000000000..056f9e0117 --- /dev/null +++ b/__tests__/fixtures/install/workspaces-install-nohoist-by-ws/packages/workspace-disable-all/package.json @@ -0,0 +1,13 @@ +{ + "name": "workspace-disable-all", + "version": "1.0.0", + "private": true, + "dependencies": { + "c": "file:../../c", + "d": "file:../../d", + "workspace-hoist-all": "^1.0.0" + }, + "workspaces": { + "nohoist": ["**"] + } +} diff --git a/__tests__/fixtures/install/workspaces-install-nohoist-by-ws/packages/workspace-hoist-all/package.json b/__tests__/fixtures/install/workspaces-install-nohoist-by-ws/packages/workspace-hoist-all/package.json new file mode 100644 index 0000000000..47168c950c --- /dev/null +++ b/__tests__/fixtures/install/workspaces-install-nohoist-by-ws/packages/workspace-hoist-all/package.json @@ -0,0 +1,9 @@ +{ + "name": "workspace-hoist-all", + "version": "1.0.0", + "private": true, + "dependencies": { + "b": "file:../../b-2", + "d": "file:../../d" + } +} diff --git a/__tests__/fixtures/install/workspaces-install-nohoist-some-from-root/a/package.json b/__tests__/fixtures/install/workspaces-install-nohoist-some-from-root/a/package.json new file mode 100644 index 0000000000..0f628dcd04 --- /dev/null +++ b/__tests__/fixtures/install/workspaces-install-nohoist-some-from-root/a/package.json @@ -0,0 +1,7 @@ +{ + "name": "a", + "version": "0.0.0", + "dependencies": { + "b": "file:../b" + } +} diff --git a/__tests__/fixtures/install/workspaces-install-nohoist-some-from-root/b-2/package.json b/__tests__/fixtures/install/workspaces-install-nohoist-some-from-root/b-2/package.json new file mode 100644 index 0000000000..57549744f3 --- /dev/null +++ b/__tests__/fixtures/install/workspaces-install-nohoist-some-from-root/b-2/package.json @@ -0,0 +1,4 @@ +{ + "name": "b", + "version": "2.0.0" +} diff --git a/__tests__/fixtures/install/workspaces-install-nohoist-some-from-root/b/package.json b/__tests__/fixtures/install/workspaces-install-nohoist-some-from-root/b/package.json new file mode 100644 index 0000000000..64fa5bdefa --- /dev/null +++ b/__tests__/fixtures/install/workspaces-install-nohoist-some-from-root/b/package.json @@ -0,0 +1,7 @@ +{ + "name": "b", + "version": "0.0.0", + "dependencies": { + "c": "file:../c" + } +} diff --git a/__tests__/fixtures/install/workspaces-install-nohoist-some-from-root/c/package.json b/__tests__/fixtures/install/workspaces-install-nohoist-some-from-root/c/package.json new file mode 100644 index 0000000000..0c0656c6d6 --- /dev/null +++ b/__tests__/fixtures/install/workspaces-install-nohoist-some-from-root/c/package.json @@ -0,0 +1,7 @@ +{ + "name": "c", + "version": "0.0.0", + "dependencies": { + "b": "file:../b-2" + } +} diff --git a/__tests__/fixtures/install/workspaces-install-nohoist-some-from-root/d/package.json b/__tests__/fixtures/install/workspaces-install-nohoist-some-from-root/d/package.json new file mode 100644 index 0000000000..38bc130e4d --- /dev/null +++ b/__tests__/fixtures/install/workspaces-install-nohoist-some-from-root/d/package.json @@ -0,0 +1,4 @@ +{ + "name": "d", + "version": "0.0.0" +} diff --git a/__tests__/fixtures/install/workspaces-install-nohoist-some-from-root/package.json b/__tests__/fixtures/install/workspaces-install-nohoist-some-from-root/package.json new file mode 100644 index 0000000000..10abfeab74 --- /dev/null +++ b/__tests__/fixtures/install/workspaces-install-nohoist-some-from-root/package.json @@ -0,0 +1,8 @@ +{ + "name": "my-project", + "private": true, + "workspaces": { + "packages": ["packages/*"], + "nohoist": ["**/d"] + } +} diff --git a/__tests__/fixtures/install/workspaces-install-nohoist-some-from-root/packages/workspace-disable-a/package.json b/__tests__/fixtures/install/workspaces-install-nohoist-some-from-root/packages/workspace-disable-a/package.json new file mode 100644 index 0000000000..0016f8be81 --- /dev/null +++ b/__tests__/fixtures/install/workspaces-install-nohoist-some-from-root/packages/workspace-disable-a/package.json @@ -0,0 +1,12 @@ +{ + "name": "workspace-disable-a", + "version": "1.0.0", + "private": true, + "dependencies": { + "a": "file:../../a", + "d": "file:../../d" + }, + "workspaces": { + "nohoist": ["a"] + } +} diff --git a/__tests__/fixtures/install/workspaces-install-nohoist-some-from-root/packages/workspace-disable-all/package.json b/__tests__/fixtures/install/workspaces-install-nohoist-some-from-root/packages/workspace-disable-all/package.json new file mode 100644 index 0000000000..49120d2521 --- /dev/null +++ b/__tests__/fixtures/install/workspaces-install-nohoist-some-from-root/packages/workspace-disable-all/package.json @@ -0,0 +1,12 @@ +{ + "name": "workspace-disable-all", + "version": "1.0.0", + "private": true, + "dependencies": { + "c": "file:../../c", + "d": "file:../../d" + }, + "workspaces": { + "nohoist": ["**"] + } +} diff --git a/__tests__/fixtures/install/workspaces-install-nohoist-some-from-root/packages/workspace-hoist-all/package.json b/__tests__/fixtures/install/workspaces-install-nohoist-some-from-root/packages/workspace-hoist-all/package.json new file mode 100644 index 0000000000..47168c950c --- /dev/null +++ b/__tests__/fixtures/install/workspaces-install-nohoist-some-from-root/packages/workspace-hoist-all/package.json @@ -0,0 +1,9 @@ +{ + "name": "workspace-hoist-all", + "version": "1.0.0", + "private": true, + "dependencies": { + "b": "file:../../b-2", + "d": "file:../../d" + } +} diff --git a/__tests__/fixtures/list/no-dev-deps-production/a/index.js b/__tests__/fixtures/list/no-dev-deps-production/a/index.js new file mode 100644 index 0000000000..5e8802b488 --- /dev/null +++ b/__tests__/fixtures/list/no-dev-deps-production/a/index.js @@ -0,0 +1 @@ +left-pad; diff --git a/__tests__/fixtures/list/no-dev-deps-production/a/package.json b/__tests__/fixtures/list/no-dev-deps-production/a/package.json new file mode 100644 index 0000000000..9113c2528e --- /dev/null +++ b/__tests__/fixtures/list/no-dev-deps-production/a/package.json @@ -0,0 +1,4 @@ +{ + "name": "a", + "version": "1.0.0" +} diff --git a/__tests__/fixtures/list/no-dev-deps-production/package.json b/__tests__/fixtures/list/no-dev-deps-production/package.json new file mode 100644 index 0000000000..10f20a42d8 --- /dev/null +++ b/__tests__/fixtures/list/no-dev-deps-production/package.json @@ -0,0 +1,5 @@ +{ + "dependencies": { + "a": "file:./a" + } +} diff --git a/__tests__/fixtures/list/no-dev-deps-production/yarn.lock b/__tests__/fixtures/list/no-dev-deps-production/yarn.lock new file mode 100644 index 0000000000..f8564acbc3 --- /dev/null +++ b/__tests__/fixtures/list/no-dev-deps-production/yarn.lock @@ -0,0 +1,6 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"a@file:./a": + version "1.0.0" diff --git a/__tests__/fixtures/publish/minimal/package.json b/__tests__/fixtures/publish/minimal/package.json new file mode 100644 index 0000000000..1545befa16 --- /dev/null +++ b/__tests__/fixtures/publish/minimal/package.json @@ -0,0 +1,4 @@ +{ + "name": "test", + "version": "0.0.0" +} diff --git a/__tests__/fixtures/publish/public/package.json b/__tests__/fixtures/publish/public/package.json new file mode 100644 index 0000000000..0de9c86d5d --- /dev/null +++ b/__tests__/fixtures/publish/public/package.json @@ -0,0 +1,7 @@ +{ + "name": "test", + "version": "0.0.0", + "publishConfig": { + "access": "public" + } +} diff --git a/__tests__/fixtures/request-cache/GET/registry.yarnpkg.com/browserslist.bin b/__tests__/fixtures/request-cache/GET/registry.yarnpkg.com/browserslist.bin new file mode 100644 index 0000000000..7b1c57a4f9 --- /dev/null +++ b/__tests__/fixtures/request-cache/GET/registry.yarnpkg.com/browserslist.bin @@ -0,0 +1,21 @@ +HTTP/1.1 200 OK +Date: Mon, 11 Dec 2017 18:38:51 GMT +Content-Type: application/vnd.npm.install-v1+json +Content-Length: 35115 +Connection: keep-alive +Set-Cookie: __cfduid=d88832e1949be97719a1f327c4bc4f7421513017531; expires=Tue, 11-Dec-18 18:38:51 GMT; path=/; domain=.yarnpkg.com; HttpOnly +Cache-Control: max-age=300 +Last-Modified: Wed, 6 Dec 2017 18:43:00 GMT +ETag: "5a283a34-892b" +Accept-Ranges: bytes +Via: 1.1 varnish +Age: 4519 +X-Served-By: cache-mdw17347-MDW +X-Cache: HIT +X-Cache-Hits: 1 +X-Timer: S1513017532.709306,VS0,VE0 +Vary: Accept-Encoding, Accept +Server: cloudflare-nginx +CF-RAY: 3cba90352e7f5625-ORD + +{"versions":{"0.1.0":{"name":"browserslist","version":"0.1.0","dependencies":{"caniuse-db":"^1.0.30000032 "},"devDependencies":{"jshint-stylish":"1.0.0","gulp-jshint":"1.9.0","gulp-mocha":"2.0.0","mocha":"2.0.1","chai":"1.10.0","gulp":"3.8.10"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"b566254ca06832bd3326f1559a2361fed92bd691","tarball":"https://registry.npmjs.org/browserslist/-/browserslist-0.1.0.tgz"}},"0.1.1":{"name":"browserslist","version":"0.1.1","dependencies":{"caniuse-db":"^1.0.30000043"},"devDependencies":{"jshint-stylish":"1.0.0","gulp-jshint":"1.9.0","gulp-mocha":"2.0.0","mocha":"2.1.0","chai":"1.10.0","gulp":"3.8.10"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"279e955e6e00afcfc4dcc6160d79aea44db0645c","tarball":"https://registry.npmjs.org/browserslist/-/browserslist-0.1.1.tgz"}},"0.1.2":{"name":"browserslist","version":"0.1.2","dependencies":{"caniuse-db":"^1.0.30000048"},"devDependencies":{"jshint-stylish":"1.0.0","gulp-jshint":"1.9.0","gulp-mocha":"2.0.0","mocha":"2.1.0","chai":"1.10.0","gulp":"3.8.10"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"e27e20730dd426149bab8051073a41fc9d3cf238","tarball":"https://registry.npmjs.org/browserslist/-/browserslist-0.1.2.tgz"}},"0.1.3":{"name":"browserslist","version":"0.1.3","dependencies":{"caniuse-db":"^1.0.30000054"},"devDependencies":{"jshint-stylish":"1.0.0","gulp-jshint":"1.9.0","gulp-mocha":"2.0.0","mocha":"2.1.0","chai":"1.10.0","gulp":"3.8.10"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"2f67975c24bb357b6b48b4bc46e7c39a1f0b3b5b","tarball":"https://registry.npmjs.org/browserslist/-/browserslist-0.1.3.tgz"}},"0.2.0":{"name":"browserslist","version":"0.2.0","dependencies":{"caniuse-db":"^1.0.30000054"},"devDependencies":{"jshint-stylish":"1.0.0","gulp-jshint":"1.9.0","gulp-mocha":"2.0.0","mocha":"2.1.0","chai":"1.10.0","gulp":"3.8.10"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"e5b7cf311cccb70772cd22d4f61c7bb80523ecd2","tarball":"https://registry.npmjs.org/browserslist/-/browserslist-0.2.0.tgz"}},"0.3.0":{"name":"browserslist","version":"0.3.0","dependencies":{"caniuse-db":"^1.0.30000078"},"devDependencies":{"jshint-stylish":"1.0.0","gulp-jshint":"1.9.2","gulp-mocha":"2.0.0","mocha":"2.1.0","chai":"2.0.0","gulp":"3.8.11"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"f4429e509b25e00c43d77bb60cc0be37292613f6","tarball":"https://registry.npmjs.org/browserslist/-/browserslist-0.3.0.tgz"}},"0.3.1":{"name":"browserslist","version":"0.3.1","dependencies":{"caniuse-db":"^1.0.30000081"},"devDependencies":{"jshint-stylish":"1.0.1","gulp-jshint":"1.9.2","gulp-mocha":"2.0.0","mocha":"2.1.0","chai":"2.1.0","gulp":"3.8.11"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"d60dd16f4aa10087f18b4b19d6432f9f79bdc833","tarball":"https://registry.npmjs.org/browserslist/-/browserslist-0.3.1.tgz"}},"0.3.2":{"name":"browserslist","version":"0.3.2","dependencies":{"caniuse-db":"^1.0.30000113"},"devDependencies":{"gulp-eslint":"0.6.0","gulp-mocha":"2.0.1","mocha":"2.2.1","chai":"2.2.0","gulp":"3.8.11"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"4e516ed1882086ff2479bab80cd164b3ae463545","tarball":"https://registry.npmjs.org/browserslist/-/browserslist-0.3.2.tgz"}},"0.3.3":{"name":"browserslist","version":"0.3.3","dependencies":{"caniuse-db":"^1.0.30000127"},"devDependencies":{"gulp-eslint":"0.9.0","gulp-mocha":"2.0.1","mocha":"2.2.4","chai":"2.2.0","gulp":"3.8.11"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"c21beb6b3d3c2492404084781113f39fc133f2c0","tarball":"https://registry.npmjs.org/browserslist/-/browserslist-0.3.3.tgz"}},"0.4.0":{"name":"browserslist","version":"0.4.0","dependencies":{"caniuse-db":"^1.0.30000153"},"devDependencies":{"gulp-eslint":"0.11.1","gulp-mocha":"2.0.1","mocha":"2.2.4","chai":"2.3.0","gulp":"3.8.11"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"3bd4ab9199dc1b9150d4d6dba4d9d3aabbc86dd4","tarball":"https://registry.npmjs.org/browserslist/-/browserslist-0.4.0.tgz"}},"0.5.0":{"name":"browserslist","version":"0.5.0","dependencies":{"caniuse-db":"^1.0.30000214"},"devDependencies":{"gulp-eslint":"0.14.0","gulp-mocha":"2.1.2","mocha":"2.2.5","chai":"3.0.0","gulp":"3.9.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"b82882493637c342b66ad3182c919e1dac6d1724","tarball":"https://registry.npmjs.org/browserslist/-/browserslist-0.5.0.tgz"}},"1.0.0":{"name":"browserslist","version":"1.0.0","dependencies":{"caniuse-db":"^1.0.30000281"},"devDependencies":{"gulp-eslint":"1.0.0","gulp-mocha":"2.1.3","mocha":"2.3.0","chai":"3.2.0","gulp":"3.9.0"},"bin":{"browserslist":"./cli.js"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"678336f890f2b5bd3cdf2093150533dcbab3e185","tarball":"https://registry.npmjs.org/browserslist/-/browserslist-1.0.0.tgz"}},"1.0.1":{"name":"browserslist","version":"1.0.1","dependencies":{"caniuse-db":"^1.0.30000335"},"devDependencies":{"gulp-eslint":"1.0.0","gulp-mocha":"2.1.3","mocha":"2.3.3","chai":"3.3.0","gulp":"3.9.0"},"bin":{"browserslist":"./cli.js"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"ef0dd708318cdf74325faeea59efec84d9464717","tarball":"https://registry.npmjs.org/browserslist/-/browserslist-1.0.1.tgz"}},"1.1.0":{"name":"browserslist","version":"1.1.0","dependencies":{"caniuse-db":"^1.0.30000384"},"devDependencies":{"eslint":"1.10.3","ava":"0.9.1"},"bin":{"browserslist":"./cli.js"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"a9ef42c2a51b51becefb3ce525ebee908a578bc5","tarball":"https://registry.npmjs.org/browserslist/-/browserslist-1.1.0.tgz"}},"1.1.1":{"name":"browserslist","version":"1.1.1","dependencies":{"caniuse-db":"^1.0.30000387"},"devDependencies":{"eslint":"1.10.3","ava":"0.9.1"},"bin":{"browserslist":"./cli.js"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"a333af8331160e1db14219ec1cc9b2da20cd4d37","tarball":"https://registry.npmjs.org/browserslist/-/browserslist-1.1.1.tgz"}},"1.1.2":{"name":"browserslist","version":"1.1.2","dependencies":{"caniuse-db":"^1.0.30000409"},"devDependencies":{"eslint-config-postcss":"^1.0.0","eslint":"1.10.3","ava":"0.11.0"},"bin":{"browserslist":"./cli.js"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"ee71ae31fc87764da23816fc4f09d2346a31879b","tarball":"https://registry.npmjs.org/browserslist/-/browserslist-1.1.2.tgz"}},"1.1.3":{"name":"browserslist","version":"1.1.3","dependencies":{"caniuse-db":"^1.0.30000409"},"devDependencies":{"eslint-config-postcss":"1.0.0","eslint":"1.10.3","ava":"0.11.0"},"bin":{"browserslist":"./cli.js"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"63e0f1fd68545a56eccafca55b7b722918ebfff5","tarball":"https://registry.npmjs.org/browserslist/-/browserslist-1.1.3.tgz"}},"1.2.0":{"name":"browserslist","version":"1.2.0","dependencies":{"caniuse-db":"^1.0.30000430"},"devDependencies":{"eslint-config-postcss":"2.0.2","eslint":"2.4.0","ava":"0.13.0"},"bin":{"browserslist":"./cli.js"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"ef1b039b4cdd75f43382fa13a24f2a8d5da536d0","tarball":"https://registry.npmjs.org/browserslist/-/browserslist-1.2.0.tgz"}},"1.3.0":{"name":"browserslist","version":"1.3.0","dependencies":{"caniuse-db":"^1.0.30000431"},"devDependencies":{"eslint-config-postcss":"2.0.2","eslint":"2.4.0","ava":"0.13.0"},"bin":{"browserslist":"./cli.js"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"517bca7192a3b47fd1d71a92366bb2b30b50eed2","tarball":"https://registry.npmjs.org/browserslist/-/browserslist-1.3.0.tgz"}},"1.3.1":{"name":"browserslist","version":"1.3.1","dependencies":{"caniuse-db":"^1.0.30000444"},"devDependencies":{"eslint-config-postcss":"2.0.2","eslint":"2.6.0","ava":"0.13.0"},"bin":{"browserslist":"./cli.js"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"6198006485d3a350732408dca74165b69abfa718","tarball":"https://registry.npmjs.org/browserslist/-/browserslist-1.3.1.tgz"}},"1.3.2":{"name":"browserslist","version":"1.3.2","dependencies":{"caniuse-db":"^1.0.30000471"},"devDependencies":{"eslint-config-postcss":"2.0.2","eslint":"2.11.1","ava":"0.15.1"},"bin":{"browserslist":"./cli.js"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"afb4309174edae938d3042ab0f55dcc2fd88806a","tarball":"https://registry.npmjs.org/browserslist/-/browserslist-1.3.2.tgz"}},"1.3.3":{"name":"browserslist","version":"1.3.3","dependencies":{"caniuse-db":"^1.0.30000484"},"devDependencies":{"eslint-config-postcss":"2.0.2","eslint":"2.13.0","ava":"0.15.2"},"bin":{"browserslist":"./cli.js"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"2fc1e896ed3636e2649651f74907b53254ddad6a","tarball":"https://registry.npmjs.org/browserslist/-/browserslist-1.3.3.tgz"}},"1.3.4":{"name":"browserslist","version":"1.3.4","dependencies":{"caniuse-db":"^1.0.30000488"},"devDependencies":{"eslint-config-postcss":"2.0.2","eslint":"2.13.1","ava":"0.15.2"},"bin":{"browserslist":"./cli.js"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"97bba1a98f011f976333a053706d089ffc9b30fa","tarball":"https://registry.npmjs.org/browserslist/-/browserslist-1.3.4.tgz"}},"1.3.5":{"name":"browserslist","version":"1.3.5","dependencies":{"caniuse-db":"^1.0.30000506"},"devDependencies":{"eslint-config-postcss":"2.0.2","eslint":"3.0.1","ava":"0.15.2"},"bin":{"browserslist":"./cli.js"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"2a1daf9b82b654186337ec13de4684b8f78450d7","tarball":"https://registry.npmjs.org/browserslist/-/browserslist-1.3.5.tgz"}},"1.3.6":{"name":"browserslist","version":"1.3.6","dependencies":{"caniuse-db":"^1.0.30000525"},"devDependencies":{"eslint-config-postcss":"2.0.2","eslint":"3.3.1","ava":"0.16.0"},"bin":{"browserslist":"./cli.js"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"952ff48d56463d3b538f85ef2f8eaddfd284b133","tarball":"https://registry.npmjs.org/browserslist/-/browserslist-1.3.6.tgz"}},"1.4.0":{"name":"browserslist","version":"1.4.0","dependencies":{"caniuse-db":"^1.0.30000539"},"devDependencies":{"eslint-config-postcss":"2.0.2","eslint":"3.6.0","ava":"0.16.0"},"bin":{"browserslist":"./cli.js"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"9cfdcf5384d9158f5b70da2aa00b30e8ff019049","tarball":"https://registry.npmjs.org/browserslist/-/browserslist-1.4.0.tgz"}},"1.5.0":{"name":"browserslist","version":"1.5.0","dependencies":{"caniuse-db":"^1.0.30000601"},"devDependencies":{"eslint":"^3.11.1","eslint-config-postcss":"^2.0.2","jest":"^18.0.0","lint-staged":"^3.2.2","pre-commit":"^1.1.3","yaspeller":"^3.0.0"},"bin":{"browserslist":"./cli.js"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"b9a1f3880dcc7afdf07baf48c8385200530eb126","tarball":"https://registry.npmjs.org/browserslist/-/browserslist-1.5.0.tgz"}},"1.5.1":{"name":"browserslist","version":"1.5.1","dependencies":{"caniuse-db":"^1.0.30000601"},"devDependencies":{"eslint":"^3.11.1","eslint-config-postcss":"^2.0.2","jest":"^18.0.0","lint-staged":"^3.2.2","pre-commit":"^1.1.3","yaspeller":"^3.0.0"},"bin":{"browserslist":"./cli.js"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"67c3f2a1a6ad174cd01d25d2362e6e6083b26986","tarball":"https://registry.npmjs.org/browserslist/-/browserslist-1.5.1.tgz"}},"1.5.2":{"name":"browserslist","version":"1.5.2","dependencies":{"caniuse-db":"^1.0.30000604"},"devDependencies":{"eslint":"^3.11.1","eslint-config-postcss":"^2.0.2","jest":"^18.1.0","lint-staged":"^3.2.5","pre-commit":"^1.1.3","yaspeller":"^3.0.0"},"bin":{"browserslist":"./cli.js"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"1c82fde0ee8693e6d15c49b7bff209dc06298c56","tarball":"https://registry.npmjs.org/browserslist/-/browserslist-1.5.2.tgz"}},"1.6.0":{"name":"browserslist","version":"1.6.0","dependencies":{"caniuse-db":"^1.0.30000613","electron-to-chromium":"^1.2.0"},"devDependencies":{"eslint":"^3.14.0","eslint-config-postcss":"^2.0.2","jest":"^18.1.0","lint-staged":"^3.2.7","pre-commit":"^1.1.3","yaspeller":"^3.0.0"},"bin":{"browserslist":"./cli.js"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"85fb7c993540d3fda31c282baf7f5aee698ac9ee","tarball":"https://registry.npmjs.org/browserslist/-/browserslist-1.6.0.tgz"}},"1.7.0":{"name":"browserslist","version":"1.7.0","dependencies":{"caniuse-db":"^1.0.30000617","electron-to-chromium":"^1.2.1"},"devDependencies":{"eslint":"^3.14.1","eslint-config-postcss":"^2.0.2","jest":"^18.1.0","lint-staged":"^3.2.8","pre-commit":"^1.1.3","yaspeller":"^3.0.0"},"bin":{"browserslist":"./cli.js"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"738df5b2971354d198b2fbd5a22c560d2d896084","tarball":"https://registry.npmjs.org/browserslist/-/browserslist-1.7.0.tgz"}},"1.7.1":{"name":"browserslist","version":"1.7.1","dependencies":{"caniuse-db":"^1.0.30000617","electron-to-chromium":"^1.2.1"},"devDependencies":{"eslint":"^3.14.1","eslint-config-postcss":"^2.0.2","jest":"^18.1.0","lint-staged":"^3.2.9","pre-commit":"^1.1.3","yaspeller":"^3.0.0"},"bin":{"browserslist":"./cli.js"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"cc9bd193979a2a4b09fdb3df6003fefe48ccefe1","tarball":"https://registry.npmjs.org/browserslist/-/browserslist-1.7.1.tgz"}},"1.7.2":{"name":"browserslist","version":"1.7.2","dependencies":{"caniuse-db":"^1.0.30000622","electron-to-chromium":"^1.2.2"},"devDependencies":{"eslint":"^3.15.0","eslint-config-postcss":"^2.0.2","jest":"^18.1.0","lint-staged":"^3.3.0","pre-commit":"^1.1.3","yaspeller":"^3.0.0"},"bin":{"browserslist":"./cli.js"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"cf4977283c3e692d6dcc241192e9de91504ff331","tarball":"https://registry.npmjs.org/browserslist/-/browserslist-1.7.2.tgz"}},"1.7.3":{"name":"browserslist","version":"1.7.3","dependencies":{"caniuse-db":"^1.0.30000623","electron-to-chromium":"^1.2.2"},"devDependencies":{"eslint":"^3.15.0","eslint-config-postcss":"^2.0.2","jest":"^18.1.0","lint-staged":"^3.3.0","pre-commit":"^1.1.3","yaspeller":"^3.0.0"},"bin":{"browserslist":"./cli.js"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"25ead9c917b278ad668b83f39c8025697797b2ab","tarball":"https://registry.npmjs.org/browserslist/-/browserslist-1.7.3.tgz"}},"1.7.4":{"name":"browserslist","version":"1.7.4","dependencies":{"caniuse-db":"^1.0.30000624","electron-to-chromium":"^1.2.2"},"devDependencies":{"eslint":"^3.15.0","eslint-config-postcss":"^2.0.2","jest":"^18.1.0","lint-staged":"^3.3.0","pre-commit":"^1.1.3","yaspeller":"^3.0.0"},"bin":{"browserslist":"./cli.js"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"56a12da876f787223743a866224ccd8f97014628","tarball":"https://registry.npmjs.org/browserslist/-/browserslist-1.7.4.tgz"}},"1.7.5":{"name":"browserslist","version":"1.7.5","dependencies":{"caniuse-db":"^1.0.30000624","electron-to-chromium":"^1.2.3"},"devDependencies":{"eslint":"^3.16.0","eslint-config-postcss":"^2.0.2","jest":"^19.0.1","lint-staged":"^3.3.1","pre-commit":"^1.1.3","yaspeller":"^3.0.0"},"bin":{"browserslist":"./cli.js"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"eca4713897b51e444283241facf3985de49a9e2b","tarball":"https://registry.npmjs.org/browserslist/-/browserslist-1.7.5.tgz"}},"1.7.6":{"name":"browserslist","version":"1.7.6","dependencies":{"caniuse-db":"^1.0.30000631","electron-to-chromium":"^1.2.5"},"devDependencies":{"eslint":"^3.16.1","eslint-config-postcss":"^2.0.2","jest":"^19.0.2","lint-staged":"^3.3.1","pre-commit":"^1.1.3","yaspeller":"^3.0.0"},"bin":{"browserslist":"./cli.js"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"af98589ce6e7ab09618d29451faacb81220bd3ba","tarball":"https://registry.npmjs.org/browserslist/-/browserslist-1.7.6.tgz"}},"1.7.7":{"name":"browserslist","version":"1.7.7","dependencies":{"caniuse-db":"^1.0.30000639","electron-to-chromium":"^1.2.7"},"devDependencies":{"eslint":"^3.18.0","eslint-config-postcss":"^2.0.2","jest":"^19.0.2","lint-staged":"^3.4.0","pre-commit":"^1.1.3","yaspeller-ci":"^0.3.0"},"bin":{"browserslist":"./cli.js"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"0bd76704258be829b2398bb50e4b62d1a166b0b9","tarball":"https://registry.npmjs.org/browserslist/-/browserslist-1.7.7.tgz"}},"2.0.0":{"name":"browserslist","version":"2.0.0","dependencies":{"caniuse-lite":"^1.0.30000657","electron-to-chromium":"^1.3.6"},"devDependencies":{"cross-spawn":"^5.1.0","eslint":"^3.19.0","eslint-config-postcss":"^2.0.2","jest":"^19.0.2","lint-staged":"^3.4.0","pre-commit":"^1.1.3","yaspeller-ci":"^0.4.0"},"bin":{"browserslist":"./cli.js"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"f9251e5c728eb7f18020b6743c2ef03feaff2a27","tarball":"https://registry.npmjs.org/browserslist/-/browserslist-2.0.0.tgz"}},"2.1.0":{"name":"browserslist","version":"2.1.0","dependencies":{"caniuse-lite":"^1.0.30000659","electron-to-chromium":"^1.3.8"},"devDependencies":{"cross-spawn":"^5.1.0","eslint":"^3.19.0","eslint-config-postcss":"^2.0.2","jest":"^19.0.2","lint-staged":"^3.4.0","pre-commit":"^1.1.3","yaspeller-ci":"^0.4.0"},"bin":{"browserslist":"./cli.js"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"2590d3de07c7129a7bd05ce3c3cb2a3fc56e78fa","tarball":"https://registry.npmjs.org/browserslist/-/browserslist-2.1.0.tgz"}},"2.1.1":{"name":"browserslist","version":"2.1.1","dependencies":{"caniuse-lite":"^1.0.30000664","electron-to-chromium":"^1.3.8"},"devDependencies":{"cross-spawn":"^5.1.0","eslint":"^3.19.0","eslint-config-postcss":"^2.0.2","jest":"^19.0.2","lint-staged":"^3.4.1","pre-commit":"^1.1.3","yaspeller-ci":"^0.4.0"},"bin":{"browserslist":"./cli.js"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"d0da26318d86352be7693d407977b8523cc78b11","tarball":"https://registry.npmjs.org/browserslist/-/browserslist-2.1.1.tgz"}},"2.1.2":{"name":"browserslist","version":"2.1.2","dependencies":{"caniuse-lite":"^1.0.30000665","electron-to-chromium":"^1.3.9"},"devDependencies":{"cross-spawn":"^5.1.0","eslint":"^3.19.0","eslint-config-postcss":"^2.0.2","jest":"^19.0.2","lint-staged":"^3.4.1","pre-commit":"^1.1.3","yaspeller-ci":"^0.4.0"},"bin":{"browserslist":"./cli.js"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"a9dd0791342dab019861c2dd1cd0fd5d83230d39","tarball":"https://registry.npmjs.org/browserslist/-/browserslist-2.1.2.tgz"}},"2.1.3":{"name":"browserslist","version":"2.1.3","dependencies":{"caniuse-lite":"^1.0.30000670","electron-to-chromium":"^1.3.11"},"devDependencies":{"cross-spawn":"^5.1.0","eslint":"^3.19.0","eslint-config-postcss":"^2.0.2","jest":"^20.0.3","lint-staged":"^3.4.2","pre-commit":"^1.1.3","yaspeller-ci":"^0.4.0"},"bin":{"browserslist":"./cli.js"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"302dc8e5e44f3d5937850868aab13e11cac3dbc7","tarball":"https://registry.npmjs.org/browserslist/-/browserslist-2.1.3.tgz"}},"2.1.4":{"name":"browserslist","version":"2.1.4","dependencies":{"caniuse-lite":"^1.0.30000670","electron-to-chromium":"^1.3.11"},"devDependencies":{"cross-spawn":"^5.1.0","eslint":"^3.19.0","eslint-config-postcss":"^2.0.2","jest":"^20.0.3","lint-staged":"^3.4.2","pre-commit":"^1.1.3","yaspeller-ci":"^0.4.0"},"bin":{"browserslist":"./cli.js"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"cc526af4a1312b7d2e05653e56d0c8ab70c0e053","tarball":"https://registry.npmjs.org/browserslist/-/browserslist-2.1.4.tgz"}},"2.1.5":{"name":"browserslist","version":"2.1.5","dependencies":{"caniuse-lite":"^1.0.30000684","electron-to-chromium":"^1.3.14"},"devDependencies":{"cross-spawn":"^5.1.0","eslint":"^4.0.0","eslint-config-postcss":"^2.0.2","jest":"^20.0.4","lint-staged":"^3.6.1","pre-commit":"^1.1.3","yaspeller-ci":"^0.4.0"},"bin":{"browserslist":"./cli.js"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"e882550df3d1cd6d481c1a3e0038f2baf13a4711","tarball":"https://registry.npmjs.org/browserslist/-/browserslist-2.1.5.tgz"}},"2.2.0":{"name":"browserslist","version":"2.2.0","dependencies":{"caniuse-lite":"^1.0.30000701","electron-to-chromium":"^1.3.15"},"devDependencies":{"cross-spawn":"^5.1.0","eslint":"^4.2.0","eslint-config-postcss":"^2.0.2","jest":"^20.0.4","lint-staged":"^4.0.2","pre-commit":"^1.1.3","yaspeller-ci":"^0.6.0"},"bin":{"browserslist":"./cli.js"},"_hasShrinkwrap":false,"directories":{},"dist":{"integrity":"sha512-t09UuOv/4/hrL1y4wZ871+kKE6E2bkdMD6duZtV7FZIHFpsmdQfW63BH3bAjkfpkbP/eFKyenUbDUKigV/VmRw==","shasum":"5e35ec993e467c6464b8cb708447386891de9f50","tarball":"https://registry.npmjs.org/browserslist/-/browserslist-2.2.0.tgz"}},"2.2.1":{"name":"browserslist","version":"2.2.1","dependencies":{"caniuse-lite":"^1.0.30000704","electron-to-chromium":"^1.3.16"},"devDependencies":{"cross-spawn":"^5.1.0","eslint":"^4.3.0","eslint-config-logux":"^16.0.0","eslint-config-standard":"^10.2.1","eslint-plugin-es5":"^1.1.0","eslint-plugin-import":"^2.7.0","eslint-plugin-jest":"^20.0.3","eslint-plugin-node":"^5.1.1","eslint-plugin-promise":"^3.5.0","eslint-plugin-security":"^1.4.0","eslint-plugin-standard":"^3.0.1","jest":"^20.0.4","lint-staged":"^4.0.2","pre-commit":"^1.1.3","yaspeller-ci":"^0.6.0"},"bin":{"browserslist":"./cli.js"},"_hasShrinkwrap":false,"directories":{},"dist":{"integrity":"sha512-q9NH7wY49FzqqsYHBv2kA/A5XUaaEvWShX3OGLugthdeqnCEaSEmU/TffiIDlcrb5XISYGCNyLvxtnHgOu1qVA==","shasum":"709048c57bf3bf9b382105c396a737ad525d948e","tarball":"https://registry.npmjs.org/browserslist/-/browserslist-2.2.1.tgz"}},"2.2.2":{"name":"browserslist","version":"2.2.2","dependencies":{"caniuse-lite":"^1.0.30000704","electron-to-chromium":"^1.3.16"},"devDependencies":{"cross-spawn":"^5.1.0","eslint":"^4.3.0","eslint-config-logux":"^16.0.0","eslint-config-standard":"^10.2.1","eslint-plugin-es5":"^1.1.0","eslint-plugin-import":"^2.7.0","eslint-plugin-jest":"^20.0.3","eslint-plugin-node":"^5.1.1","eslint-plugin-promise":"^3.5.0","eslint-plugin-security":"^1.4.0","eslint-plugin-standard":"^3.0.1","jest":"^20.0.4","lint-staged":"^4.0.2","pre-commit":"^1.1.3","yaspeller-ci":"^0.6.0"},"bin":{"browserslist":"./cli.js"},"_hasShrinkwrap":false,"directories":{},"dist":{"integrity":"sha512-MejxGMNIeIqzgaMKVYfFTWHinrwZOnWMXteN9VlHinTd13/0aDmXY9uyRqNsCTnVxqRmrjQFcXI7cy0q9K1IYg==","shasum":"e9b4618b8a01c193f9786beea09f6fd10dbe31c3","tarball":"https://registry.npmjs.org/browserslist/-/browserslist-2.2.2.tgz"}},"2.3.0":{"name":"browserslist","version":"2.3.0","dependencies":{"caniuse-lite":"^1.0.30000710","electron-to-chromium":"^1.3.17"},"devDependencies":{"cross-spawn":"^5.1.0","eslint":"^4.3.0","eslint-config-logux":"^16.0.0","eslint-config-standard":"^10.2.1","eslint-plugin-es5":"^1.1.0","eslint-plugin-import":"^2.7.0","eslint-plugin-jest":"^20.0.3","eslint-plugin-node":"^5.1.1","eslint-plugin-promise":"^3.5.0","eslint-plugin-security":"^1.4.0","eslint-plugin-standard":"^3.0.1","jest":"^20.0.4","lint-staged":"^4.0.2","pre-commit":"^1.1.3","yaspeller-ci":"^0.6.0"},"bin":{"browserslist":"./cli.js"},"_hasShrinkwrap":false,"directories":{},"dist":{"integrity":"sha512-jDr9Mea+n+FwI+kR0ce7rXCFBoM7hbL80G/th7oPxuNSK4V5J3LPMHB5vykjeI2h7fgSihBbSdoJPmzUC0606Q==","shasum":"b2aa76415c71643fe2368f6243b43bbbb4211752","tarball":"https://registry.npmjs.org/browserslist/-/browserslist-2.3.0.tgz"}},"2.3.1":{"name":"browserslist","version":"2.3.1","dependencies":{"caniuse-lite":"^1.0.30000712","electron-to-chromium":"^1.3.17"},"devDependencies":{"cross-spawn":"^5.1.0","eslint":"^4.4.1","eslint-config-logux":"^16.0.0","eslint-config-standard":"^10.2.1","eslint-plugin-es5":"^1.1.0","eslint-plugin-import":"^2.7.0","eslint-plugin-jest":"^20.0.3","eslint-plugin-node":"^5.1.1","eslint-plugin-promise":"^3.5.0","eslint-plugin-security":"^1.4.0","eslint-plugin-standard":"^3.0.1","jest":"^20.0.4","lint-staged":"^4.0.3","pre-commit":"^1.1.3","size-limit":"^0.8.1","yaspeller-ci":"^0.6.0"},"bin":{"browserslist":"./cli.js"},"_hasShrinkwrap":false,"directories":{},"dist":{"integrity":"sha512-YSRvpyaxDBBAPkwYO0THouUmA+cvYbyBHZrP/byJEUGDT9r/6TQcDASBtrAj4S45Le6JZbV8oeUAPR9wT8tisg==","shasum":"39500a2090330b2a090120ea6c7fc78b6e091c5e","tarball":"https://registry.npmjs.org/browserslist/-/browserslist-2.3.1.tgz"}},"2.3.2":{"name":"browserslist","version":"2.3.2","dependencies":{"caniuse-lite":"^1.0.30000715","electron-to-chromium":"^1.3.18"},"devDependencies":{"cross-spawn":"^5.1.0","eslint":"^4.4.1","eslint-config-logux":"^16.0.0","eslint-config-standard":"^10.2.1","eslint-plugin-es5":"^1.1.0","eslint-plugin-import":"^2.7.0","eslint-plugin-jest":"^20.0.3","eslint-plugin-node":"^5.1.1","eslint-plugin-promise":"^3.5.0","eslint-plugin-security":"^1.4.0","eslint-plugin-standard":"^3.0.1","jest":"^20.0.4","lint-staged":"^4.0.3","pre-commit":"^1.1.3","size-limit":"^0.8.4","yaspeller-ci":"^0.6.0"},"bin":{"browserslist":"./cli.js"},"_hasShrinkwrap":false,"directories":{},"dist":{"integrity":"sha512-arvLUwBTsmpfmyMfoBQH8WWICiyaVkMxJsft73/rTRU80rAPSXsi3M0uYBcUH22w7MG475eET31F4M0+31w81g==","shasum":"343ff101cce799d5eaf0b742e17d0d21efc2d379","tarball":"https://registry.npmjs.org/browserslist/-/browserslist-2.3.2.tgz"}},"2.3.3":{"name":"browserslist","version":"2.3.3","dependencies":{"caniuse-lite":"^1.0.30000715","electron-to-chromium":"^1.3.18"},"devDependencies":{"cross-spawn":"^5.1.0","eslint":"^4.4.1","eslint-config-logux":"^16.0.0","eslint-config-standard":"^10.2.1","eslint-plugin-es5":"^1.1.0","eslint-plugin-import":"^2.7.0","eslint-plugin-jest":"^20.0.3","eslint-plugin-node":"^5.1.1","eslint-plugin-promise":"^3.5.0","eslint-plugin-security":"^1.4.0","eslint-plugin-standard":"^3.0.1","jest":"^20.0.4","lint-staged":"^4.0.3","pre-commit":"^1.1.3","size-limit":"^0.9.0","yaspeller-ci":"^0.6.0"},"bin":{"browserslist":"./cli.js"},"_hasShrinkwrap":false,"directories":{},"dist":{"integrity":"sha512-p9hz6FA2H1w1ZUAXKfK3MlIA4Z9fEd56hnZSOecBIITb5j0oZk/tZRwhdE0xG56RGx2x8cc1c5AWJKWVjMLOEQ==","shasum":"2b0cabc4d28489f682598605858a0782f14b154c","tarball":"https://registry.npmjs.org/browserslist/-/browserslist-2.3.3.tgz"}},"2.4.0":{"name":"browserslist","version":"2.4.0","dependencies":{"caniuse-lite":"^1.0.30000718","electron-to-chromium":"^1.3.18"},"devDependencies":{"cross-spawn":"^5.1.0","eslint":"^4.5.0","eslint-config-logux":"^16.0.0","eslint-config-standard":"^10.2.1","eslint-plugin-es5":"^1.1.0","eslint-plugin-import":"^2.7.0","eslint-plugin-jest":"^20.0.3","eslint-plugin-node":"^5.1.1","eslint-plugin-promise":"^3.5.0","eslint-plugin-security":"^1.4.0","eslint-plugin-standard":"^3.0.1","jest":"^20.0.4","lint-staged":"^4.0.4","pre-commit":"^1.1.3","size-limit":"^0.10.0","yaspeller-ci":"^0.6.0"},"bin":{"browserslist":"./cli.js"},"_hasShrinkwrap":false,"directories":{},"dist":{"integrity":"sha512-aM2Gt4x9bVlCUteADBS6JP0F+2tMWKM1jQzUulVROtdFWFIcIVvY76AJbr7GDqy0eDhn+PcnpzzivGxY4qiaKQ==","shasum":"693ee93d01e66468a6348da5498e011f578f87f8","tarball":"https://registry.npmjs.org/browserslist/-/browserslist-2.4.0.tgz"}},"2.5.0":{"name":"browserslist","version":"2.5.0","dependencies":{"caniuse-lite":"^1.0.30000744","electron-to-chromium":"^1.3.24"},"devDependencies":{"cross-spawn":"^5.1.0","eslint":"^4.8.0","eslint-config-logux":"^16.2.0","eslint-config-standard":"^10.2.1","eslint-plugin-es5":"^1.1.0","eslint-plugin-import":"^2.7.0","eslint-plugin-jest":"^21.2.0","eslint-plugin-node":"^5.2.0","eslint-plugin-promise":"^3.5.0","eslint-plugin-security":"^1.4.0","eslint-plugin-standard":"^3.0.1","jest":"^21.2.1","lint-staged":"^4.2.3","pre-commit":"^1.1.3","size-limit":"^0.11.6","yaspeller-ci":"^0.7.0"},"bin":{"browserslist":"./cli.js"},"_hasShrinkwrap":false,"directories":{},"dist":{"integrity":"sha512-6Vw1LIigGw8zCK0gxczksUMZlO+oPUwBazAztMmFL/F8D5wB0qCuxRJGYgYM3JzaO0v2ZMRIg+nnnOgNsPGHeA==","shasum":"0ea00d22813a4dfae5786485225a9c584b3ef37c","tarball":"https://registry.npmjs.org/browserslist/-/browserslist-2.5.0.tgz"}},"2.5.1":{"name":"browserslist","version":"2.5.1","dependencies":{"caniuse-lite":"^1.0.30000744","electron-to-chromium":"^1.3.24"},"devDependencies":{"cross-spawn":"^5.1.0","eslint":"^4.8.0","eslint-config-logux":"^16.2.0","eslint-config-standard":"^10.2.1","eslint-plugin-es5":"^1.1.0","eslint-plugin-import":"^2.7.0","eslint-plugin-jest":"^21.2.0","eslint-plugin-node":"^5.2.0","eslint-plugin-promise":"^3.5.0","eslint-plugin-security":"^1.4.0","eslint-plugin-standard":"^3.0.1","jest":"^21.2.1","lint-staged":"^4.2.3","pre-commit":"^1.1.3","size-limit":"^0.11.6","yaspeller-ci":"^0.7.0"},"bin":{"browserslist":"./cli.js"},"_hasShrinkwrap":false,"directories":{},"dist":{"integrity":"sha512-jAvM2ku7YDJ+leAq3bFH1DE0Ylw+F+EQDq4GkqZfgPEqpWYw9ofQH85uKSB9r3Tv7XDbfqVtE+sdvKJW7IlPJA==","shasum":"68e4bc536bbcc6086d62843a2ffccea8396821c6","tarball":"https://registry.npmjs.org/browserslist/-/browserslist-2.5.1.tgz"}},"2.6.0":{"name":"browserslist","version":"2.6.0","dependencies":{"caniuse-lite":"^1.0.30000755","electron-to-chromium":"^1.3.27"},"devDependencies":{"cross-spawn":"^5.1.0","eslint":"^4.10.0","eslint-config-logux":"^16.2.0","eslint-config-standard":"^10.2.1","eslint-plugin-es5":"^1.1.0","eslint-plugin-import":"^2.8.0","eslint-plugin-jest":"^21.2.0","eslint-plugin-node":"^5.2.1","eslint-plugin-promise":"^3.6.0","eslint-plugin-security":"^1.4.0","eslint-plugin-standard":"^3.0.1","jest":"^21.2.1","lint-staged":"^4.3.0","pre-commit":"^1.1.3","size-limit":"^0.12.0","yaspeller-ci":"^0.7.0"},"bin":{"browserslist":"./cli.js"},"_hasShrinkwrap":false,"directories":{},"dist":{"integrity":"sha512-XgAVmla9QAC5VkNmJ+i5zbgh+sPumLEL83MDYR9J8LoCJ1NgkptAqIny0+2VyI83OAnVHLdCsUjM4vs8RLsppQ==","shasum":"15b14ab7b7df4b108979585badff121eca9e1835","tarball":"https://registry.npmjs.org/browserslist/-/browserslist-2.6.0.tgz"}},"2.6.1":{"name":"browserslist","version":"2.6.1","dependencies":{"caniuse-lite":"^1.0.30000755","electron-to-chromium":"^1.3.27"},"devDependencies":{"cross-spawn":"^5.1.0","eslint":"^4.10.0","eslint-config-logux":"^16.2.0","eslint-config-standard":"^10.2.1","eslint-plugin-es5":"^1.1.0","eslint-plugin-import":"^2.8.0","eslint-plugin-jest":"^21.2.0","eslint-plugin-node":"^5.2.1","eslint-plugin-promise":"^3.6.0","eslint-plugin-security":"^1.4.0","eslint-plugin-standard":"^3.0.1","jest":"^21.2.1","lint-staged":"^4.3.0","pre-commit":"^1.1.3","size-limit":"^0.12.0","yaspeller-ci":"^0.7.0"},"bin":{"browserslist":"./cli.js"},"_hasShrinkwrap":false,"directories":{},"dist":{"integrity":"sha512-HBZwVT7ciQB9KlXM3AUMQbnQXtHWPsEUKQTiS0BEFfY5bOrMl94ORaqQD1GyuTGh69ZmYeue9QBqiw219e09eQ==","shasum":"cc65a05ad6131ebda26f076f2822ba1bc826376b","tarball":"https://registry.npmjs.org/browserslist/-/browserslist-2.6.1.tgz"}},"2.7.0":{"name":"browserslist","version":"2.7.0","dependencies":{"caniuse-lite":"^1.0.30000757","electron-to-chromium":"^1.3.27"},"devDependencies":{"cross-spawn":"^5.1.0","eslint":"^4.10.0","eslint-config-logux":"^16.2.0","eslint-config-standard":"^10.2.1","eslint-plugin-es5":"^1.1.0","eslint-plugin-import":"^2.8.0","eslint-plugin-jest":"^21.2.0","eslint-plugin-node":"^5.2.1","eslint-plugin-promise":"^3.6.0","eslint-plugin-security":"^1.4.0","eslint-plugin-standard":"^3.0.1","jest":"^21.2.1","lint-staged":"^4.3.0","pre-commit":"^1.1.3","size-limit":"^0.12.1","yaspeller-ci":"^0.7.0"},"bin":{"browserslist":"./cli.js"},"_hasShrinkwrap":false,"directories":{},"dist":{"integrity":"sha512-s34mrlczJsfbJu//mz/m9zlOy/S6tiP6El1u8iC1gTfEnzKXvxo8RAoCxS/MmojB7rd7bnfYzvKQNHykWaUWWw==","shasum":"dc375dc70048fec3d989042a35022342902eff00","tarball":"https://registry.npmjs.org/browserslist/-/browserslist-2.7.0.tgz"}},"2.8.0":{"name":"browserslist","version":"2.8.0","dependencies":{"caniuse-lite":"^1.0.30000758","electron-to-chromium":"^1.3.27"},"devDependencies":{"cross-spawn":"^5.1.0","eslint":"^4.10.0","eslint-config-logux":"^16.2.0","eslint-config-standard":"^10.2.1","eslint-plugin-es5":"^1.1.0","eslint-plugin-import":"^2.8.0","eslint-plugin-jest":"^21.2.0","eslint-plugin-node":"^5.2.1","eslint-plugin-promise":"^3.6.0","eslint-plugin-security":"^1.4.0","eslint-plugin-standard":"^3.0.1","jest":"^21.2.1","lint-staged":"^4.3.0","pre-commit":"^1.1.3","size-limit":"^0.13.1","yaspeller-ci":"^0.7.0"},"bin":{"browserslist":"./cli.js"},"_hasShrinkwrap":false,"directories":{},"dist":{"integrity":"sha512-iiWHM1Et6Q4TQpB7Ar6pxuM3TNMXasVJY4Y/oh3q38EwR3Z+IdZ9MyVf7PI4MJFB4xpwMcZgs9bEUnPG2E3TCA==","shasum":"27d64028130a2e8585ca96f7c3b7730eff4de493","tarball":"https://registry.npmjs.org/browserslist/-/browserslist-2.8.0.tgz"}},"2.9.0":{"name":"browserslist","version":"2.9.0","dependencies":{"caniuse-lite":"^1.0.30000760","electron-to-chromium":"^1.3.27"},"devDependencies":{"cross-spawn":"^5.1.0","eslint":"^4.11.0","eslint-config-logux":"^16.2.0","eslint-config-standard":"^10.2.1","eslint-plugin-es5":"^1.1.0","eslint-plugin-import":"^2.8.0","eslint-plugin-jest":"^21.3.2","eslint-plugin-node":"^5.2.1","eslint-plugin-promise":"^3.6.0","eslint-plugin-security":"^1.4.0","eslint-plugin-standard":"^3.0.1","jest":"^21.2.1","lint-staged":"^5.0.0","pre-commit":"^1.1.3","size-limit":"^0.13.1","yaspeller-ci":"^0.7.0"},"bin":{"browserslist":"./cli.js"},"_hasShrinkwrap":false,"directories":{},"dist":{"integrity":"sha512-vJEBcDTANoDhSHL46NeOEW5hvQw7It9uCqzeFPQhpawXfnOwnpvW5C97vn1eGJ7iCkSg8wWU0nYObE7d/N95Iw==","shasum":"706aca15c53be15610f466e348cbfa0c00a6a379","tarball":"https://registry.npmjs.org/browserslist/-/browserslist-2.9.0.tgz"}},"2.9.1":{"name":"browserslist","version":"2.9.1","dependencies":{"caniuse-lite":"^1.0.30000770","electron-to-chromium":"^1.3.27"},"devDependencies":{"cross-spawn":"^5.1.0","eslint":"^4.11.0","eslint-ci":"^0.1.1","eslint-config-logux":"^17.0.0","eslint-config-standard":"^10.2.1","eslint-plugin-es5":"^1.1.0","eslint-plugin-import":"^2.8.0","eslint-plugin-jest":"^21.3.2","eslint-plugin-node":"^5.2.1","eslint-plugin-promise":"^3.6.0","eslint-plugin-security":"^1.4.0","eslint-plugin-standard":"^3.0.1","jest":"^21.2.1","lint-staged":"^5.0.0","pre-commit":"^1.1.3","size-limit":"^0.13.2","yaspeller-ci":"^1.0.0"},"bin":{"browserslist":"./cli.js"},"_hasShrinkwrap":false,"directories":{},"dist":{"integrity":"sha512-3n3nPdbUqn3nWmsy4PeSQthz2ja1ndpoXta+dwFFNhveGjMg6FXpWYe12vsTpNoXJbzx3j7GZXdtoVIdvh3JbA==","shasum":"b72d3982ab01b5cd24da62ff6d45573886aff275","tarball":"https://registry.npmjs.org/browserslist/-/browserslist-2.9.1.tgz"}},"2.10.0":{"name":"browserslist","version":"2.10.0","dependencies":{"caniuse-lite":"^1.0.30000780","electron-to-chromium":"^1.3.28"},"devDependencies":{"cross-spawn":"^5.1.0","eslint":"^4.12.1","eslint-ci":"^0.1.1","eslint-config-logux":"^17.0.0","eslint-config-standard":"^10.2.1","eslint-plugin-es5":"^1.1.0","eslint-plugin-import":"^2.8.0","eslint-plugin-jest":"^21.4.1","eslint-plugin-node":"^5.2.1","eslint-plugin-promise":"^3.6.0","eslint-plugin-security":"^1.4.0","eslint-plugin-standard":"^3.0.1","jest":"^21.2.1","lint-staged":"^6.0.0","pre-commit":"^1.1.3","size-limit":"^0.13.2","yaspeller-ci":"^1.0.0"},"bin":{"browserslist":"./cli.js"},"_hasShrinkwrap":false,"directories":{},"dist":{"integrity":"sha512-WyvzSLsuAVPOjbljXnyeWl14Ae+ukAT8MUuagKVzIDvwBxl4UAwD1xqtyQs2eWYPGUKMeC3Ol62goqYuKqTTcw==","shasum":"bac5ee1cc69ca9d96403ffb8a3abdc5b6aed6346","tarball":"https://registry.npmjs.org/browserslist/-/browserslist-2.10.0.tgz"}}},"name":"browserslist","dist-tags":{"latest":"2.10.0"},"modified":"2017-12-06T18:43:00.408Z"} \ No newline at end of file diff --git a/__tests__/fixtures/request-cache/GET/registry.yarnpkg.com/browserslist/-/browserslist-2.10.0.tgz.bin b/__tests__/fixtures/request-cache/GET/registry.yarnpkg.com/browserslist/-/browserslist-2.10.0.tgz.bin new file mode 100644 index 0000000000..88f7e45a70 Binary files /dev/null and b/__tests__/fixtures/request-cache/GET/registry.yarnpkg.com/browserslist/-/browserslist-2.10.0.tgz.bin differ diff --git a/__tests__/fixtures/request-cache/GET/registry.yarnpkg.com/caniuse-api.bin b/__tests__/fixtures/request-cache/GET/registry.yarnpkg.com/caniuse-api.bin new file mode 100644 index 0000000000..0f7d5383af --- /dev/null +++ b/__tests__/fixtures/request-cache/GET/registry.yarnpkg.com/caniuse-api.bin @@ -0,0 +1,21 @@ +HTTP/1.1 200 OK +Date: Mon, 11 Dec 2017 18:38:51 GMT +Content-Type: application/vnd.npm.install-v1+json +Content-Length: 8269 +Connection: keep-alive +Set-Cookie: __cfduid=d88832e1949be97719a1f327c4bc4f7421513017531; expires=Tue, 11-Dec-18 18:38:51 GMT; path=/; domain=.yarnpkg.com; HttpOnly +Cache-Control: max-age=300 +Last-Modified: Wed, 3 May 2017 9:12:01 GMT +ETag: "59099ee1-204d" +Accept-Ranges: bytes +Via: 1.1 varnish +Age: 2254 +X-Served-By: cache-mdw17347-MDW +X-Cache: HIT +X-Cache-Hits: 1 +X-Timer: S1513017532.519062,VS0,VE0 +Vary: Accept-Encoding, Accept +Server: cloudflare-nginx +CF-RAY: 3cba9033fd705625-ORD + +{"versions":{"0.1.0":{"name":"caniuse-api","version":"0.1.0","dependencies":{"browserslist":"^0.1.0","caniuse-db":"^1.0.30000030","lodash.memoize":"^2.4.1","lodash.uniq":"^2.4.1"},"devDependencies":{"6to5":"^1.14.17","tap-spec":"^2.1.1","tape":"^3.0.3"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"2363d7908466950f57637a2861c3d53dd6003a55","tarball":"https://registry.npmjs.org/caniuse-api/-/caniuse-api-0.1.0.tgz"}},"1.0.0":{"name":"caniuse-api","version":"1.0.0","dependencies":{"browserslist":"^0.1.0","caniuse-db":"^1.0.30000030","lodash.memoize":"^2.4.1","lodash.uniq":"^2.4.1"},"devDependencies":{"6to5":"^1.14.17","jshint":"^2.5.10","tap-spec":"^2.1.1","tape":"^3.0.3"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"392efe3eaea6a46ee9ee058f47d33c6dc9607923","tarball":"https://registry.npmjs.org/caniuse-api/-/caniuse-api-1.0.0.tgz"}},"1.1.0":{"name":"caniuse-api","version":"1.1.0","dependencies":{"browserslist":"^0.2.0","caniuse-db":"^1.0.30000030","lodash.memoize":"^2.4.1","lodash.uniq":"^2.4.1"},"devDependencies":{"6to5":"^1.14.17","jshint":"^2.5.10","tap-spec":"^2.1.1","tape":"^3.0.3"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"2969d343a6871d950b28d341f15a750227e2210b","tarball":"https://registry.npmjs.org/caniuse-api/-/caniuse-api-1.1.0.tgz"}},"1.2.0":{"name":"caniuse-api","version":"1.2.0","dependencies":{"browserslist":"^0.2.0","caniuse-db":"^1.0.30000030","lodash.memoize":"^2.4.1","lodash.uniq":"^2.4.1"},"devDependencies":{"6to5":"^1.14.17","jshint":"^2.5.10","tap-spec":"^2.1.1","tape":"^3.0.3"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"1803b57e3327e27baa91997b3f21b52a7625e967","tarball":"https://registry.npmjs.org/caniuse-api/-/caniuse-api-1.2.0.tgz"}},"1.2.1":{"name":"caniuse-api","version":"1.2.1","dependencies":{"browserslist":"^0.2.0","caniuse-db":"^1.0.30000030","lodash.memoize":"^2.4.1","lodash.uniq":"^2.4.1"},"devDependencies":{"6to5":"^1.14.17","jshint":"^2.5.10","tap-spec":"^2.1.1","tape":"^3.0.3"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"264bafaf1a5badbfb76f891bd4d285d4ad135cf7","tarball":"https://registry.npmjs.org/caniuse-api/-/caniuse-api-1.2.1.tgz"}},"1.2.2":{"name":"caniuse-api","version":"1.2.2","dependencies":{"browserslist":"^0.2.0","caniuse-db":"^1.0.30000030","lodash.memoize":"^2.4.1","lodash.uniq":"^2.4.1","shelljs":"^0.3.0"},"devDependencies":{"6to5":"^1.14.17","jshint":"^2.5.10","tap-spec":"^2.1.1","tape":"^3.0.3"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"627c88d0f7f818eac8cd6b424e2874fde7e72f1e","tarball":"https://registry.npmjs.org/caniuse-api/-/caniuse-api-1.2.2.tgz"}},"1.3.0":{"name":"caniuse-api","version":"1.3.0","dependencies":{"browserslist":"^0.2.0","caniuse-db":"^1.0.30000030","lodash.memoize":"^2.4.1","lodash.uniq":"^2.4.1","shelljs":"^0.3.0"},"devDependencies":{"babel":"^4.7.16","babel-tape-runner":"^1.0.0","jshint":"^2.5.10","tap-spec":"^2.1.1","tape":"^3.0.3"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"0181b686fbbaf48791e2c35fdab76f616a21a593","tarball":"https://registry.npmjs.org/caniuse-api/-/caniuse-api-1.3.0.tgz"}},"1.3.1":{"name":"caniuse-api","version":"1.3.1","dependencies":{"browserslist":"^0.2.0","caniuse-db":"^1.0.30000030","lodash.memoize":"^2.4.1","lodash.uniq":"^2.4.1","shelljs":"^0.3.0"},"devDependencies":{"babel":"^4.7.16","babel-tape-runner":"^1.0.0","jshint":"^2.5.10","tap-spec":"^2.1.1","tape":"^3.0.3"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"74fcf47e119dfc619237d9f3a7e98699781008ea","tarball":"https://registry.npmjs.org/caniuse-api/-/caniuse-api-1.3.1.tgz"}},"1.3.2":{"name":"caniuse-api","version":"1.3.2","dependencies":{"browserslist":"^0.4.0","caniuse-db":"^1.0.30000030","lodash.memoize":"^2.4.1","lodash.uniq":"^3.1.0","shelljs":"^0.3.0"},"devDependencies":{"babel":"^4.7.16","babel-tape-runner":"^1.0.0","jshint":"^2.5.10","tap-spec":"^2.1.1","tape":"^3.0.3"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"742c3e194ccb3bcbdb3cb492b511a47499d79e96","tarball":"https://registry.npmjs.org/caniuse-api/-/caniuse-api-1.3.2.tgz"}},"1.4.0":{"name":"caniuse-api","version":"1.4.0","dependencies":{"browserslist":"^1.0.1","caniuse-db":"^1.0.30000346","lodash.memoize":"^2.4.1","lodash.uniq":"^3.1.0","shelljs":"^0.5.3"},"devDependencies":{"babel":"^4.7.16","babel-tape-runner":"^1.0.0","jshint":"^2.5.10","tap-spec":"^2.1.1","tape":"^3.0.3"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"422227e1fc3176b6f94f70c3e991f67c61cd5b2b","tarball":"https://registry.npmjs.org/caniuse-api/-/caniuse-api-1.4.0.tgz"}},"1.4.1":{"name":"caniuse-api","version":"1.4.1","dependencies":{"browserslist":"^1.0.1","caniuse-db":"^1.0.30000346","lodash.memoize":"^2.4.1","lodash.uniq":"^3.1.0","shelljs":"^0.5.3"},"devDependencies":{"babel":"^4.7.16","babel-tape-runner":"^1.0.0","jshint":"^2.5.10","tap-spec":"^2.1.1","tape":"^3.0.3"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"47f9c1ba01428681e13cd9e62f38daeda1a2495c","tarball":"https://registry.npmjs.org/caniuse-api/-/caniuse-api-1.4.1.tgz"}},"1.5.0":{"name":"caniuse-api","version":"1.5.0","dependencies":{"browserslist":"^1.0.1","caniuse-db":"^1.0.30000346","lodash.memoize":"^4.1.0","lodash.uniq":"^4.3.0","shelljs":"^0.7.0"},"devDependencies":{"babel":"^4.7.16","babel-tape-runner":"^1.3.1","jshint":"^2.5.10","tap-spec":"^4.1.1","tape":"^4.5.1"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"e0a6d8cdaf7229baf0552530c23c6bc4df9bf0ef","tarball":"https://registry.npmjs.org/caniuse-api/-/caniuse-api-1.5.0.tgz"}},"1.5.1":{"name":"caniuse-api","version":"1.5.1","dependencies":{"browserslist":"^1.0.1","caniuse-db":"^1.0.30000346","lodash.memoize":"^4.1.0","lodash.uniq":"^4.3.0","shelljs":"^0.7.0"},"devDependencies":{"babel":"^4.7.16","babel-tape-runner":"^1.3.1","jshint":"^2.5.10","npmpub":"^3.1.0","tap-spec":"^4.1.1","tape":"^4.5.1"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"8edb536c41e2a3d0e5e960538a8398f00be46b27","tarball":"https://registry.npmjs.org/caniuse-api/-/caniuse-api-1.5.1.tgz"}},"1.5.2":{"name":"caniuse-api","version":"1.5.2","dependencies":{"browserslist":"^1.0.1","caniuse-db":"^1.0.30000346","lodash.memoize":"^4.1.0","lodash.uniq":"^4.3.0","shelljs":"^0.7.0"},"devDependencies":{"babel":"^4.7.16","babel-tape-runner":"^1.3.1","jshint":"^2.5.10","npmpub":"^3.1.0","tap-spec":"^4.1.1","tape":"^4.5.1"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"8f393c682f661c0a997b77bba6e826483fb3600e","tarball":"https://registry.npmjs.org/caniuse-api/-/caniuse-api-1.5.2.tgz"}},"1.5.3":{"name":"caniuse-api","version":"1.5.3","dependencies":{"browserslist":"^1.0.1","caniuse-db":"^1.0.30000346","lodash.memoize":"^4.1.0","lodash.uniq":"^4.3.0"},"devDependencies":{"babel-cli":"^6.22.2","babel-eslint":"^5.0.0","babel-preset-latest":"^6.22.0","babel-tape-runner":"^2.0.1","jshint":"^2.5.10","npmpub":"^3.1.0","tap-spec":"^4.1.1","tape":"^4.5.1"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"5018e674b51c393e4d50614275dc017e27c4a2a2","tarball":"https://registry.npmjs.org/caniuse-api/-/caniuse-api-1.5.3.tgz"}},"1.6.1":{"name":"caniuse-api","version":"1.6.1","dependencies":{"browserslist":"^1.3.6","caniuse-db":"^1.0.30000529","lodash.memoize":"^4.1.2","lodash.uniq":"^4.5.0"},"devDependencies":{"babel-cli":"^6.22.2","babel-eslint":"^5.0.0","babel-preset-latest":"^6.22.0","babel-tape-runner":"^2.0.1","jshint":"^2.5.10","npmpub":"^3.1.0","tap-spec":"^4.1.1","tape":"^4.6.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"b534e7c734c4f81ec5fbe8aca2ad24354b962c6c","tarball":"https://registry.npmjs.org/caniuse-api/-/caniuse-api-1.6.1.tgz"}},"2.0.0":{"name":"caniuse-api","version":"2.0.0","dependencies":{"browserslist":"^2.0.0","caniuse-lite":"^1.0.0","lodash.memoize":"^4.1.2","lodash.uniq":"^4.5.0"},"devDependencies":{"babel-cli":"^6.22.2","babel-eslint":"^5.0.0","babel-preset-latest":"^6.22.0","babel-tape-runner":"^2.0.1","jshint":"^2.5.10","npmpub":"^3.1.0","tap-spec":"^4.1.1","tape":"^4.6.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"b1ddb5a5966b16f48dc4998444d4bbc6c7d9d834","tarball":"https://registry.npmjs.org/caniuse-api/-/caniuse-api-2.0.0.tgz"}}},"name":"caniuse-api","dist-tags":{"latest":"2.0.0"},"modified":"2017-05-03T09:12:01.052Z"} \ No newline at end of file diff --git a/__tests__/fixtures/request-cache/GET/registry.yarnpkg.com/caniuse-api/-/caniuse-api-2.0.0.tgz.bin b/__tests__/fixtures/request-cache/GET/registry.yarnpkg.com/caniuse-api/-/caniuse-api-2.0.0.tgz.bin new file mode 100644 index 0000000000..a400158e4c Binary files /dev/null and b/__tests__/fixtures/request-cache/GET/registry.yarnpkg.com/caniuse-api/-/caniuse-api-2.0.0.tgz.bin differ diff --git a/__tests__/fixtures/request-cache/GET/registry.yarnpkg.com/caniuse-lite.bin b/__tests__/fixtures/request-cache/GET/registry.yarnpkg.com/caniuse-lite.bin new file mode 100644 index 0000000000..7229b6981f --- /dev/null +++ b/__tests__/fixtures/request-cache/GET/registry.yarnpkg.com/caniuse-lite.bin @@ -0,0 +1,21 @@ +HTTP/1.1 200 OK +Date: Mon, 11 Dec 2017 18:38:52 GMT +Content-Type: application/vnd.npm.install-v1+json +Content-Length: 96186 +Connection: keep-alive +Set-Cookie: __cfduid=d939a285946350410a19e2773d98c8f1a1513017532; expires=Tue, 11-Dec-18 18:38:52 GMT; path=/; domain=.yarnpkg.com; HttpOnly +Cache-Control: max-age=300 +Last-Modified: Sun, 10 Dec 2017 7:01:15 GMT +ETag: "5a2cdbbb-177ba" +Accept-Ranges: bytes +Via: 1.1 varnish +Age: 11870 +X-Served-By: cache-mdw17343-MDW +X-Cache: HIT +X-Cache-Hits: 1 +X-Timer: S1513017532.087176,VS0,VE1 +Vary: Accept-Encoding, Accept +Server: cloudflare-nginx +CF-RAY: 3cba90378af671d9-ORD + +{"versions":{"0.1.0":{"name":"caniuse-lite","version":"0.1.0","devDependencies":{"all-contributors-cli":"^3.0.7","alphanum-sort":"^1.0.2","ava":"^0.17.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","caniuse-db":"^1.0.30000605","del-cli":"^0.2.1","json-loader":"^0.5.4","nyc":"^10.1.2","rollup":"^0.41.4","rollup-plugin-buble":"^0.15.0","rollup-plugin-cleanup":"^1.0.0","timsort":"^0.3.0","webpack":"^1.14.0","webpack-bundle-analyzer":"^2.2.1"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"22360b6b6803dd211d60415162f0ec33a0a66157","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-0.1.0.tgz"}},"0.2.0":{"name":"caniuse-lite","version":"0.2.0","devDependencies":{"all-contributors-cli":"^3.0.7","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","caniuse-db":"1.0.30000649","del-cli":"^0.2.1","jest":"^19.0.2","listr":"^0.11.0","mz":"^2.6.0","rollup":"^0.41.4","rollup-plugin-buble":"^0.15.0","rollup-plugin-cleanup":"^1.0.0","webpack":"^2.0.0","webpack-bundle-analyzer":"^2.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"9f2731421eb1638cbdade62989176a5a69474128","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-0.2.0.tgz"}},"0.3.0":{"name":"caniuse-lite","version":"0.3.0","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","caniuse-db":"1.0.30000653","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","np":"^2.13.1","remark":"^7.0.0","rollup":"^0.41.4","rollup-plugin-buble":"^0.15.0","rollup-plugin-cleanup":"^1.0.0","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","webpack":"^2.0.0","webpack-bundle-analyzer":"^2.0.0","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"7e182363d002b23e167a8e8f6082147ce7453627","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-0.3.0.tgz"}},"1.0.30000655":{"name":"caniuse-lite","version":"1.0.30000655","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","caniuse-db":"1.0.30000655","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","np":"^2.13.1","remark":"^7.0.0","rollup":"^0.41.4","rollup-plugin-buble":"^0.15.0","rollup-plugin-cleanup":"^1.0.0","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","webpack":"^2.0.0","webpack-bundle-analyzer":"^2.0.0","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"20613c829e27942b3441d47da4a4b9b67e056b57","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000655.tgz"}},"1.0.30000656":{"name":"caniuse-lite","version":"1.0.30000656","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000656","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","np":"^2.13.1","remark":"^7.0.0","rollup":"^0.41.4","rollup-plugin-buble":"^0.15.0","rollup-plugin-cleanup":"^1.0.0","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","webpack":"^2.0.0","webpack-bundle-analyzer":"^2.0.0","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"e6beefead44e0b6d82314fd42f57101270de41a7","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000656.tgz"}},"1.0.30000657":{"name":"caniuse-lite","version":"1.0.30000657","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000657","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","np":"^2.13.1","remark":"^7.0.0","rollup":"^0.41.4","rollup-plugin-buble":"^0.15.0","rollup-plugin-cleanup":"^1.0.0","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","webpack":"^2.0.0","webpack-bundle-analyzer":"^2.0.0","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"43ff22428ea436da7ed8cc38d418347944862f62","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000657.tgz"}},"1.0.30000659":{"name":"caniuse-lite","version":"1.0.30000659","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000659","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","np":"^2.13.1","remark":"^7.0.0","rollup":"^0.41.4","rollup-plugin-buble":"^0.15.0","rollup-plugin-cleanup":"^1.0.0","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","webpack":"^2.0.0","webpack-bundle-analyzer":"^2.0.0","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"7eeac0aac71930ba95912c61ec69baa3301a330c","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000659.tgz"}},"1.0.30000660":{"name":"caniuse-lite","version":"1.0.30000660","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000660","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","np":"^2.13.1","remark":"^7.0.0","rollup":"^0.41.4","rollup-plugin-buble":"^0.15.0","rollup-plugin-cleanup":"^1.0.0","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","webpack":"^2.0.0","webpack-bundle-analyzer":"^2.0.0","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"49f8572c3763b64aca221ac2b4da87bc214f759c","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000660.tgz"}},"1.0.30000661":{"name":"caniuse-lite","version":"1.0.30000661","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000661","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","np":"^2.13.1","remark":"^7.0.0","rollup":"^0.41.4","rollup-plugin-buble":"^0.15.0","rollup-plugin-cleanup":"^1.0.0","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","webpack":"^2.0.0","webpack-bundle-analyzer":"^2.0.0","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"d0de936b38e037f76803150ff1ad2914d17c9c36","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000661.tgz"}},"1.0.30000662":{"name":"caniuse-lite","version":"1.0.30000662","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000662","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","np":"^2.13.1","remark":"^7.0.0","rollup":"^0.41.4","rollup-plugin-buble":"^0.15.0","rollup-plugin-cleanup":"^1.0.0","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","webpack":"^2.0.0","webpack-bundle-analyzer":"^2.0.0","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"4b3af71d1c13ce9dfcbc6bc7830afac958ad19ca","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000662.tgz"}},"1.0.30000663":{"name":"caniuse-lite","version":"1.0.30000663","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000663","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","np":"^2.13.1","remark":"^7.0.0","rollup":"^0.41.4","rollup-plugin-buble":"^0.15.0","rollup-plugin-cleanup":"^1.0.0","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","webpack":"^2.0.0","webpack-bundle-analyzer":"^2.0.0","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"fc34de11ddc9289510be92ad8a277976497d1a96","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000663.tgz"}},"1.0.30000664":{"name":"caniuse-lite","version":"1.0.30000664","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000664","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","np":"^2.13.1","remark":"^7.0.0","rollup":"^0.41.4","rollup-plugin-buble":"^0.15.0","rollup-plugin-cleanup":"^1.0.0","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","webpack":"^2.0.0","webpack-bundle-analyzer":"^2.0.0","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"33f5a8eed8c78caa89de2df592913570b3a4f6fb","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000664.tgz"}},"1.0.30000665":{"name":"caniuse-lite","version":"1.0.30000665","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000665","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","np":"^2.13.1","remark":"^7.0.0","rollup":"^0.41.4","rollup-plugin-buble":"^0.15.0","rollup-plugin-cleanup":"^1.0.0","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","webpack":"^2.0.0","webpack-bundle-analyzer":"^2.0.0","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"62cf1283afb9b7b42d5ddceeb0345ce1ec432a1e","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000665.tgz"}},"1.0.30000666":{"name":"caniuse-lite","version":"1.0.30000666","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000666","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","np":"^2.13.1","remark":"^7.0.0","rollup":"^0.41.4","rollup-plugin-buble":"^0.15.0","rollup-plugin-cleanup":"^1.0.0","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","webpack":"^2.0.0","webpack-bundle-analyzer":"^2.0.0","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"831b63247e24fa408e20c6c546c4173d27c5a1a5","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000666.tgz"}},"1.0.30000667":{"name":"caniuse-lite","version":"1.0.30000667","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000667","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","np":"^2.13.1","remark":"^7.0.0","rollup":"^0.41.4","rollup-plugin-buble":"^0.15.0","rollup-plugin-cleanup":"^1.0.0","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","webpack":"^2.0.0","webpack-bundle-analyzer":"^2.0.0","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"dcbf8f19fa3b7ef447e7d514170a9ef949f4e347","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000667.tgz"}},"1.0.30000668":{"name":"caniuse-lite","version":"1.0.30000668","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000668","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","np":"^2.13.1","remark":"^7.0.0","rollup":"^0.41.4","rollup-plugin-buble":"^0.15.0","rollup-plugin-cleanup":"^1.0.0","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","webpack":"^2.0.0","webpack-bundle-analyzer":"^2.0.0","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"e48b1a95270e3a0245fb2f90a2b89702599bdf98","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000668.tgz"}},"1.0.30000669":{"name":"caniuse-lite","version":"1.0.30000669","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000669","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","np":"^2.13.1","remark":"^7.0.0","rollup":"^0.41.4","rollup-plugin-buble":"^0.15.0","rollup-plugin-cleanup":"^1.0.0","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","webpack":"^2.0.0","webpack-bundle-analyzer":"^2.0.0","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"f312f4868722f3ce869ce934da3b536e0e393845","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000669.tgz"}},"1.0.30000670":{"name":"caniuse-lite","version":"1.0.30000670","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000670","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","np":"^2.13.1","remark":"^7.0.0","rollup":"^0.41.4","rollup-plugin-buble":"^0.15.0","rollup-plugin-cleanup":"^1.0.0","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","webpack":"^2.0.0","webpack-bundle-analyzer":"^2.0.0","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"c94f7dbf0b68eaadc46d3d203f46e82e7801135e","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000670.tgz"}},"1.0.30000671":{"name":"caniuse-lite","version":"1.0.30000671","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000671","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","np":"^2.13.1","remark":"^7.0.0","rollup":"^0.41.4","rollup-plugin-buble":"^0.15.0","rollup-plugin-cleanup":"^1.0.0","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","webpack":"^2.0.0","webpack-bundle-analyzer":"^2.0.0","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"c206c2f1a1feb34de46064407c4356818389bf1e","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000671.tgz"}},"1.0.30000672":{"name":"caniuse-lite","version":"1.0.30000672","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000672","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","np":"^2.13.1","remark":"^7.0.0","rollup":"^0.41.4","rollup-plugin-buble":"^0.15.0","rollup-plugin-cleanup":"^1.0.0","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","webpack":"^2.0.0","webpack-bundle-analyzer":"^2.0.0","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"3f89b9907db78653f88bc4d056ed626e8ec74357","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000672.tgz"}},"1.0.30000673":{"name":"caniuse-lite","version":"1.0.30000673","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000673","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","np":"^2.13.1","remark":"^7.0.0","rollup":"^0.41.4","rollup-plugin-buble":"^0.15.0","rollup-plugin-cleanup":"^1.0.0","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","webpack":"^2.0.0","webpack-bundle-analyzer":"^2.0.0","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"4f1c5fefb304f712c526614d83b19476c16e662a","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000673.tgz"}},"1.0.30000674":{"name":"caniuse-lite","version":"1.0.30000674","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000674","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","np":"^2.13.1","remark":"^7.0.0","rollup":"^0.41.4","rollup-plugin-buble":"^0.15.0","rollup-plugin-cleanup":"^1.0.0","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","webpack":"^2.0.0","webpack-bundle-analyzer":"^2.0.0","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"3eabc5e40ae2dce6375dd292f116b9e25bd505a7","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000674.tgz"}},"1.0.30000676":{"name":"caniuse-lite","version":"1.0.30000676","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000676","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","np":"^2.13.1","remark":"^7.0.0","rollup":"^0.41.4","rollup-plugin-buble":"^0.15.0","rollup-plugin-cleanup":"^1.0.0","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","webpack":"^2.0.0","webpack-bundle-analyzer":"^2.0.0","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"1e962123f48073f0c51c4ea0651dd64d25786498","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000676.tgz"}},"1.0.30000677":{"name":"caniuse-lite","version":"1.0.30000677","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000677","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","np":"^2.13.1","remark":"^7.0.0","rollup":"^0.41.4","rollup-plugin-buble":"^0.15.0","rollup-plugin-cleanup":"^1.0.0","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","webpack":"^2.0.0","webpack-bundle-analyzer":"^2.0.0","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"43090233d4b2c7190657f95455983d94d264baaa","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000677.tgz"}},"1.0.30000679":{"name":"caniuse-lite","version":"1.0.30000679","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000679","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","np":"^2.13.1","remark":"^7.0.0","rollup":"^0.41.4","rollup-plugin-buble":"^0.15.0","rollup-plugin-cleanup":"^1.0.0","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","webpack":"^2.0.0","webpack-bundle-analyzer":"^2.0.0","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"0fb5bb3658d4d4448f8f86a1c48df15664aa05ef","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000679.tgz"}},"1.0.30000680":{"name":"caniuse-lite","version":"1.0.30000680","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000680","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","np":"^2.13.1","remark":"^7.0.0","rollup":"^0.41.4","rollup-plugin-buble":"^0.15.0","rollup-plugin-cleanup":"^1.0.0","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","webpack":"^2.0.0","webpack-bundle-analyzer":"^2.0.0","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"d94d81294471617e86500f0aab90f11d22bc8934","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000680.tgz"}},"1.0.30000683":{"name":"caniuse-lite","version":"1.0.30000683","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000683","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","np":"^2.13.1","remark":"^7.0.0","rollup":"^0.41.4","rollup-plugin-buble":"^0.15.0","rollup-plugin-cleanup":"^1.0.0","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","webpack":"^2.0.0","webpack-bundle-analyzer":"^2.0.0","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"a7573707cf2acc9217ca6484d1dfbc9f13898364","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000683.tgz"}},"1.0.30000684":{"name":"caniuse-lite","version":"1.0.30000684","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000684","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","np":"^2.13.1","remark":"^7.0.0","rollup":"^0.41.4","rollup-plugin-buble":"^0.15.0","rollup-plugin-cleanup":"^1.0.0","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","webpack":"^2.0.0","webpack-bundle-analyzer":"^2.0.0","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"0c1032d0b36e14d1ac199f93ef2d1c42d3f03fd7","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000684.tgz"}},"1.0.30000686":{"name":"caniuse-lite","version":"1.0.30000686","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000686","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","np":"^2.13.1","remark":"^7.0.0","rollup":"^0.41.4","rollup-plugin-buble":"^0.15.0","rollup-plugin-cleanup":"^1.0.0","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","webpack":"^2.0.0","webpack-bundle-analyzer":"^2.0.0","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"d9d9ec6110e5533be544a689003f7596532c67d3","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000686.tgz"}},"1.0.30000687":{"name":"caniuse-lite","version":"1.0.30000687","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000687","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","np":"^2.13.1","remark":"^7.0.0","rollup":"^0.41.4","rollup-plugin-buble":"^0.15.0","rollup-plugin-cleanup":"^1.0.0","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","webpack":"^2.0.0","webpack-bundle-analyzer":"^2.0.0","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"06763368260f5257e0c98f2b0c8d23cca4c160bb","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000687.tgz"}},"1.0.30000688":{"name":"caniuse-lite","version":"1.0.30000688","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000688","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","np":"^2.13.1","remark":"^7.0.0","rollup":"^0.41.4","rollup-plugin-buble":"^0.15.0","rollup-plugin-cleanup":"^1.0.0","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","webpack":"^2.0.0","webpack-bundle-analyzer":"^2.0.0","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"95036716b9459bb7471aba617516461ff562b359","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000688.tgz"}},"1.0.30000689":{"name":"caniuse-lite","version":"1.0.30000689","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000689","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","np":"^2.13.1","remark":"^7.0.0","rollup":"^0.41.4","rollup-plugin-buble":"^0.15.0","rollup-plugin-cleanup":"^1.0.0","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","webpack":"^2.0.0","webpack-bundle-analyzer":"^2.0.0","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"729b6fc3afb0d92df93e0aafd539367e771a0fd6","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000689.tgz"}},"1.0.30000690":{"name":"caniuse-lite","version":"1.0.30000690","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000690","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","np":"^2.13.1","remark":"^7.0.0","rollup":"^0.41.4","rollup-plugin-buble":"^0.15.0","rollup-plugin-cleanup":"^1.0.0","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","webpack":"^2.0.0","webpack-bundle-analyzer":"^2.0.0","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"3b232dbc0cf32bc2a888ec199852a50afa37f5ef","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000690.tgz"}},"1.0.30000692":{"name":"caniuse-lite","version":"1.0.30000692","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000692","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","np":"^2.13.1","remark":"^7.0.0","rollup":"^0.41.4","rollup-plugin-buble":"^0.15.0","rollup-plugin-cleanup":"^1.0.0","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","webpack":"^2.0.0","webpack-bundle-analyzer":"^2.0.0","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"34600fd7152352d85a47f4662a3b51b02d8b646f","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000692.tgz"}},"1.0.30000693":{"name":"caniuse-lite","version":"1.0.30000693","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000693","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","np":"^2.13.1","remark":"^7.0.0","rollup":"^0.41.4","rollup-plugin-buble":"^0.15.0","rollup-plugin-cleanup":"^1.0.0","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","webpack":"^2.0.0","webpack-bundle-analyzer":"^2.0.0","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"c9c6298697c71fdf6cb13eefe8aa93926f2f8613","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000693.tgz"}},"1.0.30000694":{"name":"caniuse-lite","version":"1.0.30000694","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000694","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","np":"^2.13.1","remark":"^7.0.0","rollup":"^0.41.4","rollup-plugin-buble":"^0.15.0","rollup-plugin-cleanup":"^1.0.0","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","webpack":"^2.0.0","webpack-bundle-analyzer":"^2.0.0","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"1492dab7c10c608c9d37a723e6e3e7873e0ce94f","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000694.tgz"}},"1.0.30000695":{"name":"caniuse-lite","version":"1.0.30000695","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000695","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","np":"^2.13.1","remark":"^7.0.0","rollup":"^0.41.4","rollup-plugin-buble":"^0.15.0","rollup-plugin-cleanup":"^1.0.0","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","webpack":"^2.0.0","webpack-bundle-analyzer":"^2.0.0","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"0c2f711d49b9979884fa74349888aa48a8689dfd","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000695.tgz"}},"1.0.30000696":{"name":"caniuse-lite","version":"1.0.30000696","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000696","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","np":"^2.13.1","remark":"^7.0.0","rollup":"^0.41.4","rollup-plugin-buble":"^0.15.0","rollup-plugin-cleanup":"^1.0.0","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","webpack":"^2.0.0","webpack-bundle-analyzer":"^2.0.0","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"30f2695d2a01a0dfd779a26ab83f4d134b3da5cc","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000696.tgz"}},"1.0.30000697":{"name":"caniuse-lite","version":"1.0.30000697","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000697","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","np":"^2.13.1","remark":"^7.0.0","rollup":"^0.41.4","rollup-plugin-buble":"^0.15.0","rollup-plugin-cleanup":"^1.0.0","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","webpack":"^2.0.0","webpack-bundle-analyzer":"^2.0.0","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"125fb00604b63fbb188db96a667ce2922dcd6cdd","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000697.tgz"}},"1.0.30000698":{"name":"caniuse-lite","version":"1.0.30000698","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000698","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","np":"^2.13.1","remark":"^7.0.0","rollup":"^0.41.4","rollup-plugin-buble":"^0.15.0","rollup-plugin-cleanup":"^1.0.0","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","webpack":"^2.0.0","webpack-bundle-analyzer":"^2.0.0","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"8102e8978b1f36962f2a102432e4bf4eac7b6cbe","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000698.tgz"}},"1.0.30000699":{"name":"caniuse-lite","version":"1.0.30000699","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000699","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","np":"^2.13.1","remark":"^7.0.0","rollup":"^0.41.4","rollup-plugin-buble":"^0.15.0","rollup-plugin-cleanup":"^1.0.0","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","webpack":"^2.0.0","webpack-bundle-analyzer":"^2.0.0","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"2a187b737edaa9ebedbbb56edcb53e994eceda0c","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000699.tgz"}},"1.0.30000700":{"name":"caniuse-lite","version":"1.0.30000700","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000700","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","np":"^2.13.1","remark":"^7.0.0","rollup":"^0.41.4","rollup-plugin-buble":"^0.15.0","rollup-plugin-cleanup":"^1.0.0","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","webpack":"^2.0.0","webpack-bundle-analyzer":"^2.0.0","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"6084871ec75c6fa62327de97622514f95d9db26a","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000700.tgz"}},"1.0.30000701":{"name":"caniuse-lite","version":"1.0.30000701","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000701","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","np":"^2.13.1","remark":"^7.0.0","rollup":"^0.41.4","rollup-plugin-buble":"^0.15.0","rollup-plugin-cleanup":"^1.0.0","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","webpack":"^2.0.0","webpack-bundle-analyzer":"^2.0.0","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"9d673cf6b74dcb3d5c21d213176b011ac6a45baa","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000701.tgz"}},"1.0.30000702":{"name":"caniuse-lite","version":"1.0.30000702","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000702","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","np":"^2.13.1","remark":"^7.0.0","rollup":"^0.41.4","rollup-plugin-buble":"^0.15.0","rollup-plugin-cleanup":"^1.0.0","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","webpack":"^2.0.0","webpack-bundle-analyzer":"^2.0.0","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"bd66e40345528fe0c001917d1d3f55454df634f1","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000702.tgz"}},"1.0.30000703":{"name":"caniuse-lite","version":"1.0.30000703","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000703","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","np":"^2.13.1","remark":"^7.0.0","rollup":"^0.41.4","rollup-plugin-buble":"^0.15.0","rollup-plugin-cleanup":"^1.0.0","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","webpack":"^2.0.0","webpack-bundle-analyzer":"^2.0.0","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"666e8c3f1e4f7abb1d16d48e04e7e9e8df934925","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000703.tgz"}},"1.0.30000704":{"name":"caniuse-lite","version":"1.0.30000704","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000704","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","np":"^2.13.1","remark":"^7.0.0","rollup":"^0.41.4","rollup-plugin-buble":"^0.15.0","rollup-plugin-cleanup":"^1.0.0","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","webpack":"^2.0.0","webpack-bundle-analyzer":"^2.0.0","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"adb6ea01134515663682db93abab291d4c02946b","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000704.tgz"}},"1.0.30000706":{"name":"caniuse-lite","version":"1.0.30000706","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000706","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","remark":"^7.0.0","size-limit":"^0.7.1","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"bc59abc41ba7d4a3634dda95befded6114e1f24e","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000706.tgz"}},"1.0.30000708":{"name":"caniuse-lite","version":"1.0.30000708","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000708","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","remark":"^7.0.0","size-limit":"^0.7.1","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"71dbf388c57f379b1bb66c89a890edc04c2509b6","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000708.tgz"}},"1.0.30000709":{"name":"caniuse-lite","version":"1.0.30000709","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000709","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","remark":"^7.0.0","size-limit":"^0.7.1","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"e027c7a0dfd5ada58f931a1080fc71965375559b","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000709.tgz"}},"1.0.30000710":{"name":"caniuse-lite","version":"1.0.30000710","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000710","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","remark":"^7.0.0","size-limit":"^0.7.1","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"1c249bf7c6a61161c9b10906e3ad9fa5b6761af1","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000710.tgz"}},"1.0.30000711":{"name":"caniuse-lite","version":"1.0.30000711","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000711","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","remark":"^7.0.0","size-limit":"^0.7.1","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"90f632a4ede34d40b3e49622e58e710dc187ef6c","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000711.tgz"}},"1.0.30000712":{"name":"caniuse-lite","version":"1.0.30000712","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000712","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","remark":"^7.0.0","size-limit":"^0.7.1","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"b4732def2459224f3f78c6a9ba103abfcc705670","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000712.tgz"}},"1.0.30000713":{"name":"caniuse-lite","version":"1.0.30000713","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000713","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","remark":"^7.0.0","size-limit":"^0.7.1","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"33957ecb4a2154a5d40a60d13d8bf1cfa0881a8a","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000713.tgz"}},"1.0.30000714":{"name":"caniuse-lite","version":"1.0.30000714","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000714","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","remark":"^7.0.0","size-limit":"^0.7.1","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"e7e5b43172f20c9fdc2f1e4204b37140c447739f","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000714.tgz"}},"1.0.30000715":{"name":"caniuse-lite","version":"1.0.30000715","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000715","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","remark":"^7.0.0","size-limit":"^0.7.1","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"c327f5e6d907ebcec62cde598c3bf0dd793fb9a0","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000715.tgz"}},"1.0.30000716":{"name":"caniuse-lite","version":"1.0.30000716","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000716","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","remark":"^7.0.0","size-limit":"^0.7.1","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"2b40dd4a7edb7f0c468643b899b832b315988e6a","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000716.tgz"}},"1.0.30000717":{"name":"caniuse-lite","version":"1.0.30000717","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000717","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","remark":"^7.0.0","size-limit":"^0.7.1","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"4539b126af787c1d4851944de22b2bd8780d3612","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000717.tgz"}},"1.0.30000718":{"name":"caniuse-lite","version":"1.0.30000718","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000718","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","remark":"^7.0.0","size-limit":"^0.7.1","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"0dd24290beb11310b2d80f6b70a823c2a65a6fad","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000718.tgz"}},"1.0.30000720":{"name":"caniuse-lite","version":"1.0.30000720","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000720","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","remark":"^7.0.0","size-limit":"^0.7.1","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"9313aba5b923fab5c78f6054819b6f0cbc626352","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000720.tgz"}},"1.0.30000721":{"name":"caniuse-lite","version":"1.0.30000721","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000721","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","remark":"^7.0.0","size-limit":"^0.7.1","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"931a21a7bd85016300328d21f126d84b73437d35","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000721.tgz"}},"1.0.30000722":{"name":"caniuse-lite","version":"1.0.30000722","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000722","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","remark":"^7.0.0","size-limit":"^0.7.1","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"8cbfe07440478e3a16ab0d3b182feef1901eab55","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000722.tgz"}},"1.0.30000723":{"name":"caniuse-lite","version":"1.0.30000723","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000723","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","remark":"^7.0.0","size-limit":"^0.7.1","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"f9db1e2868caf097b00265ac2e71ba44b608fb1e","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000723.tgz"}},"1.0.30000724":{"name":"caniuse-lite","version":"1.0.30000724","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000724","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","remark":"^7.0.0","size-limit":"^0.7.1","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"b9711be59257bdbce6a872ade51a11e864c21ec1","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000724.tgz"}},"1.0.30000725":{"name":"caniuse-lite","version":"1.0.30000725","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000725","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","remark":"^7.0.0","size-limit":"^0.7.1","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"4fa66372323c6ff46c8a1ba03f9dcd73d7a1cb39","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000725.tgz"}},"1.0.30000726":{"name":"caniuse-lite","version":"1.0.30000726","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000726","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","remark":"^7.0.0","size-limit":"^0.7.1","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"966a753fa107a09d4131cf8b3d616723a06ccf7e","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000726.tgz"}},"1.0.30000727":{"name":"caniuse-lite","version":"1.0.30000727","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000727","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","remark":"^7.0.0","size-limit":"^0.7.1","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"20c895768398ded5f98a4beab4a76c285def41d2","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000727.tgz"}},"1.0.30000730":{"name":"caniuse-lite","version":"1.0.30000730","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000730","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","remark":"^7.0.0","size-limit":"^0.7.1","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"26a14ff1b3bfc1f1cb4da75c2c73451b3f1ade1a","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000730.tgz"}},"1.0.30000731":{"name":"caniuse-lite","version":"1.0.30000731","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000731","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","remark":"^7.0.0","size-limit":"^0.7.1","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"6f2b9096285af3c7bcf2abe39647bb525d68c842","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000731.tgz"}},"1.0.30000732":{"name":"caniuse-lite","version":"1.0.30000732","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000732","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","remark":"^7.0.0","size-limit":"^0.7.1","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"7cf9ca565f4d31a4b3dfa6e26b72ec22e9027da1","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000732.tgz"}},"1.0.30000733":{"name":"caniuse-lite","version":"1.0.30000733","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000733","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","remark":"^7.0.0","size-limit":"^0.7.1","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"ebfc48254117cc0c66197a4536cb4397a6cfbccd","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000733.tgz"}},"1.0.30000734":{"name":"caniuse-lite","version":"1.0.30000734","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000734","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","remark":"^7.0.0","size-limit":"^0.7.1","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"492791fb0557978fcc1b7a8f486270b35ea6e569","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000734.tgz"}},"1.0.30000735":{"name":"caniuse-lite","version":"1.0.30000735","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000735","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","remark":"^7.0.0","size-limit":"^0.7.1","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"aab44016ef243e215ef43fd1343efd22930842f8","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000735.tgz"}},"1.0.30000736":{"name":"caniuse-lite","version":"1.0.30000736","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000736","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","remark":"^7.0.0","size-limit":"^0.7.1","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"df369dfb7ed4d77a8a01244252c6e2f7db9cc689","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000736.tgz"}},"1.0.30000737":{"name":"caniuse-lite","version":"1.0.30000737","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000737","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","remark":"^7.0.0","size-limit":"^0.7.1","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"8199a601dd54c096e1f8567bcb7461b94f0d4509","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000737.tgz"}},"1.0.30000738":{"name":"caniuse-lite","version":"1.0.30000738","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000738","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","remark":"^7.0.0","size-limit":"^0.7.1","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"1820c3c9adb9a117e311a5bdca1d25bc34288eba","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000738.tgz"}},"1.0.30000739":{"name":"caniuse-lite","version":"1.0.30000739","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000739","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","remark":"^7.0.0","size-limit":"^0.7.1","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"9ee8c7016f5c522dbb0c0863d55c61efb453ae95","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000739.tgz"}},"1.0.30000740":{"name":"caniuse-lite","version":"1.0.30000740","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000740","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","remark":"^7.0.0","size-limit":"^0.7.1","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"f2c4c04d6564eb812e61006841700ad557f6f973","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000740.tgz"}},"1.0.30000741":{"name":"caniuse-lite","version":"1.0.30000741","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000741","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","remark":"^7.0.0","size-limit":"^0.7.1","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"bc526bc2046e6bc38737cfd77d3026ef04b8f464","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000741.tgz"}},"1.0.30000742":{"name":"caniuse-lite","version":"1.0.30000742","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000742","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","remark":"^7.0.0","size-limit":"^0.7.1","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"b5ac8a4a6f36e40a33a6188a8a8bdf8460c32d25","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000742.tgz"}},"1.0.30000743":{"name":"caniuse-lite","version":"1.0.30000743","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000743","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","remark":"^7.0.0","size-limit":"^0.7.1","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"f4f5c6750676ff8f6144ea40456c3729d5341769","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000743.tgz"}},"1.0.30000744":{"name":"caniuse-lite","version":"1.0.30000744","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000744","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","remark":"^7.0.0","size-limit":"^0.7.1","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"860fa5c83ba34fe619397d607f30bb474821671b","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000744.tgz"}},"1.0.30000745":{"name":"caniuse-lite","version":"1.0.30000745","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000745","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","remark":"^7.0.0","size-limit":"^0.7.1","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"20d6fede1157a4935133502946fc7e0e6b880da5","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000745.tgz"}},"1.0.30000746":{"name":"caniuse-lite","version":"1.0.30000746","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000746","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","remark":"^7.0.0","size-limit":"^0.7.1","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"c64f95a3925cfd30207a308ed76c1ae96ea09ea0","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000746.tgz"}},"1.0.30000747":{"name":"caniuse-lite","version":"1.0.30000747","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000747","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","remark":"^7.0.0","size-limit":"^0.7.1","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"da86e78e12d0641abeeaee6ecd55d81bd9bd3b5d","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000747.tgz"}},"1.0.30000748":{"name":"caniuse-lite","version":"1.0.30000748","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000748","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","remark":"^7.0.0","size-limit":"^0.7.1","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"44c8d6da52ad65a5d7b9dca4efebd0bdd982ba09","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000748.tgz"}},"1.0.30000749":{"name":"caniuse-lite","version":"1.0.30000749","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000749","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","remark":"^7.0.0","size-limit":"^0.7.1","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"2ff382865aead8cca35dacfbab04f58effa4c01c","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000749.tgz"}},"1.0.30000750":{"name":"caniuse-lite","version":"1.0.30000750","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000750","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","remark":"^7.0.0","size-limit":"^0.7.1","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"38ad19aa4c6d88da38e8900d3666b4e3bbb65c22","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000750.tgz"}},"1.0.30000751":{"name":"caniuse-lite","version":"1.0.30000751","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000751","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","remark":"^7.0.0","size-limit":"^0.7.1","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"298ad34182ca4359757b4a93afc681b7b917e358","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000751.tgz"}},"1.0.30000752":{"name":"caniuse-lite","version":"1.0.30000752","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000752","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","remark":"^7.0.0","size-limit":"^0.7.1","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"0a79df520669d92ddc7f57406eed935948263130","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000752.tgz"}},"1.0.30000753":{"name":"caniuse-lite","version":"1.0.30000753","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000753","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","remark":"^7.0.0","size-limit":"^0.7.1","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"10d7683272edf94e5f4a8e94710e60c218f6ced7","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000753.tgz"}},"1.0.30000755":{"name":"caniuse-lite","version":"1.0.30000755","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000755","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","remark":"^7.0.0","size-limit":"^0.7.1","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"9ce5f6e06bd75ec8209abe8853c3beef02248d65","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000755.tgz"}},"1.0.30000756":{"name":"caniuse-lite","version":"1.0.30000756","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000756","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","remark":"^7.0.0","size-limit":"^0.7.1","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"3da701c1521b9fab87004c6de7c97fa47dbeaad2","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000756.tgz"}},"1.0.30000757":{"name":"caniuse-lite","version":"1.0.30000757","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000757","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","remark":"^7.0.0","size-limit":"^0.7.1","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"81e3bc029728a032933501994ef79db1c21159e3","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000757.tgz"}},"1.0.30000758":{"name":"caniuse-lite","version":"1.0.30000758","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000758","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","remark":"^7.0.0","size-limit":"^0.7.1","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"e261140076651049cf6891ed4bc649b5c8c26c69","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000758.tgz"}},"1.0.30000760":{"name":"caniuse-lite","version":"1.0.30000760","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000760","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","remark":"^7.0.0","size-limit":"^0.7.1","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"ec720395742f1c7ec8947fd6dd2604e77a8f98ff","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000760.tgz"}},"1.0.30000762":{"name":"caniuse-lite","version":"1.0.30000762","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000762","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","remark":"^7.0.0","size-limit":"^0.7.1","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"0591eaee7e1fc3d95399a8869f2e00092c16ecd9","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000762.tgz"}},"1.0.30000764":{"name":"caniuse-lite","version":"1.0.30000764","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000764","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","remark":"^7.0.0","size-limit":"^0.7.1","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"97ea7472f9d3e691eede34f21983cfc219ac7842","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000764.tgz"}},"1.0.30000765":{"name":"caniuse-lite","version":"1.0.30000765","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000765","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","remark":"^7.0.0","size-limit":"^0.7.1","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"aa1a75019276b48463c0fca2a5257fb9f26a7c9d","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000765.tgz"}},"1.0.30000766":{"name":"caniuse-lite","version":"1.0.30000766","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000766","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","remark":"^7.0.0","size-limit":"^0.7.1","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"8a095cc5eb9923c27008ce4d0db23e65a3e28843","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000766.tgz"}},"1.0.30000769":{"name":"caniuse-lite","version":"1.0.30000769","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000769","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","remark":"^7.0.0","size-limit":"^0.7.1","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"d68c5aa0772ea3eac6c97d42e239c9b4d3261b93","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000769.tgz"}},"1.0.30000770":{"name":"caniuse-lite","version":"1.0.30000770","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000770","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","remark":"^7.0.0","size-limit":"^0.7.1","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"bc8e7f50b073273390db6ab357378909a14e9bdb","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000770.tgz"}},"1.0.30000772":{"name":"caniuse-lite","version":"1.0.30000772","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000772","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","remark":"^7.0.0","size-limit":"^0.7.1","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"78129622cabfed7af1ff38b64ab680a6a0865420","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000772.tgz"}},"1.0.30000774":{"name":"caniuse-lite","version":"1.0.30000774","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000774","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","remark":"^7.0.0","size-limit":"^0.7.1","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"60f4ecf5d45980e7ac5901f03ce67f1ae08df59f","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000774.tgz"}},"1.0.30000775":{"name":"caniuse-lite","version":"1.0.30000775","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000775","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","remark":"^7.0.0","size-limit":"^0.7.1","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"74d27feddc47f3c84cfbcb130c3092a35ebc2de2","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000775.tgz"}},"1.0.30000776":{"name":"caniuse-lite","version":"1.0.30000776","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000776","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","remark":"^7.0.0","size-limit":"^0.7.1","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"616d0f16fb8c7ac69f2ca344fbd501a24879816c","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000776.tgz"}},"1.0.30000777":{"name":"caniuse-lite","version":"1.0.30000777","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000777","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","remark":"^7.0.0","size-limit":"^0.7.1","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"31c18a4a8cd49782ebb305c8e8a93e6b3b3e4f13","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000777.tgz"}},"1.0.30000778":{"name":"caniuse-lite","version":"1.0.30000778","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000778","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","remark":"^7.0.0","size-limit":"^0.7.1","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"f1e7cb8b13b1f6744402291d75f0bcd4c3160369","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000778.tgz"}},"1.0.30000779":{"name":"caniuse-lite","version":"1.0.30000779","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000779","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","remark":"^7.0.0","size-limit":"^0.7.1","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"59285a00d3ce84361d2c668f251fe46baaeb951b","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000779.tgz"}},"1.0.30000780":{"name":"caniuse-lite","version":"1.0.30000780","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000780","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","remark":"^7.0.0","size-limit":"^0.7.1","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"1f9095f2efd4940e0ba6c5992ab7a9b64cc35ba4","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000780.tgz"}},"1.0.30000781":{"name":"caniuse-lite","version":"1.0.30000781","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000781","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","remark":"^7.0.0","size-limit":"^0.7.1","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"d5afb556b65d19eb499ebd1a5ad990633f85cc68","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000781.tgz"}},"1.0.30000782":{"name":"caniuse-lite","version":"1.0.30000782","devDependencies":{"all-contributors-cli":"^3.0.7","any-observable":"^0.2.0","babel-cli":"^6.24.0","babel-generator":"^6.21.0","babel-preset-env":"^1.1.8","babel-register":"^6.18.0","babel-types":"^6.21.0","bunyan":"^1.8.10","caniuse-db":"1.0.30000782","del-cli":"^0.2.1","execa":"^0.6.3","fecha":"^2.3.0","gift":"^0.10.0","got":"^6.7.1","jest":"^19.0.2","listr":"^0.11.0","mdast-util-heading-range":"^2.0.1","mz":"^2.6.0","remark":"^7.0.0","size-limit":"^0.7.1","split":"^1.0.0","stream-to-observable":"^0.2.0","unist-builder":"^1.0.2","write-file-promise":"^1.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"5b82b8c385f25348745c471ca51320afb1b7f254","tarball":"https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000782.tgz"}}},"name":"caniuse-lite","dist-tags":{"latest":"1.0.30000782"},"modified":"2017-12-10T07:01:15.681Z"} \ No newline at end of file diff --git a/__tests__/fixtures/request-cache/GET/registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000782.tgz.bin b/__tests__/fixtures/request-cache/GET/registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000782.tgz.bin new file mode 100644 index 0000000000..46d37d3806 Binary files /dev/null and b/__tests__/fixtures/request-cache/GET/registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000782.tgz.bin differ diff --git a/__tests__/fixtures/request-cache/GET/registry.yarnpkg.com/electron-to-chromium.bin b/__tests__/fixtures/request-cache/GET/registry.yarnpkg.com/electron-to-chromium.bin new file mode 100644 index 0000000000..a8df2b44d1 --- /dev/null +++ b/__tests__/fixtures/request-cache/GET/registry.yarnpkg.com/electron-to-chromium.bin @@ -0,0 +1,21 @@ +HTTP/1.1 200 OK +Date: Mon, 11 Dec 2017 18:38:51 GMT +Content-Type: application/vnd.npm.install-v1+json +Content-Length: 14502 +Connection: keep-alive +Set-Cookie: __cfduid=d88832e1949be97719a1f327c4bc4f7421513017531; expires=Tue, 11-Dec-18 18:38:51 GMT; path=/; domain=.yarnpkg.com; HttpOnly +Cache-Control: max-age=300 +Last-Modified: Tue, 5 Dec 2017 9:02:18 GMT +ETag: "5a26609a-38a6" +Accept-Ranges: bytes +Via: 1.1 varnish +Age: 2862 +X-Served-By: cache-mdw17347-MDW +X-Cache: HIT +X-Cache-Hits: 2 +X-Timer: S1513017532.901913,VS0,VE0 +Vary: Accept-Encoding, Accept +Server: cloudflare-nginx +CF-RAY: 3cba90365f415625-ORD + +{"versions":{"1.0.0":{"name":"electron-to-chromium","version":"1.0.0","devDependencies":{"request":"^2.79.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"984a5364268933e7070f863c2a250720f78b01dc","tarball":"https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.0.0.tgz"}},"1.0.1":{"name":"electron-to-chromium","version":"1.0.1","devDependencies":{"request":"^2.79.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"0d792c55dc927110bec0feca989b5b2616df5b43","tarball":"https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.0.1.tgz"}},"1.1.0":{"name":"electron-to-chromium","version":"1.1.0","devDependencies":{"request":"^2.79.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"c0c5d5bed6843da24c0f68a4d5206207795afbf9","tarball":"https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.1.0.tgz"}},"1.1.1":{"name":"electron-to-chromium","version":"1.1.1","devDependencies":{"request":"^2.79.0","shelljs":"^0.7.6"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"c27f9ec8e6bbbbe55e6076a1d9eec02519627b79","tarball":"https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.1.1.tgz"}},"1.2.0":{"name":"electron-to-chromium","version":"1.2.0","devDependencies":{"request":"^2.79.0","shelljs":"^0.7.6"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"3bd7761f85bd4163602259ae6c7ed338050b17e7","tarball":"https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.2.0.tgz"}},"1.2.1":{"name":"electron-to-chromium","version":"1.2.1","devDependencies":{"request":"^2.79.0","shelljs":"^0.7.6"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"63ac7579a1c5bedb296c8607621f2efc9a54b968","tarball":"https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.2.1.tgz"}},"1.2.2":{"name":"electron-to-chromium","version":"1.2.2","devDependencies":{"request":"^2.79.0","shelljs":"^0.7.6"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"e41bc9488c88e3cfa1e94bde28e8420d7d47c47c","tarball":"https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.2.2.tgz"}},"1.2.3":{"name":"electron-to-chromium","version":"1.2.3","devDependencies":{"request":"^2.79.0","shelljs":"^0.7.6"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"4b4d04d237c301f72e2d15c2137b2b79f9f5ab76","tarball":"https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.2.3.tgz"}},"1.2.4":{"name":"electron-to-chromium","version":"1.2.4","devDependencies":{"request":"^2.79.0","shelljs":"^0.7.6"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"9751cbea89fa120bf88c226ba41eb8d0b6f1b597","tarball":"https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.2.4.tgz"}},"1.2.5":{"name":"electron-to-chromium","version":"1.2.5","devDependencies":{"request":"^2.79.0","shelljs":"^0.7.6"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"d373727228843dfd8466c276089f13b40927a952","tarball":"https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.2.5.tgz"}},"1.2.6":{"name":"electron-to-chromium","version":"1.2.6","devDependencies":{"request":"^2.79.0","shelljs":"^0.7.6"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"f38ad51d1919b06bc07275c62629db803ddca05a","tarball":"https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.2.6.tgz"}},"1.2.7":{"name":"electron-to-chromium","version":"1.2.7","devDependencies":{"request":"^2.79.0","shelljs":"^0.7.6"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"4f748061407e478c76256d04496972b71f647407","tarball":"https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.2.7.tgz"}},"1.2.8":{"name":"electron-to-chromium","version":"1.2.8","devDependencies":{"request":"^2.79.0","shelljs":"^0.7.6"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"22c2e6200d350da27d6050db7e3f6f85d18cf4ed","tarball":"https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.2.8.tgz"}},"1.3.0":{"name":"electron-to-chromium","version":"1.3.0","devDependencies":{"request":"^2.79.0","shelljs":"^0.7.6"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"8fd5aee0eb85e024c3be88bfa99c8b560b661259","tarball":"https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.0.tgz"}},"1.3.1":{"name":"electron-to-chromium","version":"1.3.1","devDependencies":{"request":"^2.79.0","shelljs":"^0.7.6"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"75697666b0abd80104577b53a96a6d06ca2b7f2c","tarball":"https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.1.tgz"}},"1.3.2":{"name":"electron-to-chromium","version":"1.3.2","devDependencies":{"request":"^2.79.0","shelljs":"^0.7.6"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"b8ce5c93b308db0e92f6d0435c46ddec8f6363ab","tarball":"https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.2.tgz"}},"1.3.3":{"name":"electron-to-chromium","version":"1.3.3","devDependencies":{"ava":"^0.18.2","codecov":"^2.1.0","nyc":"^10.2.0","request":"^2.79.0","shelljs":"^0.7.6"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"651eb63fe89f39db70ffc8dbd5d9b66958bc6a0e","tarball":"https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.3.tgz"}},"1.3.4":{"name":"electron-to-chromium","version":"1.3.4","devDependencies":{"ava":"^0.18.2","codecov":"^2.1.0","nyc":"^10.2.0","request":"^2.79.0","shelljs":"^0.7.6"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"e51769c0cf550e0cf5aedf6aa2b803a264b3a900","tarball":"https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.4.tgz"}},"1.3.5":{"name":"electron-to-chromium","version":"1.3.5","devDependencies":{"ava":"^0.18.2","codecov":"^2.1.0","nyc":"^10.2.0","request":"^2.79.0","shelljs":"^0.7.6"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"6cd6ff2106224a6130e235f21050f9546bc3e729","tarball":"https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.5.tgz"}},"1.3.6":{"name":"electron-to-chromium","version":"1.3.6","devDependencies":{"ava":"^0.18.2","codecov":"^2.1.0","nyc":"^10.2.0","request":"^2.79.0","shelljs":"^0.7.6"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"b90ff7e9094e6f7dd343761a001e82592d937db2","tarball":"https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.6.tgz"}},"1.3.7":{"name":"electron-to-chromium","version":"1.3.7","devDependencies":{"ava":"^0.18.2","codecov":"^2.1.0","nyc":"^10.2.0","request":"^2.79.0","shelljs":"^0.7.6"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"9fb75a2417f28114425d364de118d1cfd681432b","tarball":"https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.7.tgz"}},"1.3.8":{"name":"electron-to-chromium","version":"1.3.8","devDependencies":{"ava":"^0.18.2","codecov":"^2.1.0","nyc":"^10.2.0","request":"^2.79.0","shelljs":"^0.7.6"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"b2c8a2c79bb89fbbfd3724d9555e15095b5f5fb6","tarball":"https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.8.tgz"}},"1.3.9":{"name":"electron-to-chromium","version":"1.3.9","devDependencies":{"ava":"^0.18.2","codecov":"^2.1.0","nyc":"^10.2.0","request":"^2.79.0","shelljs":"^0.7.6"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"db1cba2a26aebcca2f7f5b8b034554468609157d","tarball":"https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.9.tgz"}},"1.3.10":{"name":"electron-to-chromium","version":"1.3.10","devDependencies":{"ava":"^0.18.2","codecov":"^2.1.0","nyc":"^10.2.0","request":"^2.79.0","shelljs":"^0.7.6"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"63d62b785471f0d8dda85199d64579de8a449f08","tarball":"https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.10.tgz"}},"1.3.11":{"name":"electron-to-chromium","version":"1.3.11","devDependencies":{"ava":"^0.18.2","codecov":"^2.1.0","nyc":"^10.2.0","request":"^2.79.0","shelljs":"^0.7.6"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"744761df1d67b492b322ce9aa0aba5393260eb61","tarball":"https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.11.tgz"}},"1.3.12":{"name":"electron-to-chromium","version":"1.3.12","devDependencies":{"ava":"^0.18.2","codecov":"^2.1.0","nyc":"^10.2.0","request":"^2.79.0","shelljs":"^0.7.6"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"62f33e4a59b4855f0de4bb8972bf1b841b98b6d2","tarball":"https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.12.tgz"}},"1.3.13":{"name":"electron-to-chromium","version":"1.3.13","devDependencies":{"ava":"^0.18.2","codecov":"^2.1.0","nyc":"^10.2.0","request":"^2.79.0","shelljs":"^0.7.6"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"1b3a5eace6e087bb5e257a100b0cbfe81b2891fc","tarball":"https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.13.tgz"}},"1.3.14":{"name":"electron-to-chromium","version":"1.3.14","devDependencies":{"ava":"^0.18.2","codecov":"^2.1.0","nyc":"^10.2.0","request":"^2.79.0","shelljs":"^0.7.6"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"64af0f9efd3c3c6acd57d71f83b49ca7ee9c4b43","tarball":"https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.14.tgz"}},"1.3.15":{"name":"electron-to-chromium","version":"1.3.15","devDependencies":{"ava":"^0.18.2","codecov":"^2.1.0","nyc":"^10.2.0","request":"^2.79.0","shelljs":"^0.7.6"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"08397934891cbcfaebbd18b82a95b5a481138369","tarball":"https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.15.tgz"}},"1.3.16":{"name":"electron-to-chromium","version":"1.3.16","devDependencies":{"ava":"^0.18.2","codecov":"^2.1.0","nyc":"^10.2.0","request":"^2.79.0","shelljs":"^0.7.6"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"d0e026735754770901ae301a21664cba45d92f7d","tarball":"https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.16.tgz"}},"1.3.17":{"name":"electron-to-chromium","version":"1.3.17","devDependencies":{"ava":"^0.18.2","codecov":"^2.1.0","nyc":"^10.2.0","request":"^2.79.0","shelljs":"^0.7.6"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"41c13457cc7166c5c15e767ae61d86a8cacdee5d","tarball":"https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.17.tgz"}},"1.3.18":{"name":"electron-to-chromium","version":"1.3.18","devDependencies":{"ava":"^0.18.2","codecov":"^2.1.0","nyc":"^10.2.0","request":"^2.79.0","shelljs":"^0.7.6"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"3dcc99da3e6b665f6abbc71c28ad51a2cd731a9c","tarball":"https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.18.tgz"}},"1.3.19":{"name":"electron-to-chromium","version":"1.3.19","devDependencies":{"ava":"^0.18.2","codecov":"^2.1.0","nyc":"^10.2.0","request":"^2.79.0","shelljs":"^0.7.6"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"73d97b0e8b05aa776cedf3cdce7fdc0538037675","tarball":"https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.19.tgz"}},"1.3.20":{"name":"electron-to-chromium","version":"1.3.20","devDependencies":{"ava":"^0.18.2","codecov":"^2.1.0","nyc":"^10.2.0","request":"^2.79.0","shelljs":"^0.7.6"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"2eedd5ccbae7ddc557f68ad1fce9c172e915e4e5","tarball":"https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.20.tgz"}},"1.3.21":{"name":"electron-to-chromium","version":"1.3.21","devDependencies":{"ava":"^0.18.2","codecov":"^2.1.0","nyc":"^10.2.0","request":"^2.79.0","shelljs":"^0.7.6"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"a967ebdcfe8ed0083fc244d1894022a8e8113ea2","tarball":"https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.21.tgz"}},"1.3.22":{"name":"electron-to-chromium","version":"1.3.22","devDependencies":{"ava":"^0.18.2","codecov":"^2.1.0","nyc":"^10.2.0","request":"^2.79.0","shelljs":"^0.7.6"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"4322d52c151406e3eaef74ad02676883e8416418","tarball":"https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.22.tgz"}},"1.3.23":{"name":"electron-to-chromium","version":"1.3.23","devDependencies":{"ava":"^0.18.2","codecov":"^2.1.0","nyc":"^10.2.0","request":"^2.79.0","shelljs":"^0.7.6"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"e6668ab18cb69afb8f577c8a9fc23d002788be74","tarball":"https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.23.tgz"}},"1.3.24":{"name":"electron-to-chromium","version":"1.3.24","devDependencies":{"ava":"^0.18.2","codecov":"^2.1.0","nyc":"^10.2.0","request":"^2.79.0","shelljs":"^0.7.6"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"9b7b88bb05ceb9fa016a177833cc2dde388f21b6","tarball":"https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.24.tgz"}},"1.3.25":{"name":"electron-to-chromium","version":"1.3.25","devDependencies":{"ava":"^0.18.2","codecov":"^2.1.0","nyc":"^10.2.0","request":"^2.79.0","shelljs":"^0.7.6"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"453b21009836d0997d86035601ff6cae4791c460","tarball":"https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.25.tgz"}},"1.3.26":{"name":"electron-to-chromium","version":"1.3.26","devDependencies":{"ava":"^0.18.2","codecov":"^2.1.0","nyc":"^10.2.0","request":"^2.79.0","shelljs":"^0.7.6"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"996427294861a74d9c7c82b9260ea301e8c02d66","tarball":"https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.26.tgz"}},"1.3.27":{"name":"electron-to-chromium","version":"1.3.27","devDependencies":{"ava":"^0.18.2","codecov":"^2.1.0","nyc":"^10.2.0","request":"^2.79.0","shelljs":"^0.7.6"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"78ecb8a399066187bb374eede35d9c70565a803d","tarball":"https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.27.tgz"}},"1.3.28":{"name":"electron-to-chromium","version":"1.3.28","devDependencies":{"ava":"^0.18.2","codecov":"^2.1.0","nyc":"^10.2.0","request":"^2.79.0","shelljs":"^0.7.6"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"8dd4e6458086644e9f9f0a1cf32e2a1f9dffd9ee","tarball":"https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.28.tgz"}}},"name":"electron-to-chromium","dist-tags":{"latest":"1.3.28"},"modified":"2017-12-05T09:02:18.254Z"} \ No newline at end of file diff --git a/__tests__/fixtures/request-cache/GET/registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.28.tgz.bin b/__tests__/fixtures/request-cache/GET/registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.28.tgz.bin new file mode 100644 index 0000000000..9a711e727a Binary files /dev/null and b/__tests__/fixtures/request-cache/GET/registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.28.tgz.bin differ diff --git a/__tests__/fixtures/request-cache/GET/registry.yarnpkg.com/loader-utils.bin b/__tests__/fixtures/request-cache/GET/registry.yarnpkg.com/loader-utils.bin index 265dd3b6b1..ec6a3b3176 100644 Binary files a/__tests__/fixtures/request-cache/GET/registry.yarnpkg.com/loader-utils.bin and b/__tests__/fixtures/request-cache/GET/registry.yarnpkg.com/loader-utils.bin differ diff --git a/__tests__/fixtures/request-cache/GET/registry.yarnpkg.com/lodash.memoize.bin b/__tests__/fixtures/request-cache/GET/registry.yarnpkg.com/lodash.memoize.bin new file mode 100644 index 0000000000..a06fad7380 --- /dev/null +++ b/__tests__/fixtures/request-cache/GET/registry.yarnpkg.com/lodash.memoize.bin @@ -0,0 +1,21 @@ +HTTP/1.1 200 OK +Date: Mon, 11 Dec 2017 18:38:52 GMT +Content-Type: application/vnd.npm.install-v1+json +Content-Length: 5904 +Connection: keep-alive +Set-Cookie: __cfduid=d942f2b24f634f142722f0777b300562a1513017532; expires=Tue, 11-Dec-18 18:38:52 GMT; path=/; domain=.yarnpkg.com; HttpOnly +Cache-Control: max-age=300 +Last-Modified: Mon, 22 May 2017 3:50:12 GMT +ETag: "59225ff4-1710" +Accept-Ranges: bytes +Via: 1.1 varnish +Age: 3081 +X-Served-By: cache-mdw17327-MDW +X-Cache: HIT +X-Cache-Hits: 1 +X-Timer: S1513017532.081757,VS0,VE1 +Vary: Accept-Encoding, Accept +Server: cloudflare-nginx +CF-RAY: 3cba90377a832591-ORD + +{"versions":{"2.0.0":{"name":"lodash.memoize","version":"2.0.0","dependencies":{"lodash.isfunction":"~2.0.0","lodash._keyprefix":"~2.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"dbd81ea8b64e05d3dfd43ad9a249ceeec51a3c56","tarball":"https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-2.0.0.tgz"}},"2.1.0":{"name":"lodash.memoize","version":"2.1.0","dependencies":{"lodash.isfunction":"~2.1.0","lodash._keyprefix":"~2.1.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"81b0d5d070402321ae6350ef36e61d436963f78b","tarball":"https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-2.1.0.tgz"}},"2.2.0":{"name":"lodash.memoize","version":"2.2.0","dependencies":{"lodash.isfunction":"~2.2.0","lodash._keyprefix":"~2.2.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"25e24314b2321bc8ee6b375634378e1dadb8b500","tarball":"https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-2.2.0.tgz"}},"2.2.1":{"name":"lodash.memoize","version":"2.2.1","dependencies":{"lodash.isfunction":"~2.2.1","lodash._keyprefix":"~2.2.1"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"7ada90bea3cb07b08ed3e1a3b8366b630d7e47c4","tarball":"https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-2.2.1.tgz"}},"2.3.0":{"name":"lodash.memoize","version":"2.3.0","dependencies":{"lodash.isfunction":"~2.3.0","lodash._keyprefix":"~2.3.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"33e069f7c8aecd62740354308507eccc0177c9f7","tarball":"https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-2.3.0.tgz"}},"2.4.0":{"name":"lodash.memoize","version":"2.4.0","dependencies":{"lodash.isfunction":"~2.4.0","lodash._keyprefix":"~2.4.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"abf14070c8382fd1b25d26e7817727ff5557c0d2","tarball":"https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-2.4.0.tgz"}},"2.4.1":{"name":"lodash.memoize","version":"2.4.1","dependencies":{"lodash.isfunction":"~2.4.1","lodash._keyprefix":"~2.4.1"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"a014470dd6d03e73663843ea3b60d6972c3b8c30","tarball":"https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-2.4.1.tgz"}},"3.0.0":{"name":"lodash.memoize","version":"3.0.0","dependencies":{"lodash.isfunction":"^3.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"ff7475e87866d7a8d556d615ea8a8b9b6af9e6c4","tarball":"https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-3.0.0.tgz"}},"3.0.1":{"name":"lodash.memoize","version":"3.0.1","dependencies":{"lodash.isfunction":"^3.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"ec9f7c48ec76405a9d0ab21111c1408a9c5f9bdd","tarball":"https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-3.0.1.tgz"}},"3.0.2":{"name":"lodash.memoize","version":"3.0.2","_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"7b7ce2816a8c9d6f3beb21caa0985d3de2ea3e86","tarball":"https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-3.0.2.tgz"}},"3.0.3":{"name":"lodash.memoize","version":"3.0.3","_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"2fc47e23b9edf8a9c8f23298452240350c3b196d","tarball":"https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-3.0.3.tgz"}},"3.0.4":{"name":"lodash.memoize","version":"3.0.4","_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"2dcbd2c287cbc0a55cc42328bd0c736150d53e3f","tarball":"https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-3.0.4.tgz"}},"3.1.0":{"name":"lodash.memoize","version":"3.1.0","dependencies":{"lodash._mapcache":"^3.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"63b2914fd54205b58144037060812edc12040edf","tarball":"https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-3.1.0.tgz"}},"3.1.1":{"name":"lodash.memoize","version":"3.1.1","_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"581bc0bf46e3d5dcde7b305cbd7121926ff0d84c","tarball":"https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-3.1.1.tgz"}},"4.0.0":{"name":"lodash.memoize","version":"4.0.0","dependencies":{"lodash._mapcache":"^4.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"9f65275a01ad2eb97722315621175bf0f99f725b","tarball":"https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.0.0.tgz"}},"4.0.1":{"name":"lodash.memoize","version":"4.0.1","dependencies":{"lodash._mapcache":"^4.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"f510e66c098e431a7656b1f9456c1402d880a46a","tarball":"https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.0.1.tgz"}},"4.0.2":{"name":"lodash.memoize","version":"4.0.2","dependencies":{"lodash._mapcache":"~4.1.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"7e205ba23f6a6b1c55e541ebdf919bc0d5bcde1d","tarball":"https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.0.2.tgz"}},"4.0.3":{"name":"lodash.memoize","version":"4.0.3","dependencies":{"lodash._mapcache":"~4.1.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"ec33633118d0931dd143d0480b1aae9397c9f572","tarball":"https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.0.3.tgz"}},"4.1.0":{"name":"lodash.memoize","version":"4.1.0","dependencies":{"lodash._root":"~3.0.0"},"_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"7b29100f5ee714466528e09bd5da4fb2898524c1","tarball":"https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.0.tgz"}},"4.1.1":{"name":"lodash.memoize","version":"4.1.1","_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"1f5a26e0560c7eed6140c4f4fb56be248456c8a1","tarball":"https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.1.tgz"}},"4.1.2":{"name":"lodash.memoize","version":"4.1.2","_hasShrinkwrap":false,"directories":{},"dist":{"shasum":"bcc6c49a42a2840ed997f323eada5ecd182e0bfe","tarball":"https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz"}}},"name":"lodash.memoize","dist-tags":{"latest":"4.1.2"},"modified":"2017-05-22T03:50:12.401Z"} \ No newline at end of file diff --git a/__tests__/fixtures/run/script-shell/package.json b/__tests__/fixtures/run/script-shell/package.json new file mode 100644 index 0000000000..7adbf000a9 --- /dev/null +++ b/__tests__/fixtures/run/script-shell/package.json @@ -0,0 +1,6 @@ +{ + "license": "MIT", + "scripts": { + "start": "echo $SHELL" + } +} diff --git a/__tests__/fixtures/upgrade/direct-dependency/package.json b/__tests__/fixtures/upgrade/direct-dependency/package.json new file mode 100644 index 0000000000..ace0343538 --- /dev/null +++ b/__tests__/fixtures/upgrade/direct-dependency/package.json @@ -0,0 +1,5 @@ +{ + "dependencies": { + "async": "2.0.0" + } +} diff --git a/__tests__/fixtures/upgrade/direct-dependency/yarn.lock b/__tests__/fixtures/upgrade/direct-dependency/yarn.lock new file mode 100644 index 0000000000..7228efd284 --- /dev/null +++ b/__tests__/fixtures/upgrade/direct-dependency/yarn.lock @@ -0,0 +1,13 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +async@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/async/-/async-2.0.0.tgz#d0900ad385af13804540a109c42166e3ae7b2b9d" + dependencies: + lodash "^4.8.0" + +lodash@^4.8.0: + version "4.17.4" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" diff --git a/__tests__/fixtures/why/dep-included-at-2-levels/b/package.json b/__tests__/fixtures/why/dep-included-at-2-levels/b/package.json new file mode 100644 index 0000000000..fc5061589d --- /dev/null +++ b/__tests__/fixtures/why/dep-included-at-2-levels/b/package.json @@ -0,0 +1,8 @@ +{ + "name": "b", + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "caniuse-api": "^2.0.0" + } +} diff --git a/__tests__/fixtures/why/dep-included-at-2-levels/package.json b/__tests__/fixtures/why/dep-included-at-2-levels/package.json new file mode 100644 index 0000000000..190b600fc8 --- /dev/null +++ b/__tests__/fixtures/why/dep-included-at-2-levels/package.json @@ -0,0 +1,9 @@ +{ + "name": "a", + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "b": "file:./b", + "caniuse-lite": "^1.0.0" + } +} diff --git a/__tests__/fixtures/why/workspaces-nohoist/package.json b/__tests__/fixtures/why/workspaces-nohoist/package.json new file mode 100644 index 0000000000..5ea0ec1e73 --- /dev/null +++ b/__tests__/fixtures/why/workspaces-nohoist/package.json @@ -0,0 +1,10 @@ +{ + "private": true, + "workspaces": { + "packages": ["packages/*"], + "nohoist": ["mime-db"] + }, + "devDependencies": { + "left-pad": "1.1.3" + } +} diff --git a/__tests__/fixtures/why/workspaces-nohoist/packages/workspace-1/package.json b/__tests__/fixtures/why/workspaces-nohoist/packages/workspace-1/package.json new file mode 100644 index 0000000000..2f31a8c858 --- /dev/null +++ b/__tests__/fixtures/why/workspaces-nohoist/packages/workspace-1/package.json @@ -0,0 +1,12 @@ +{ + "name": "workspace-1", + "version": "1.0.0", + "private": true, + "workspaces": { + "nohoist": ["mime-types"] + }, + "dependencies": { + "mime-types": "2.1.12", + "uglifyify": "3.0.0" + } +} diff --git a/__tests__/fixtures/why/workspaces-nohoist/packages/workspace-2/package.json b/__tests__/fixtures/why/workspaces-nohoist/packages/workspace-2/package.json new file mode 100644 index 0000000000..ba904dd210 --- /dev/null +++ b/__tests__/fixtures/why/workspaces-nohoist/packages/workspace-2/package.json @@ -0,0 +1,9 @@ +{ + "name": "workspace-2", + "version": "1.0.0", + "private": false, + "dependencies": { + "mime-types": "2.1.12", + "uglifyify": "3.0.4" + } +} diff --git a/__tests__/index.js b/__tests__/index.js index 88541afc5b..48b8cec5f1 100644 --- a/__tests__/index.js +++ b/__tests__/index.js @@ -60,20 +60,8 @@ async function execCommand( }); } -function expectAddSuccessfullOutput(stdout, pkg) { - const lastLines = stdout.slice(stdout.length - 4); - expect(lastLines[0]).toEqual('success Saved lockfile.'); - expect(lastLines[1]).toEqual('success Saved 1 new dependency.'); - expect(lastLines[2]).toContain(pkg); - expect(lastLines[3]).toContain('Done'); -} - -function expectAddSuccessfullOutputWithNoLockFile(stdout, pkg) { - const lastLines = stdout.slice(stdout.length - 4); - expect(lastLines[0]).not.toEqual('success Saved lockfile.'); - expect(lastLines[1]).toEqual('success Saved 1 new dependency.'); - expect(lastLines[2]).toContain(pkg); - expect(lastLines[3]).toContain('Done'); +function expectAddOutput(stdout) { + expect(stdout.slice(1, stdout.length - 1)).toMatchSnapshot(); } function expectRunOutput(stdout) { @@ -112,29 +100,29 @@ function expectAnInfoMessageAfterError(command: Promise>, expecte .catch(error => expect(error.stdout).toContain(expectedInfo)); } -test.concurrent('should add package', async () => { +test('should add package', async () => { const stdout = await execCommand('add', ['left-pad'], 'run-add', true); - expectAddSuccessfullOutput(stdout, 'left-pad'); + expectAddOutput(stdout); }); -test.concurrent('should add package with no-lockfile option', async () => { +test('should add package with no-lockfile option', async () => { const stdout = await execCommand('add', ['repeating', '--no-lockfile'], 'run-add-option', true); - expectAddSuccessfullOutputWithNoLockFile(stdout, 'repeating'); + expectAddOutput(stdout); }); -test.concurrent('should add package with frozen-lockfile option', async () => { +test('should add package with frozen-lockfile option', async () => { const stdout = await execCommand('add', ['repeating', '--frozen-lockfile'], 'run-add-option', true); - expectAddSuccessfullOutputWithNoLockFile(stdout, 'repeating'); + expectAddOutput(stdout); }); -test.concurrent('should add package with no-lockfile option in front', async () => { +test('should add package with no-lockfile option in front', async () => { const stdout = await execCommand('add', ['--no-lockfile', 'split-lines'], 'run-add-option-in-front', true); - expectAddSuccessfullOutputWithNoLockFile(stdout, 'split-lines'); + expectAddOutput(stdout); }); -test.concurrent('should add lockfile package', async () => { +test('should add lockfile package', async () => { const stdout = await execCommand('add', ['lockfile'], 'run-add-lockfile', true); - expectAddSuccessfullOutput(stdout, 'lockfile'); + expectAddOutput(stdout); }); // test is failing on Node 4, https://travis-ci.org/yarnpkg/yarn/jobs/216254539 diff --git a/__tests__/package-hoister.js b/__tests__/package-hoister.js index 4f29557503..c26b0180d9 100644 --- a/__tests__/package-hoister.js +++ b/__tests__/package-hoister.js @@ -4,8 +4,12 @@ import PackageHoister, {HoistManifest} from '../src/package-hoister.js'; import PackageResolver from '../src/package-resolver.js'; import Lockfile from '../src/lockfile'; import type PackageReference from '../src/package-reference.js'; +import {extractWorkspaces} from '../src/config.js'; import type Config from '../src/config.js'; -import type {Manifest} from '../src/types.js'; +import type {Manifest, WorkspacesManifestMap, WorkspacesConfig} from '../src/types.js'; +import WorkspaceLayout from '../src/workspace-layout.js'; +import {getPackagePath} from './commands/_helpers.js'; +import mm from 'micromatch'; const path = require('path'); @@ -28,16 +32,29 @@ function createManifestForUid(uid, dependencies): Manifest { // key is the module uid, in the form name@version ('lodash@1.2.3') // value is an array of strings of dependencies (['lodash@1.2.3', 'grunt@4.5.6']) // These modules will be loaded into a mock PackageResolver that will use the hash's keys to resolve the package. -function createTestFixture(testModules: any = {}): any { - const config = (({ +type UpdateResolver = (resolver: PackageResolver, config: Config) => void; + +function createTestFixture( + testModules: any = {}, + workspacesEnabled: boolean = true, + updateResolver?: UpdateResolver, +): any { + const config: Config = (({ cwd: CWD, lockfileFolder: CWD, + workspacesEnabled, getFolder(): string { return 'node_modules'; }, generateHardModulePath(pkg: ?PackageReference): string { return pkg ? pkg.uid : ''; }, + getWorkspaces(manifest: ?Manifest): ?WorkspacesConfig { + if (this.workspacesEnabled) { + return extractWorkspaces(manifest); + } + return undefined; + }, }: any): Config); // build Manifests with just enough information to get the PackageHoister to work. @@ -50,6 +67,10 @@ function createTestFixture(testModules: any = {}): any { packageResolver.addPattern(uid, packageManifest); }); + if (updateResolver) { + updateResolver(packageResolver, config); + } + const packageHoister = new PackageHoister(config, packageResolver); const atPath = function(...installPaths): string { @@ -72,6 +93,7 @@ function createTestFixture(testModules: any = {}): any { const toContainPackage = function(received: any, ...expected: any): JestMatcherResult { const [uid, expectedInstallPath] = expected; + let pass: boolean = false; received.forEach(pkg => { const [location: string, hoistManifest: HoistManifest] = pkg; @@ -311,3 +333,505 @@ test('will hoist packages under subdirectories when they cannot hoist to root', expect(result).toContainPackage('c@1.0.0', atPath('a', 'node_modules', 'c')); expect(result).toContainPackage('d@1.0.0', atPath('a', 'node_modules', 'd')); }); + +describe('nohoist', () => { + test('nohoist can be turned off by disable workspaces (workspaces-experimental)', () => { + const {atPath, packageHoister, packageResolver} = createTestFixture( + { + 'a@1.0.0': ['c@1.0.0'], + 'b@2.0.0': [], + 'c@1.0.0': [], + }, + false, + ); + const pkg: any = packageResolver.getStrictResolvedPattern('a@1.0.0'); + pkg.workspaces = {nohoist: ['c']}; + + packageHoister.seed(['a@1.0.0', 'b@2.0.0']); + const result = packageHoister.init(); + + expect(result.length).toEqual(3); + expect(result).toContainPackage('a@1.0.0', atPath('a')); + expect(result).toContainPackage('b@2.0.0', atPath('b')); + expect(result).toContainPackage('c@1.0.0', atPath('c')); + }); + describe('nohoist = hoist to the top of its branch instead of root', () => { + function fixture(): any { + return createTestFixture({ + 'a@1.0.0': ['c@1.0.0'], + 'b@1.0.0': ['c@1.0.0'], + 'c@1.0.0': ['d@1.0.0'], + 'd@1.0.0': [], + }); + } + test('shallow nohoist', () => { + const {atPath, packageHoister, packageResolver} = fixture(); + + // nohoist a/c + const pkg: any = packageResolver.getStrictResolvedPattern('a@1.0.0'); + pkg.workspaces = {nohoist: ['c']}; + + packageHoister.seed(['a@1.0.0', 'b@1.0.0']); + const result = packageHoister.init(); + + expect(result.length).toEqual(5); + expect(result).toContainPackage('a@1.0.0', atPath('a')); + expect(result).toContainPackage('b@1.0.0', atPath('b')); + expect(result).toContainPackage('c@1.0.0', atPath('c')); + expect(result).toContainPackage('d@1.0.0', atPath('d')); + expect(result).toContainPackage('c@1.0.0', atPath('a', 'node_modules', 'c')); + }); + test('deep nohoist', () => { + const {atPath, packageHoister, packageResolver} = fixture(); + + // nohoist a/c and everything under a/c + const pkg: any = packageResolver.getStrictResolvedPattern('a@1.0.0'); + pkg.workspaces = {nohoist: ['c', 'c/**']}; + + packageHoister.seed(['a@1.0.0', 'b@1.0.0']); + const result = packageHoister.init(); + + expect(result.length).toEqual(6); + expect(result).toContainPackage('a@1.0.0', atPath('a')); + expect(result).toContainPackage('b@1.0.0', atPath('b')); + expect(result).toContainPackage('c@1.0.0', atPath('c')); + expect(result).toContainPackage('d@1.0.0', atPath('d')); + expect(result).toContainPackage('c@1.0.0', atPath('a', 'node_modules', 'c')); + expect(result).toContainPackage('d@1.0.0', atPath('a', 'node_modules', 'd')); + }); + }); + test('nohoist pkg will be duplicated independent of the hoisted version', () => { + const {atPath, packageHoister, packageResolver} = createTestFixture({ + 'a@1.0.0': ['c@1.0.0'], + 'b@1.0.0': ['c@1.0.0'], + 'c@1.0.0': ['d@1.0.0'], + 'd@1.0.0': [], + }); + + const pkg: any = packageResolver.getStrictResolvedPattern('a@1.0.0'); + pkg.workspaces = {nohoist: ['c']}; + + packageHoister.seed(['a@1.0.0', 'b@1.0.0']); + const result = packageHoister.init(); + + expect(result.length).toEqual(5); + expect(result).toContainPackage('a@1.0.0', atPath('a')); + expect(result).toContainPackage('b@1.0.0', atPath('b')); + expect(result).toContainPackage('c@1.0.0', atPath('a', 'node_modules', 'c')); + expect(result).toContainPackage('c@1.0.0', atPath('c')); + expect(result).toContainPackage('d@1.0.0', atPath('d')); + }); + test('nohoist pkg will NOT be duplicated within the same branch', () => { + const {atPath, packageHoister, packageResolver} = createTestFixture({ + 'a@1.0.0': ['b@1.0.0', 'c@1.0.0'], + 'b@1.0.0': ['d@1.0.0'], + 'c@1.0.0': ['d@1.0.0'], + 'd@1.0.0': [], + }); + + const pkg: any = packageResolver.getStrictResolvedPattern('a@1.0.0'); + pkg.workspaces = {nohoist: ['b', 'c', '**/d']}; + + packageHoister.seed(['a@1.0.0']); + const result = packageHoister.init(); + + expect(result.length).toEqual(4); + expect(result).toContainPackage('a@1.0.0', atPath('a')); + expect(result).toContainPackage('b@1.0.0', atPath('a', 'node_modules', 'b')); + expect(result).toContainPackage('c@1.0.0', atPath('a', 'node_modules', 'c')); + expect(result).toContainPackage('d@1.0.0', atPath('a', 'node_modules', 'd')); + }); + test('can dedup and avoid circular reference', () => { + const {atPath, packageHoister, packageResolver} = createTestFixture({ + 'a@1.0.0': ['c@1.0.0'], + 'b@2.0.0': [], + 'c@1.0.0': ['d@1.0.0'], + 'd@1.0.0': ['c@1.0.0'], + }); + + const pkg: any = packageResolver.getStrictResolvedPattern('a@1.0.0'); + pkg.workspaces = {nohoist: ['c']}; + + packageHoister.seed(['a@1.0.0', 'b@2.0.0']); + const result = packageHoister.init(); + + expect(result.length).toEqual(5); + expect(result).toContainPackage('a@1.0.0', atPath('a')); + expect(result).toContainPackage('b@2.0.0', atPath('b')); + expect(result).toContainPackage('c@1.0.0', atPath('a', 'node_modules', 'c')); + expect(result).toContainPackage('d@1.0.0', atPath('d')); + expect(result).toContainPackage('c@1.0.0', atPath('c')); + }); + test('can handle conflict version', () => { + const {atPath, packageHoister, packageResolver} = createTestFixture({ + 'a@1.0.0': ['c@1.0.0'], + 'b@2.0.0': [], + 'b@1.0.0': [], + 'c@1.0.0': ['b@1.0.0'], + }); + + const pkg: any = packageResolver.getStrictResolvedPattern('a@1.0.0'); + pkg.workspaces = {nohoist: ['c']}; + + packageHoister.seed(['a@1.0.0', 'b@2.0.0']); + const result = packageHoister.init(); + + expect(result.length).toEqual(4); + expect(result).toContainPackage('a@1.0.0', atPath('a')); + expect(result).toContainPackage('b@2.0.0', atPath('b')); + expect(result).toContainPackage('c@1.0.0', atPath('a', 'node_modules', 'c')); + expect(result).toContainPackage('b@1.0.0', atPath('a', 'node_modules', 'b')); + }); + + test('nohoist matches package regardless version', () => { + const {atPath, packageHoister, packageResolver} = createTestFixture({ + 'a@1.0.0': ['b@1.0.0', 'c@1.0.0'], + 'b@1.0.0': [], + 'b@2.0.0': [], + 'c@1.0.0': ['b@2.0.0'], + }); + + const pkg: any = packageResolver.getStrictResolvedPattern('a@1.0.0'); + pkg.workspaces = {nohoist: ['b', 'c']}; + + packageHoister.seed(['a@1.0.0']); + const result = packageHoister.init(); + + expect(result.length).toEqual(4); + expect(result).toContainPackage('a@1.0.0', atPath('a')); + expect(result).toContainPackage('b@1.0.0', atPath('a', 'node_modules', 'b')); + expect(result).toContainPackage('c@1.0.0', atPath('a', 'node_modules', 'c')); + expect(result).toContainPackage('b@2.0.0', atPath('a', 'node_modules', 'c', 'node_modules', 'b')); + }); + test('can detect circular reference', () => { + const {atPath, packageHoister, packageResolver} = createTestFixture({ + 'a@1.0.0': ['b@1.0.0', 'c@1.0.0'], + 'b@2.0.0': [], + 'b@1.0.0': ['c@1.0.0'], + 'c@1.0.0': ['b@2.0.0'], + }); + + const pkg: any = packageResolver.getStrictResolvedPattern('a@1.0.0'); + pkg.workspaces = {nohoist: ['b']}; + + packageHoister.seed(['a@1.0.0', 'b@2.0.0']); + const result = packageHoister.init(); + + expect(result.length).toEqual(4); + expect(result).toContainPackage('a@1.0.0', atPath('a')); + expect(result).toContainPackage('b@2.0.0', atPath('b')); + expect(result).toContainPackage('b@1.0.0', atPath('a', 'node_modules', 'b')); + expect(result).toContainPackage('c@1.0.0', atPath('c')); + }); + test('can nohoist a linked package', () => { + const {atPath, packageHoister, packageResolver} = createTestFixture({ + 'a@1.0.0': ['b@1.0.0', 'c@1.0.0'], + 'b@1.0.0': ['d@1.0.0'], + 'c@1.0.0': [], + 'd@1.0.0': [], + }); + + // b is a linked package + let pkg: any = packageResolver.getStrictResolvedPattern('b@1.0.0'); + pkg._remote = {type: 'link'}; + + // a will not hoist b and everything under b + pkg = packageResolver.getStrictResolvedPattern('a@1.0.0'); + pkg.workspaces = {nohoist: ['b', 'b/**']}; + + packageHoister.seed(['a@1.0.0']); + const result = packageHoister.init(); + + expect(result.length).toEqual(4); + expect(result).toContainPackage('a@1.0.0', atPath('a')); + expect(result).toContainPackage('c@1.0.0', atPath('c')); + expect(result).toContainPackage('d@1.0.0', atPath('a', 'node_modules', 'd')); + expect(result).toContainPackage('b@1.0.0', atPath('a', 'node_modules', 'b')); + }); + + describe('nohoistList pattern matching', () => { + const paths = ['a', 'a/b', 'a/b/c', 'a/b/c/d', 'a/d', 'b/c', 'd/a', 'e/d/a', 'd/a/e', 'd/a/e/b']; + test('match explicit path', () => { + expect(mm(paths, 'a')).toEqual(['a']); + expect(mm(paths, 'b/c')).toEqual(['b/c']); + expect(mm(paths, 'd')).toEqual([]); + expect(mm(paths, 'a/b')).toEqual(['a/b']); + }); + test('match glob pattern', () => { + expect(mm(paths, '**')).toEqual(paths); + expect(mm(paths, '*')).toEqual(['a']); + + expect(mm(paths, 'a/*')).toEqual(['a/b', 'a/d']); + expect(mm(paths, 'a/**')).toEqual(['a/b', 'a/b/c', 'a/b/c/d', 'a/d']); + expect(mm(paths, '*/a')).toEqual(['d/a']); + expect(mm(paths, '**/a')).toEqual(['a', 'd/a', 'e/d/a']); + expect(mm(paths, '*/a/*')).toEqual(['d/a/e']); + expect(mm(paths, '**/a/**')).toEqual(['a/b', 'a/b/c', 'a/b/c/d', 'a/d', 'd/a/e', 'd/a/e/b']); + }); + }); + test('can disable hoist for the whole branch', () => { + const {atPath, packageHoister, packageResolver} = createTestFixture({ + 'a@1.0.0': ['b@1.0.0', 'c@1.0.0'], + 'b@1.0.0': ['d@1.0.0'], + 'c@1.0.0': ['d@1.0.0'], + 'd@1.0.0': [], + }); + + // disable hoisting for everything under a + const pkg: any = packageResolver.getStrictResolvedPattern('a@1.0.0'); + pkg.workspaces = {nohoist: ['**']}; + + packageHoister.seed(['a@1.0.0', 'b@1.0.0']); + const result = packageHoister.init(); + + expect(result.length).toEqual(6); + expect(result).toContainPackage('a@1.0.0', atPath('a')); + expect(result).toContainPackage('b@1.0.0', atPath('b')); + expect(result).toContainPackage('d@1.0.0', atPath('d')); + + expect(result).toContainPackage('b@1.0.0', atPath('a', 'node_modules', 'b')); + expect(result).toContainPackage('c@1.0.0', atPath('a', 'node_modules', 'c')); + expect(result).toContainPackage('d@1.0.0', atPath('a', 'node_modules', 'd')); + }); + test('can disable hoist for particular package tree', () => { + const {atPath, packageHoister, packageResolver} = createTestFixture({ + 'a@1.0.0': ['b@1.0.0', 'e@1.0.0'], + 'b@1.0.0': ['c@1.0.0'], + 'c@1.0.0': ['d@1.0.0'], + 'd@1.0.0': [], + 'e@1.0.0': [], + }); + + // disable hoisting for everything under a + const pkg: any = packageResolver.getStrictResolvedPattern('a@1.0.0'); + pkg.workspaces = {nohoist: ['b', 'b/**']}; + + packageHoister.seed(['a@1.0.0']); + const result = packageHoister.init(); + + expect(result.length).toEqual(5); + expect(result).toContainPackage('a@1.0.0', atPath('a')); + expect(result).toContainPackage('e@1.0.0', atPath('e')); + + expect(result).toContainPackage('b@1.0.0', atPath('a', 'node_modules', 'b')); + expect(result).toContainPackage('c@1.0.0', atPath('a', 'node_modules', 'c')); + expect(result).toContainPackage('d@1.0.0', atPath('a', 'node_modules', 'd')); + }); + describe('nohoist with workspaces context', () => { + function updateWorkspaces(rootPattern: string, nohoist?: Array, workspaces: Array): UpdateResolver { + return (resolver: PackageResolver, config: Config): void => { + const root: Manifest = resolver.getStrictResolvedPattern(rootPattern); + if (nohoist) { + root.workspaces = {nohoist}; + } + + const wsMap: WorkspacesManifestMap = {}; + wsMap[root.name] = {loc: root._loc || '', manifest: root}; + + workspaces.forEach(w => { + const pkg = resolver.getStrictResolvedPattern(w); + pkg._remote = { + type: 'workspace', + registry: 'npm', + hash: null, + reference: '', + }; + wsMap[pkg.name] = {loc: pkg._loc || '', manifest: pkg}; + }); + resolver.workspaceLayout = new WorkspaceLayout(wsMap, config); + resolver.workspaceLayout.virtualManifestName = root.name; + + // hoister.nohoistResolver._wsRootPackageName = root.name; + }; + } + describe('disable hoist for a package', () => { + function fixture(f: UpdateResolver): any { + return createTestFixture( + { + 'w1@1.0.0': ['a@1.0.0'], + 'w2@1.0.0': ['a@1.0.0', 'b@1.0.0'], + 'a@1.0.0': ['c@1.0.0'], + 'b@1.0.0': ['a@1.0.0'], + 'c@1.0.0': [], + 'root@1.0.0': ['w1@1.0.0', 'w2@1.0.0'], + }, + true, + f, + ); + } + + test('from root for all workspaces', () => { + // root disable 'a' hoisting, no matter where it is + const {packageHoister} = fixture(updateWorkspaces('root@1.0.0', ['**/a'], ['w1@1.0.0', 'w2@1.0.0'])); + const config = packageHoister.config; + + packageHoister.seed(['root@1.0.0']); + const result = packageHoister.init(); + + expect(result.length).toEqual(8); + expect(result).toContainPackage('root@1.0.0', getPackagePath(config, 'root')); + expect(result).toContainPackage('w1@1.0.0', getPackagePath(config, 'w1')); + expect(result).toContainPackage('w2@1.0.0', getPackagePath(config, 'w2')); + expect(result).toContainPackage('b@1.0.0', getPackagePath(config, 'b')); + expect(result).toContainPackage('c@1.0.0', getPackagePath(config, 'c')); + + expect(result).toContainPackage('a@1.0.0', getPackagePath(config, 'w1/a')); + expect(result).toContainPackage('a@1.0.0', getPackagePath(config, 'w2/a')); + + // note: a hoisted b will also inherit the root's nohoist constraint + expect(result).toContainPackage('a@1.0.0', getPackagePath(config, 'b/a')); + }); + test('from root for a specific workspaces', () => { + // root disable 'a' hoisting, no matter where it is + const {packageHoister} = fixture(updateWorkspaces('root@1.0.0', ['w1/a'], ['w1@1.0.0', 'w2@1.0.0'])); + const config = packageHoister.config; + + packageHoister.seed(['root@1.0.0']); + const result = packageHoister.init(); + + expect(result.length).toEqual(7); + expect(result).toContainPackage('root@1.0.0', getPackagePath(config, 'root')); + expect(result).toContainPackage('w1@1.0.0', getPackagePath(config, 'w1')); + expect(result).toContainPackage('w2@1.0.0', getPackagePath(config, 'w2')); + expect(result).toContainPackage('a@1.0.0', getPackagePath(config, 'a')); + expect(result).toContainPackage('b@1.0.0', getPackagePath(config, 'b')); + expect(result).toContainPackage('c@1.0.0', getPackagePath(config, 'c')); + + expect(result).toContainPackage('a@1.0.0', getPackagePath(config, 'w1/a')); + }); + test('from workspace', () => { + // w2 disable 'a' hoisting + const {packageHoister, packageResolver} = fixture( + updateWorkspaces('root@1.0.0', undefined, ['w1@1.0.0', 'w2@1.0.0']), + ); + const config = packageHoister.config; + + const pkg: any = packageResolver.getStrictResolvedPattern('w2@1.0.0'); + pkg.workspaces = {nohoist: ['a']}; + + packageHoister.seed(['root@1.0.0']); + const result = packageHoister.init(); + + expect(result.length).toEqual(7); + expect(result).toContainPackage('root@1.0.0', getPackagePath(config, 'root')); + expect(result).toContainPackage('w1@1.0.0', getPackagePath(config, 'w1')); + expect(result).toContainPackage('w2@1.0.0', getPackagePath(config, 'w2')); + expect(result).toContainPackage('a@1.0.0', getPackagePath(config, 'a')); + expect(result).toContainPackage('b@1.0.0', getPackagePath(config, 'b')); + expect(result).toContainPackage('c@1.0.0', getPackagePath(config, 'c')); + + expect(result).toContainPackage('a@1.0.0', getPackagePath(config, 'w2/a')); + }); + }); + describe('workspace depends on another workspace', () => { + function fixture(f: UpdateResolver): any { + return createTestFixture( + { + 'w1@1.0.0': ['a@1.0.0'], + 'w2@1.0.0': ['w1@1.0.0', 'b@1.0.0'], + 'a@1.0.0': ['c@1.0.0'], + 'b@1.0.0': ['c@1.0.0'], + 'c@1.0.0': [], + 'root@1.0.0': ['w1@1.0.0', 'w2@1.0.0'], + }, + true, + f, + ); + } + test('can nohoist dependent workspace just like any package', () => { + const {packageHoister, packageResolver} = fixture( + updateWorkspaces('root@1.0.0', undefined, ['w1@1.0.0', 'w2@1.0.0']), + ); + const config = packageHoister.config; + + // w2 disable 'w1' and all of w1's direct dependency hoisting + const pkg: any = packageResolver.getStrictResolvedPattern('w2@1.0.0'); + pkg.workspaces = {nohoist: ['w1', 'w1/**']}; + + packageHoister.seed(['root@1.0.0']); + const result = packageHoister.init(); + + expect(result.length).toEqual(9); + expect(result).toContainPackage('root@1.0.0', getPackagePath(config, 'root')); + expect(result).toContainPackage('w1@1.0.0', getPackagePath(config, 'w1')); + expect(result).toContainPackage('w2@1.0.0', getPackagePath(config, 'w2')); + expect(result).toContainPackage('a@1.0.0', getPackagePath(config, 'a')); + expect(result).toContainPackage('b@1.0.0', getPackagePath(config, 'b')); + expect(result).toContainPackage('c@1.0.0', getPackagePath(config, 'c')); + + expect(result).toContainPackage('w1@1.0.0', getPackagePath(config, 'w2/w1')); + expect(result).toContainPackage('a@1.0.0', getPackagePath(config, 'w2/a')); + expect(result).toContainPackage('c@1.0.0', getPackagePath(config, 'w2/c')); + }); + test('all workspaces nohoist will be honored', () => { + const {packageHoister, packageResolver} = fixture( + updateWorkspaces('root@1.0.0', undefined, ['w1@1.0.0', 'w2@1.0.0']), + ); + const config = packageHoister.config; + + // w2 disable all of its top level packages hoisting + let pkg: any = packageResolver.getStrictResolvedPattern('w2@1.0.0'); + pkg.workspaces = {nohoist: ['*']}; + + // w1 disable 'a' and all of its dependency hoisting + pkg = packageResolver.getStrictResolvedPattern('w1@1.0.0'); + pkg.workspaces = {nohoist: ['a', 'a/**']}; + + packageHoister.seed(['root@1.0.0']); + const result = packageHoister.init(); + + expect(result.length).toEqual(10); + // root + expect(result).toContainPackage('root@1.0.0', getPackagePath(config, 'root')); + expect(result).toContainPackage('w1@1.0.0', getPackagePath(config, 'w1')); + expect(result).toContainPackage('w2@1.0.0', getPackagePath(config, 'w2')); + // from w2/b/c + expect(result).toContainPackage('c@1.0.0', getPackagePath(config, 'c')); + + // under w1 + expect(result).toContainPackage('a@1.0.0', getPackagePath(config, 'w1/a')); + expect(result).toContainPackage('c@1.0.0', getPackagePath(config, 'w1/c')); + + // under w2 + expect(result).toContainPackage('w1@1.0.0', getPackagePath(config, 'w2/w1')); + expect(result).toContainPackage('a@1.0.0', getPackagePath(config, 'w2/a')); + expect(result).toContainPackage('b@1.0.0', getPackagePath(config, 'w2/b')); + expect(result).toContainPackage('c@1.0.0', getPackagePath(config, 'w2/c')); + }); + }); + }); + test('originalParentPath shows before-hoist dependency tree path', () => { + const {packageHoister} = createTestFixture({ + 'a@1.0.0': ['c@1.0.0'], + 'b@1.0.0': ['c@1.0.0'], + 'c@1.0.0': [], + }); + + // disable hoisting for everything under a + packageHoister.seed(['a@1.0.0', 'b@1.0.0']); + const result = packageHoister.init(); + const paths = result.map(r => [r[1].key, r[1].originalParentPath]); + + expect(paths.length).toEqual(3); + expect(paths).toContainEqual(['a', '']); + expect(paths).toContainEqual(['b', '']); + expect(paths).toContainEqual(['c', '/a']); + }); + test('previousPaths should reflect hoist history', () => { + const {packageHoister} = createTestFixture({ + 'a@1.0.0': ['c@1.0.0'], + 'b@1.0.0': ['c@1.0.0'], + 'c@1.0.0': [], + }); + + // disable hoisting for everything under a + packageHoister.seed(['a@1.0.0', 'b@1.0.0']); + const result = packageHoister.init(); + const hoistHistory = result.map(r => [r[1].key, r[1].previousPaths]); + + expect(hoistHistory.length).toEqual(3); + expect(hoistHistory).toContainEqual(['a', []]); + expect(hoistHistory).toContainEqual(['b', []]); + expect(hoistHistory).toContainEqual(['c', ['/a/c', '/b/c']]); + }); +}); diff --git a/__tests__/package-resolver.js b/__tests__/package-resolver.js index 5e8f2b9100..68136a5117 100644 --- a/__tests__/package-resolver.js +++ b/__tests__/package-resolver.js @@ -9,7 +9,7 @@ import makeTemp from './_temp.js'; import * as fs from '../src/util/fs.js'; import * as constants from '../src/constants.js'; -jasmine.DEFAULT_TIMEOUT_INTERVAL = 60000; +jasmine.DEFAULT_TIMEOUT_INTERVAL = 90000; const path = require('path'); @@ -51,10 +51,9 @@ function addTest(pattern, registry = 'npm', init: ?(cacheFolder: string) => Prom }); } -// TODO Got broken for some time, needs revision -// addTest('https://github.com/npm-ml/re'); // git url with no .git -// addTest('git+https://github.com/npm-ml/ocaml.git#npm-4.02.3'); // git+hash -// addTest('https://github.com/npm-ml/ocaml.git#npm-4.02.3'); // hash +addTest('https://github.com/ocaml/ocaml-re'); // git url with no .git +addTest('git+https://github.com/ocaml/ocaml.git#4.02.3'); // git+hash +addTest('https://github.com/ocaml/ocaml.git#4.02.3'); // hash addTest('https://git@github.com/stevemao/left-pad.git'); // git url, with username addTest('https://bitbucket.org/hgarcia/node-bitbucket-api.git'); // hosted git url addTest('https://github.com/yarnpkg/yarn/releases/download/v0.18.1/yarn-v0.18.1.tar.gz'); // tarball diff --git a/__tests__/registries/npm-registry.js b/__tests__/registries/npm-registry.js index 6fa85aac66..ce0f97e464 100644 --- a/__tests__/registries/npm-registry.js +++ b/__tests__/registries/npm-registry.js @@ -72,138 +72,504 @@ function createMocks(): Object { } describe('request', () => { - test('should call requestManager.request with url', () => { + // a helper function for creating an instance of npm registry, + // making requests and inspecting request parameters + function createRegistry(config: Object): Object { const testCwd = '.'; const {mockRequestManager, mockRegistries, mockReporter} = createMocks(); const npmRegistry = new NpmRegistry(testCwd, mockRegistries, mockRequestManager, mockReporter); + npmRegistry.config = config; + return { + request(url: string, options: Object, packageName: string): Object { + npmRegistry.request(url, options, packageName); + const lastIndex = mockRequestManager.request.mock.calls.length - 1; + const requestParams = mockRequestManager.request.mock.calls[lastIndex][0]; + return requestParams; + }, + }; + } + test('should call requestManager.request with url', () => { const url = 'https://github.com/yarnpkg/yarn.tgz'; - - npmRegistry.request(url); - - const requestParams = mockRequestManager.request.mock.calls[0][0]; - + const config = {}; + const requestParams = createRegistry(config).request(url); expect(requestParams.url).toBe(url); }); - test('should not add authorization header if pathname not to registry', () => { - const testCwd = '.'; - const {mockRequestManager, mockRegistries, mockReporter} = createMocks(); - const npmRegistry = new NpmRegistry(testCwd, mockRegistries, mockRequestManager, mockReporter); - - const url = 'https://github.com/yarnpkg/yarn.tgz'; - - npmRegistry.request(url); - - const requestParams = mockRequestManager.request.mock.calls[0][0]; - - expect(requestParams.headers.authorization).toBeUndefined(); - }); - - test('should not add authorization header if pathname not to registry and always-auth is true', () => { - const testCwd = '.'; - const {mockRequestManager, mockRegistries, mockReporter} = createMocks(); - const npmRegistry = new NpmRegistry(testCwd, mockRegistries, mockRequestManager, mockReporter); - - const url = 'https://github.com/yarnpkg/yarn.tgz'; - - npmRegistry.config = { - 'always-auth': true, - _authToken: 'testAuthToken', - }; - npmRegistry.request(url); - - const requestParams = mockRequestManager.request.mock.calls[0][0]; - - expect(requestParams.headers.authorization).toBeUndefined(); - }); - - test('should not add authorization header if pathname is to registry and always-auth is false', () => { - const testCwd = '.'; - const {mockRequestManager, mockRegistries, mockReporter} = createMocks(); - const npmRegistry = new NpmRegistry(testCwd, mockRegistries, mockRequestManager, mockReporter); - - const url = 'https://registry.npmjs.org/yarnpkg/yarn.tgz'; - - npmRegistry.config = { - // Default is: 'always-auth': false, - _authToken: 'testAuthToken', - }; - npmRegistry.request(url); - - const requestParams = mockRequestManager.request.mock.calls[0][0]; - - expect(requestParams.headers.authorization).toBeUndefined(); - }); - - test('should not add authorization header if pathname is to registry and not scopped package', () => { - const testCwd = '.'; - const {mockRequestManager, mockRegistries, mockReporter} = createMocks(); - const npmRegistry = new NpmRegistry(testCwd, mockRegistries, mockRequestManager, mockReporter); - - const url = 'https://registry.npmjs.org/yarnpkg/yarn.tgz'; - - npmRegistry.config = { - _authToken: 'testAuthToken', - }; - npmRegistry.request(url); - - const requestParams = mockRequestManager.request.mock.calls[0][0]; - - expect(requestParams.headers.authorization).toBeUndefined(); - }); - - test('should add authorization header if pathname is to registry and always-auth is true', () => { - const testCwd = '.'; - const {mockRequestManager, mockRegistries, mockReporter} = createMocks(); - const npmRegistry = new NpmRegistry(testCwd, mockRegistries, mockRequestManager, mockReporter); - - const url = 'https://registry.npmjs.org/yarnpkg/yarn.tgz'; - - npmRegistry.config = { - 'always-auth': true, - _authToken: 'testAuthToken', - }; - npmRegistry.request(url); - - const requestParams = mockRequestManager.request.mock.calls[0][0]; - - expect(requestParams.headers.authorization).toBe('Bearer testAuthToken'); - }); - - test('should add authorization header if pathname is to registry and is scopped package', () => { - const testCwd = '.'; - const {mockRequestManager, mockRegistries, mockReporter} = createMocks(); - const npmRegistry = new NpmRegistry(testCwd, mockRegistries, mockRequestManager, mockReporter); - - const url = 'https://registry.npmjs.org/@testScope%2fyarn.tgz'; - - npmRegistry.config = { - _authToken: 'testAuthToken', - }; - npmRegistry.request(url); - - const requestParams = mockRequestManager.request.mock.calls[0][0]; - - expect(requestParams.headers.authorization).toBe('Bearer testAuthToken'); - }); - - test('should add authorization header with token for custom registries with a scoped package', () => { - const testCwd = '.'; - const {mockRequestManager, mockRegistries, mockReporter} = createMocks(); - const npmRegistry = new NpmRegistry(testCwd, mockRegistries, mockRequestManager, mockReporter); - - const url = 'https://some.other.registry/@testScope%2fyarn.tgz'; - - npmRegistry.config = { - '//some.other.registry/:_authToken': 'testScopedAuthToken', - '@testScope:registry': '//some.other.registry/', - }; - npmRegistry.request(url); - - const requestParams = mockRequestManager.request.mock.calls[0][0]; - - expect(requestParams.headers.authorization).toBe('Bearer testScopedAuthToken'); + const testCases = [ + { + title: 'using npm as default registry and using private registry for scoped packages', + config: { + '//registry.myorg.com/:_authToken': 'scopedPrivateAuthToken', + '@private:registry': 'https://registry.myorg.com/', + }, + requests: [ + { + url: 'yarn', + pkg: 'yarn', + expect: {root: 'https://registry.npmjs.org', auth: false}, + }, + { + url: '@yarn%2fcore', + pkg: '@yarn/core', + expect: {root: 'https://registry.npmjs.org', auth: false}, + }, + { + url: '-/package/yarn/dist-tags', + pkg: 'yarn', + expect: {root: 'https://registry.npmjs.org', auth: false}, + }, + { + url: '-/package/@yarn%2fcore/dist-tags', + pkg: '@yarn/core', + expect: {root: 'https://registry.npmjs.org', auth: false}, + }, + { + url: '-/user/token/abcdef', + pkg: null, + expect: {root: 'https://registry.npmjs.org', auth: false}, + }, + { + url: 'https://registry.npmjs.org/dist/-/@yarn-core-1.0.0.tgz', + pkg: '@yarn/core', + expect: {root: 'https://registry.npmjs.org', auth: false}, + }, + { + url: 'https://registry.yarnpkg.com/dist/-/@yarn-core-1.0.0.tgz', + pkg: '@yarn/core', + expect: {root: 'https://registry.yarnpkg.com', auth: false}, + }, + { + url: 'https://registry.yarnpkg.com/dist/-/@yarn-core-1.0.0.tgz', + pkg: null, + expect: {root: 'https://registry.yarnpkg.com', auth: false}, + }, + { + url: 'https://some.cdn.com/@yarn/core.tgz', + pkg: '@yarn/core', + expect: {root: 'https://some.cdn.com', auth: false}, + }, + { + url: 'https://some.cdn.com/@yarn/core.tgz', + pkg: null, + expect: {root: 'https://some.cdn.com', auth: false}, + }, + { + url: '@private/pkg', + pkg: '@private/pkg', + expect: {root: 'https://registry.myorg.com', auth: 'scopedPrivateAuthToken'}, + }, + { + url: 'https://some.cdn.com/some-hash/@private-pkg-1.0.0.tar.gz', + pkg: '@private/pkg', + expect: {root: 'https://some.cdn.com', auth: false}, + }, + { + url: 'https://some.cdn.com/@private/pkg', + pkg: null, + expect: {root: 'https://some.cdn.com', auth: false}, + }, + ], + }, + { + title: 'using scoped packages in both npm and private registry', + config: { + '//registry.npmjs.org/:_authToken': 'scopedNpmAuthToken', + '@yarn:registry': 'https://registry.npmjs.org/', + '//registry.myorg.com/:_authToken': 'scopedPrivateAuthToken', + '@private:registry': 'https://registry.myorg.com/', + }, + requests: [ + { + url: 'yarn', + pkg: 'yarn', + expect: {root: 'https://registry.npmjs.org', auth: false}, + }, + { + url: '@yarn%2fcore', + pkg: '@yarn/core', + expect: {root: 'https://registry.npmjs.org', auth: 'scopedNpmAuthToken'}, + }, + { + url: '-/package/yarn/dist-tags', + pkg: 'yarn', + expect: {root: 'https://registry.npmjs.org', auth: false}, + }, + { + url: '-/package/@yarn%2fcore/dist-tags', + pkg: '@yarn/core', + expect: {root: 'https://registry.npmjs.org', auth: 'scopedNpmAuthToken'}, + }, + { + url: '-/user/token/abcdef', + pkg: null, + expect: {root: 'https://registry.npmjs.org', auth: false}, + }, + { + url: 'https://registry.npmjs.org/dist/-/@yarn-core-1.0.0.tgz', + pkg: '@yarn/core', + expect: {root: 'https://registry.npmjs.org', auth: 'scopedNpmAuthToken'}, + }, + { + url: 'https://registry.yarnpkg.com/dist/-/@yarn-core-1.0.0.tgz', + pkg: '@yarn/core', + expect: {root: 'https://registry.yarnpkg.com', auth: 'scopedNpmAuthToken'}, + }, + { + url: 'https://registry.yarnpkg.com/dist/-/@yarn-core-1.0.0.tgz', + pkg: null, + expect: {root: 'https://registry.yarnpkg.com', auth: false}, + }, + { + url: 'https://some.cdn.com/@yarn/core.tgz', + pkg: '@yarn/core', + expect: {root: 'https://some.cdn.com', auth: false}, + }, + { + url: 'https://some.cdn.com/@yarn/core.tgz', + pkg: null, + expect: {root: 'https://some.cdn.com', auth: false}, + }, + { + url: '@private/pkg', + pkg: '@private/pkg', + expect: {root: 'https://registry.myorg.com', auth: 'scopedPrivateAuthToken'}, + }, + { + url: 'https://some.cdn.com/some-hash/@private-pkg-1.0.0.tar.gz', + pkg: '@private/pkg', + expect: {root: 'https://some.cdn.com', auth: false}, + }, + { + url: 'https://some.cdn.com/@private/pkg', + pkg: null, + expect: {root: 'https://some.cdn.com', auth: false}, + }, + ], + }, + { + title: 'using authenticated npm and using private registry for scoped packages', + config: { + _authToken: 'scopedNpmAuthToken', + '//registry.myorg.com/:_authToken': 'scopedPrivateAuthToken', + '@private:registry': 'https://registry.myorg.com/', + }, + requests: [ + { + url: 'yarn', + pkg: 'yarn', + expect: {root: 'https://registry.npmjs.org', auth: false}, + }, + { + url: '@yarn%2fcore', + pkg: '@yarn/core', + expect: {root: 'https://registry.npmjs.org', auth: 'scopedNpmAuthToken'}, + }, + { + url: '-/package/yarn/dist-tags', + pkg: 'yarn', + expect: {root: 'https://registry.npmjs.org', auth: false}, + }, + { + url: '-/package/@yarn%2fcore/dist-tags', + pkg: '@yarn/core', + expect: {root: 'https://registry.npmjs.org', auth: 'scopedNpmAuthToken'}, + }, + { + url: '-/user/token/abcdef', + pkg: null, + expect: {root: 'https://registry.npmjs.org', auth: false}, + }, + { + url: 'https://registry.npmjs.org/dist/-/@yarn-core-1.0.0.tgz', + pkg: '@yarn/core', + expect: {root: 'https://registry.npmjs.org', auth: 'scopedNpmAuthToken'}, + }, + { + url: 'https://registry.yarnpkg.com/dist/-/@yarn-core-1.0.0.tgz', + pkg: '@yarn/core', + expect: {root: 'https://registry.yarnpkg.com', auth: 'scopedNpmAuthToken'}, + }, + { + url: 'https://registry.yarnpkg.com/dist/-/@yarn-core-1.0.0.tgz', + pkg: null, + expect: {root: 'https://registry.yarnpkg.com', auth: false}, + }, + { + url: 'https://some.cdn.com/@yarn/core.tgz', + pkg: '@yarn/core', + expect: {root: 'https://some.cdn.com', auth: false}, + }, + { + url: 'https://some.cdn.com/@yarn/core.tgz', + pkg: null, + expect: {root: 'https://some.cdn.com', auth: false}, + }, + { + url: '@private/pkg', + pkg: '@private/pkg', + expect: {root: 'https://registry.myorg.com', auth: 'scopedPrivateAuthToken'}, + }, + { + url: 'https://some.cdn.com/some-hash/@private-pkg-1.0.0.tar.gz', + pkg: '@private/pkg', + expect: {root: 'https://some.cdn.com', auth: false}, + }, + { + url: 'https://some.cdn.com/@private/pkg', + pkg: null, + expect: {root: 'https://some.cdn.com', auth: false}, + }, + ], + }, + { + title: 'using npm with always-auth and using private registry for scoped packages', + config: { + 'always-auth': true, + '//registry.npmjs.org/:_authToken': 'npmAuthToken', + '@private:registry': 'https://registry.myorg.com/', + '//registry.myorg.com/:_authToken': 'scopedPrivateAuthToken', + }, + requests: [ + { + url: 'yarn', + pkg: 'yarn', + expect: {root: 'https://registry.npmjs.org', auth: 'npmAuthToken'}, + }, + { + url: '@yarn%2fcore', + pkg: '@yarn/core', + expect: {root: 'https://registry.npmjs.org', auth: 'npmAuthToken'}, + }, + { + url: '-/package/yarn/dist-tags', + pkg: 'yarn', + expect: {root: 'https://registry.npmjs.org', auth: 'npmAuthToken'}, + }, + { + url: '-/package/@yarn%2fcore/dist-tags', + pkg: '@yarn/core', + expect: {root: 'https://registry.npmjs.org', auth: 'npmAuthToken'}, + }, + { + url: '-/user/token/abcdef', + pkg: null, + expect: {root: 'https://registry.npmjs.org', auth: 'npmAuthToken'}, + }, + { + url: 'https://registry.npmjs.org/dist/-/@yarn-core-1.0.0.tgz', + pkg: '@yarn/core', + expect: {root: 'https://registry.npmjs.org', auth: 'npmAuthToken'}, + }, + { + url: 'https://registry.yarnpkg.com/dist/-/@yarn-core-1.0.0.tgz', + pkg: '@yarn/core', + expect: {root: 'https://registry.yarnpkg.com', auth: 'npmAuthToken'}, + }, + { + url: 'https://registry.yarnpkg.com/dist/-/@yarn-core-1.0.0.tgz', + pkg: null, + expect: {root: 'https://registry.yarnpkg.com', auth: 'npmAuthToken'}, + }, + { + url: 'https://some.cdn.com/@yarn/core.tgz', + pkg: '@yarn/core', + expect: {root: 'https://some.cdn.com', auth: false}, + }, + { + url: 'https://some.cdn.com/@yarn/core.tgz', + pkg: null, + expect: {root: 'https://some.cdn.com', auth: false}, + }, + { + url: '@private/pkg', + pkg: '@private/pkg', + expect: {root: 'https://registry.myorg.com', auth: 'scopedPrivateAuthToken'}, + }, + { + url: 'https://some.cdn.com/some-hash/@private-pkg-1.0.0.tar.gz', + pkg: '@private/pkg', + expect: {root: 'https://some.cdn.com', auth: false}, + }, + { + url: 'https://some.cdn.com/@private/pkg', + pkg: null, + expect: {root: 'https://some.cdn.com', auth: false}, + }, + ], + }, + { + title: 'using private registry as default registry and using scoped packages on npm registry', + config: { + 'always-auth': true, + registry: 'https://registry.myorg.com/', + '//registry.myorg.com/:_authToken': 'privateAuthToken', + '//registry.npmjs.org/:_authToken': 'scopedNpmAuthToken', + '@yarn:registry': 'https://registry.npmjs.org/', + }, + requests: [ + { + url: 'yarn', + pkg: 'yarn', + expect: {root: 'https://registry.myorg.com', auth: 'privateAuthToken'}, + }, + { + url: '@yarn%2fcore', + pkg: '@yarn/core', + expect: {root: 'https://registry.npmjs.org', auth: 'scopedNpmAuthToken'}, + }, + { + url: '-/package/yarn/dist-tags', + pkg: 'yarn', + expect: {root: 'https://registry.myorg.com', auth: 'privateAuthToken'}, + }, + { + url: '-/package/@yarn%2fcore/dist-tags', + pkg: '@yarn/core', + expect: {root: 'https://registry.npmjs.org', auth: 'scopedNpmAuthToken'}, + }, + { + url: '-/user/token/abcdef', + pkg: null, + expect: {root: 'https://registry.myorg.com', auth: 'privateAuthToken'}, + }, + { + url: 'https://registry.npmjs.org/dist/-/@yarn-core-1.0.0.tgz', + pkg: '@yarn/core', + expect: {root: 'https://registry.npmjs.org', auth: 'scopedNpmAuthToken'}, + }, + { + url: 'https://registry.yarnpkg.com/dist/-/@yarn-core-1.0.0.tgz', + pkg: '@yarn/core', + expect: {root: 'https://registry.yarnpkg.com', auth: 'scopedNpmAuthToken'}, + }, + { + url: 'https://registry.yarnpkg.com/dist/-/@yarn-core-1.0.0.tgz', + pkg: null, + expect: {root: 'https://registry.yarnpkg.com', auth: false}, + }, + { + url: 'https://some.cdn.com/@yarn/core.tgz', + pkg: '@yarn/core', + expect: {root: 'https://some.cdn.com', auth: false}, + }, + { + url: 'https://some.cdn.com/@yarn/core.tgz', + pkg: null, + expect: {root: 'https://some.cdn.com', auth: false}, + }, + { + url: '@private/pkg', + pkg: '@private/pkg', + expect: {root: 'https://registry.myorg.com', auth: 'privateAuthToken'}, + }, + { + url: 'https://some.cdn.com/some-hash/@private-pkg-1.0.0.tar.gz', + pkg: '@private/pkg', + expect: {root: 'https://some.cdn.com', auth: false}, + }, + { + url: 'https://some.cdn.com/@private/pkg', + pkg: null, + expect: {root: 'https://some.cdn.com', auth: false}, + }, + ], + }, + { + title: 'registry url and request url path sensitivity', + config: { + '@private:registry': 'https://registry.myorg.com/api/npm/registry/', + '//registry.myorg.com/api/npm/registry/:_authToken': 'scopedPrivateAuthToken', + }, + requests: [ + { + url: 'https://registry.myorg.com/api/npm/registry/private---pkg.tar.gz', + pkg: '@private/pkg', + expect: {root: 'https://registry.myorg.com/api/npm/registry/', auth: 'scopedPrivateAuthToken'}, + }, + { + url: 'https://registry.myorg.com/api/packages/private---pkg.tar.gz', + pkg: '@private/pkg', + expect: {root: 'https://registry.myorg.com/api/packages/', auth: false}, + }, + ], + }, + { + title: 'using custom-host-suffix for registries where pathnames play a role', + config: { + '@private:registry': 'https://registry.myorg.com/api/npm/registry/', + '//registry.myorg.com/api/npm/registry/:_authToken': 'scopedPrivateAuthToken', + 'custom-host-suffix': 'registry.myorg.com', + }, + requests: [ + { + url: '@private/pkg', + pkg: '@private/pkg', + expect: {root: 'https://registry.myorg.com/api/npm/registry/', auth: 'scopedPrivateAuthToken'}, + }, + { + url: 'https://some.cdn.com/some-hash/@private-pkg-1.0.0.tar.gz', + pkg: '@private/pkg', + expect: {root: 'https://some.cdn.com', auth: false}, + }, + { + url: 'https://some.cdn.com/@private/pkg', + pkg: null, + expect: {root: 'https://some.cdn.com', auth: false}, + }, + { + url: 'https://registry.myorg.com/api/packages/private---pkg.tar.gz', + pkg: '@private/pkg', + expect: {root: 'https://registry.myorg.com/api/packages/', auth: 'scopedPrivateAuthToken'}, + }, + ], + }, + { + title: 'using multiple config entries for registries where pathnames play a role', + config: { + '@private:registry': 'https://registry.myorg.com/api/npm/registry/', + '//registry.myorg.com/api/npm/registry/:_authToken': 'scopedPrivateAuthToken', + '//registry.myorg.com/api/packages/:_authToken': 'scopedPrivateAuthToken', + }, + requests: [ + { + url: '@private/pkg', + pkg: '@private/pkg', + expect: {root: 'https://registry.myorg.com/api/npm/registry/', auth: 'scopedPrivateAuthToken'}, + }, + { + url: 'https://some.cdn.com/some-hash/@private-pkg-1.0.0.tar.gz', + pkg: '@private/pkg', + expect: {root: 'https://some.cdn.com', auth: false}, + }, + { + url: 'https://some.cdn.com/@private/pkg', + pkg: null, + expect: {root: 'https://some.cdn.com', auth: false}, + }, + { + url: 'https://registry.myorg.com/api/packages/private---pkg.tar.gz', + pkg: '@private/pkg', + expect: {root: 'https://registry.myorg.com/api/packages/', auth: 'scopedPrivateAuthToken'}, + }, + ], + }, + ]; + + testCases.forEach(testCase => { + describe(testCase.title, () => { + const registry = createRegistry(testCase.config); + testCase.requests.forEach(req => { + const desc = + `with request url ${req.url}${req.pkg ? ` in context of package ${req.pkg}` : ''} ` + + `auth is ${req.expect.auth ? req.expect.auth : 'not sent'}`; + (req.skip ? it.skip : req.only ? it.only : it)(desc, () => { + const requestParams = registry.request(req.url, {}, req.pkg); + expect(requestParams.url.substr(0, req.expect.root.length)).toBe(req.expect.root); + expect(requestParams.headers.authorization).toBe(req.expect.auth ? `Bearer ${req.expect.auth}` : undefined); + }); + }); + }); }); }); @@ -222,6 +588,9 @@ describe('isRequestToRegistry functional test', () => { ['http://foo.bar/foo/bar/baz', 'https://foo.bar:443/foo/'], ['https://foo.bar/foo/bar/baz', 'https://foo.bar:443/foo/'], ['HTTP://xn--xample-hva.com:80/foo/bar/baz', 'http://êxample.com/foo/bar/baz'], + // yarn and npm registries are interchangeable + ['https://registry.npmjs.org/foo/bar', 'https://registry.npmjs.org/'], + ['https://registry.yarnpkg.com/foo/bar', 'https://registry.npmjs.org/'], ]; const invalidRegistryUrls = [ diff --git a/__tests__/resolvers/exotics/hosted-git-resolver.js b/__tests__/resolvers/exotics/hosted-git-resolver.js index 74b57e1117..cbd225394c 100644 --- a/__tests__/resolvers/exotics/hosted-git-resolver.js +++ b/__tests__/resolvers/exotics/hosted-git-resolver.js @@ -42,3 +42,15 @@ test('explodeHostedGitFragment should work identical with and without .git suffi expect(explodeHostedGitFragment(fragmentWithoutGit, reporter)).toEqual(expectedFragment); expect(explodeHostedGitFragment(fragmentWithGit, reporter)).toEqual(expectedFragment); }); + +test('explodeHostedGitFragment should allow the project name to contain .git', () => { + const fragmentString = 'jure/lens.github'; + + const expectedFragment: ExplodedFragment = { + user: 'jure', + repo: 'lens.github', + hash: '', + }; + + expect(explodeHostedGitFragment(fragmentString, reporter)).toEqual(expectedFragment); +}); diff --git a/__tests__/resolvers/exotics/registry-resolver.js b/__tests__/resolvers/exotics/registry-resolver.js new file mode 100644 index 0000000000..ab8d802594 --- /dev/null +++ b/__tests__/resolvers/exotics/registry-resolver.js @@ -0,0 +1,30 @@ +/* @flow */ + +import PackageRequest from '../../../src/package-request.js'; +import RegistryResolver from '../../../src/resolvers/exotics/registry-resolver.js'; + +const mockPackageRequest: PackageRequest = ({}: any); + +test('resolves unscoped npm: package', () => { + const resolver = new RegistryResolver(mockPackageRequest, 'npm:foo@0.0.1'); + + expect(resolver.name).toEqual('foo'); +}); + +test('resolves scoped npm: package', () => { + const resolver = new RegistryResolver(mockPackageRequest, 'npm:@org/foo@0.0.1'); + + expect(resolver.name).toEqual('@org/foo'); +}); + +test('resolves unscoped yarn: package', () => { + const resolver = new RegistryResolver(mockPackageRequest, 'yarn:foo@0.0.1'); + + expect(resolver.name).toEqual('foo'); +}); + +test('resolves scoped yarn: package', () => { + const resolver = new RegistryResolver(mockPackageRequest, 'yarn:@org/foo@0.0.1'); + + expect(resolver.name).toEqual('@org/foo'); +}); diff --git a/__tests__/util/git/git-ref-resolver.js b/__tests__/util/git/git-ref-resolver.js index de6fc4e74e..01d540a25c 100644 --- a/__tests__/util/git/git-ref-resolver.js +++ b/__tests__/util/git/git-ref-resolver.js @@ -22,6 +22,7 @@ test('resolveVersion', async () => { const refs: GitRefs = new Map(); refs.set('refs/heads/1.1', 'eaa56cb34863810060abbec2d755ba51508afedc'); refs.set('refs/heads/3.3', '4cff93aa6e8270c3bec988af464d28a164bc3cb2'); + refs.set('refs/heads/v3.3.0', '06910374874035a3388c42a6f6403b2b785e9993'); refs.set('refs/heads/main', '8a41a314e23dc566a6b7e73c757a10d13e3320cf'); refs.set('refs/heads/both', '106c28537be070b98ca1effaef6a2bf6414e1e49'); refs.set('refs/tags/v1.1.0', '37d5ed001dc4402d5446911c4e1cb589449e7d8d'); @@ -110,6 +111,22 @@ test('resolveVersion', async () => { sha: '8a41a314e23dc566a6b7e73c757a10d13e3320cf', ref: 'refs/heads/main', }); + expect(await resolve('^1.0')).toEqual({ + sha: '37d5ed001dc4402d5446911c4e1cb589449e7d8d', + ref: 'refs/tags/v1.1.0', + }); + expect(await resolve('semver:^1.0')).toEqual({ + sha: '37d5ed001dc4402d5446911c4e1cb589449e7d8d', + ref: 'refs/tags/v1.1.0', + }); + expect(await resolve('^3.0')).toEqual({ + sha: '06910374874035a3388c42a6f6403b2b785e9993', + ref: 'refs/heads/v3.3.0', + }); + expect(await resolve('semver:^3.0')).toEqual({ + sha: '06910374874035a3388c42a6f6403b2b785e9993', + ref: 'refs/heads/v3.3.0', + }); }); test('isCommitSha', () => { diff --git a/__tests__/util/guess-name.js b/__tests__/util/guess-name.js index a9115480a1..f7fc41be6d 100644 --- a/__tests__/util/guess-name.js +++ b/__tests__/util/guess-name.js @@ -24,6 +24,13 @@ const examples = [ 'awesome-name.tar.gz', ]; +const dotExamples = [ + 'awesomename/awesome.name', + 'awesomename/awesome.name.git', + 'awesomename/awesome.name.tar.gz', + 'awesomename/awesome.name.tar.bz2', +]; + describe('guessName', () => { for (const source of examples) { it(`guess name of ${source}`, () => { @@ -31,3 +38,11 @@ describe('guessName', () => { }); } }); + +describe('guessName dot examples', () => { + for (const source of dotExamples) { + it(`guess name of ${source}`, () => { + expect(guessName(source)).toBe('awesome.name'); + }); + } +}); diff --git a/bin/yarn.js b/bin/yarn.js index 0ff0839bf9..e46b1f6002 100755 --- a/bin/yarn.js +++ b/bin/yarn.js @@ -9,7 +9,7 @@ var majorVer = parseInt(ver.split('.')[0], 10); if (majorVer < 4) { console.error('Node version ' + ver + ' is not supported, please use Node.js 4.0 or higher.'); - process.exitCode = 1; + process.exit(1); // eslint-disable-line no-process-exit } else { var dirPath = '../lib/'; var v8CompileCachePath = dirPath + 'v8-compile-cache'; diff --git a/package.json b/package.json index 6ae2454032..5f23a7086d 100644 --- a/package.json +++ b/package.json @@ -1,12 +1,11 @@ { "name": "yarn", "installationMethod": "unknown", - "version": "1.3.2", + "version": "1.4.1", "license": "BSD-2-Clause", "preferGlobal": true, "description": "📦🐈 Fast, reliable, and secure dependency management.", "dependencies": { - "babel-eslint": "^7.2.3", "babel-runtime": "^6.26.0", "bytes": "^2.4.0", "camelcase": "^4.0.0", @@ -17,15 +16,12 @@ "debug": "^2.2.0", "detect-indent": "^5.0.0", "dnscache": "^1.0.1", - "eslint-plugin-jest": "^20.0.3", - "eslint-plugin-jsx-a11y": "^6.0.2", - "eslint-plugin-relay": "0.0.8", "glob": "^7.1.1", "gunzip-maybe": "^1.4.0", "ini": "^1.3.4", "inquirer": "^3.0.1", "invariant": "^2.2.0", - "is-builtin-module": "^1.0.0", + "is-builtin-module": "^2.0.0", "is-ci": "^1.0.10", "is-webpack-bundle": "^1.0.0", "leven": "^2.0.0", @@ -53,6 +49,7 @@ }, "devDependencies": { "babel-core": "^6.26.0", + "babel-eslint": "^7.2.3", "babel-loader": "^6.2.5", "babel-plugin-array-includes": "^2.0.3", "babel-plugin-transform-inline-imports-commonjs": "^1.0.0", @@ -68,9 +65,12 @@ "eslint-plugin-babel": "^4.0.0", "eslint-plugin-flowtype": "^2.35.0", "eslint-plugin-jasmine": "^2.6.2", + "eslint-plugin-jest": "^20.0.3", + "eslint-plugin-jsx-a11y": "^6.0.2", "eslint-plugin-prefer-object-spread": "^1.2.1", "eslint-plugin-prettier": "^2.1.2", "eslint-plugin-react": "^7.1.0", + "eslint-plugin-relay": "^0.0.8", "eslint-plugin-yarn-internal": "file:scripts/eslint-rules", "execa": "^0.7.0", "flow-bin": "^0.52.0", @@ -82,7 +82,7 @@ "gulp-sourcemaps": "^2.2.0", "gulp-util": "^3.0.7", "gulp-watch": "^4.3.5", - "jest": "21.2.1", + "jest": "^21.2.1", "jsinspect": "^0.12.6", "minimatch": "^3.0.4", "mock-stdin": "^0.3.0", diff --git a/renovate.json b/renovate.json new file mode 100644 index 0000000000..5fcce11213 --- /dev/null +++ b/renovate.json @@ -0,0 +1,6 @@ +{ + "extends": [ + "config:base", + ":preserveSemverRanges" + ] +} diff --git a/src/cli/commands/add.js b/src/cli/commands/add.js index f511d8e13b..617c676397 100644 --- a/src/cli/commands/add.js +++ b/src/cli/commands/add.js @@ -21,7 +21,9 @@ import semver from 'semver'; export class Add extends Install { constructor(args: Array, flags: Object, config: Config, reporter: Reporter, lockfile: Lockfile) { - super(flags, config, reporter, lockfile); + const workspaceRootIsCwd = config.cwd === config.lockfileFolder; + const _flags = flags ? {...flags, workspaceRootIsCwd} : {workspaceRootIsCwd}; + super(_flags, config, reporter, lockfile); this.args = args; // only one flag is supported, so we can figure out which one was passed to `yarn add` this.flagToOrigin = [ @@ -104,6 +106,49 @@ export class Add extends Install { return preparedPatterns; } + preparePatternsForLinking(patterns: Array, cwdManifest: Manifest, cwdIsRoot: boolean): Array { + // remove the newly added patterns if cwd != root and update the in-memory package dependency instead + if (cwdIsRoot) { + return patterns; + } + + let manifest; + const cwdPackage = `${cwdManifest.name}@${cwdManifest.version}`; + try { + manifest = this.resolver.getStrictResolvedPattern(cwdPackage); + } catch (e) { + this.reporter.warn(this.reporter.lang('unknownPackage', cwdPackage)); + return patterns; + } + + let newPatterns = patterns; + this._iterateAddedPackages((pattern, registry, dependencyType, pkgName, version) => { + // remove added package from patterns list + const filtered = newPatterns.filter(p => p !== pattern); + invariant( + newPatterns.length - filtered.length > 0, + `expect added pattern '${pattern}' in the list: ${patterns.toString()}`, + ); + newPatterns = filtered; + + // add new package into in-memory manifest so they can be linked properly + manifest[dependencyType] = manifest[dependencyType] || {}; + if (manifest[dependencyType][pkgName] === version) { + // package already existed + return; + } + + // update dependencies in the manifest + invariant(manifest._reference, 'manifest._reference should not be null'); + const ref: Object = manifest._reference; + + ref['dependencies'] = ref['dependencies'] || []; + ref['dependencies'].push(pattern); + }); + + return newPatterns; + } + async bailout(patterns: Array, workspaceLayout: ?WorkspaceLayout): Promise { const lockfileCache = this.lockfile.cache; if (!lockfileCache) { @@ -154,11 +199,33 @@ export class Add extends Install { const opts: ListOptions = { reqDepth: 0, }; - const {trees, count} = await buildTree(this.resolver, this.linker, patterns, opts, true, true); - this.reporter.success( - count === 1 ? this.reporter.lang('savedNewDependency') : this.reporter.lang('savedNewDependencies', count), - ); - this.reporter.tree('newDependencies', trees); + + // restore the original patterns + const merged = [...patterns, ...this.addedPatterns]; + + const {trees, count} = await buildTree(this.resolver, this.linker, merged, opts, true, true); + + if (count === 1) { + this.reporter.success(this.reporter.lang('savedNewDependency')); + } else { + this.reporter.success(this.reporter.lang('savedNewDependencies', count)); + } + + if (!count) { + return; + } + + const resolverPatterns = new Set(); + for (const pattern of patterns) { + const {version, name} = this.resolver.getResolvedPattern(pattern) || {}; + resolverPatterns.add(`${name}@${version}`); + } + const directRequireDependencies = trees.filter(({name}) => resolverPatterns.has(name)); + + this.reporter.info(this.reporter.lang('directDependencies')); + this.reporter.tree('newDirectDependencies', directRequireDependencies); + this.reporter.info(this.reporter.lang('allDependencies')); + this.reporter.tree('newAllDependencies', trees); } /** @@ -168,10 +235,28 @@ export class Add extends Install { async savePackages(): Promise { // fill rootPatternsToOrigin without `excludePatterns` await Install.prototype.fetchRequestFromCwd.call(this); - const patternOrigins = Object.keys(this.rootPatternsToOrigin); + // // get all the different registry manifests in this folder + const manifests: Object = await this.config.getRootManifests(); + + this._iterateAddedPackages((pattern, registry, dependencyType, pkgName, version) => { + // add it to manifest + const {object} = manifests[registry]; + + object[dependencyType] = object[dependencyType] || {}; + object[dependencyType][pkgName] = version; - // get all the different registry manifests in this folder - const manifests = await this.config.getRootManifests(); + if (dependencyType !== this.flagToOrigin) { + this.reporter.warn(this.reporter.lang('moduleAlreadyInManifest', pkgName, dependencyType, this.flagToOrigin)); + } + }); + + await this.config.saveRootManifests(manifests); + } + + _iterateAddedPackages( + f: (pattern: string, registry: string, dependencyType: string, pkgName: string, version: string) => void, + ) { + const patternOrigins = Object.keys(this.rootPatternsToOrigin); // add new patterns to their appropriate registry manifest for (const pattern of this.addedPatterns) { @@ -191,18 +276,8 @@ export class Add extends Install { // depType is calculated when `yarn upgrade` command is used const target = depType || this.flagToOrigin; - // add it to manifest - const {object} = manifests[ref.registry]; - - object[target] = object[target] || {}; - object[target][pkg.name] = version; - - if (target !== this.flagToOrigin) { - this.reporter.warn(this.reporter.lang('moduleAlreadyInManifest', pkg.name, depType, this.flagToOrigin)); - } + f(pattern, ref.registry, target, pkg.name, version); } - - await this.config.saveRootManifests(manifests); } } diff --git a/src/cli/commands/config.js b/src/cli/commands/config.js index e8340d0404..1e35326d73 100644 --- a/src/cli/commands/config.js +++ b/src/cli/commands/config.js @@ -31,6 +31,7 @@ const CONFIG_KEYS = [ 'childConcurrency', 'networkTimeout', 'workspacesEnabled', + 'workspacesNohoistEnabled', 'pruneOfflineMirror', 'enableMetaFolder', 'enableLockfileVersions', diff --git a/src/cli/commands/global.js b/src/cli/commands/global.js index ccc5a83abe..3ecc91fad1 100644 --- a/src/cli/commands/global.js +++ b/src/cli/commands/global.js @@ -199,8 +199,8 @@ async function list(config: Config, reporter: Reporter, flags: Object, args: Arr // install so we get hard file paths const lockfile = await Lockfile.fromDirectory(config.cwd); - const install = new Install({skipIntegrityCheck: true}, config, new NoopReporter(), lockfile); - const patterns = await install.init(); + const install = new Install({}, config, new NoopReporter(), lockfile); + const patterns = await install.getFlattenedDeps(); // dump global modules for (const pattern of patterns) { diff --git a/src/cli/commands/install.js b/src/cli/commands/install.js index e8003f6e35..118b739845 100644 --- a/src/cli/commands/install.js +++ b/src/cli/commands/install.js @@ -151,7 +151,7 @@ function normalizeFlags(config: Config, rawFlags: Object): Flags { // outdated, update-interactive includeWorkspaceDeps: !!rawFlags.includeWorkspaceDeps, - // remove, update + // add, remove, update workspaceRootIsCwd: rawFlags.workspaceRootIsCwd !== false, }; @@ -316,9 +316,11 @@ export class Install { } }; - pushDeps('dependencies', projectManifestJson, {hint: null, optional: false}, true); - pushDeps('devDependencies', projectManifestJson, {hint: 'dev', optional: false}, !this.config.production); - pushDeps('optionalDependencies', projectManifestJson, {hint: 'optional', optional: true}, true); + if (cwdIsRoot) { + pushDeps('dependencies', projectManifestJson, {hint: null, optional: false}, true); + pushDeps('devDependencies', projectManifestJson, {hint: 'dev', optional: false}, !this.config.production); + pushDeps('optionalDependencies', projectManifestJson, {hint: 'optional', optional: true}, true); + } if (this.config.workspaceRootFolder) { const workspaceLoc = cwdIsRoot ? loc : path.join(this.config.lockfileFolder, filename); @@ -356,6 +358,8 @@ export class Install { dependencies: workspaceDependencies, devDependencies: {...workspaceManifestJson.devDependencies}, optionalDependencies: {...workspaceManifestJson.optionalDependencies}, + private: workspaceManifestJson.private, + workspaces: workspaceManifestJson.workspaces, }; workspaceLayout.virtualManifestName = virtualDependencyManifest.name; const virtualDep = {}; @@ -397,6 +401,9 @@ export class Install { preparePatterns(patterns: Array): Array { return patterns; } + preparePatternsForLinking(patterns: Array, cwdManifest: Manifest, cwdIsRoot: boolean): Array { + return patterns; + } async bailout(patterns: Array, workspaceLayout: ?WorkspaceLayout): Promise { if (this.flags.skipIntegrityCheck || this.flags.force) { @@ -473,6 +480,21 @@ export class Install { } } + /** + * helper method that gets only recent manifests + * used by global.ls command + */ + async getFlattenedDeps(): Promise> { + const {requests: depRequests, patterns: rawPatterns} = await this.fetchRequestFromCwd(); + + await this.resolver.init(depRequests, {}); + + const manifests = await fetcher.fetch(this.resolver.getManifests(), this.config); + this.resolver.updateManifests(manifests); + + return this.flatten(rawPatterns); + } + /** * TODO description */ @@ -534,6 +556,11 @@ export class Install { // remove integrity hash to make this operation atomic await this.integrityChecker.removeIntegrityFile(); this.reporter.step(curr, total, this.reporter.lang('linkingDependencies'), emoji.get('link')); + flattenedTopLevelPatterns = this.preparePatternsForLinking( + flattenedTopLevelPatterns, + manifest, + this.config.lockfileFolder === this.config.cwd, + ); await this.linker.init(flattenedTopLevelPatterns, workspaceLayout, { linkDuplicates: this.flags.linkDuplicates, ignoreOptional: this.flags.ignoreOptional, diff --git a/src/cli/commands/licenses.js b/src/cli/commands/licenses.js index 1d95c73bf7..61c9fa00e6 100644 --- a/src/cli/commands/licenses.js +++ b/src/cli/commands/licenses.js @@ -49,44 +49,71 @@ async function getManifests(config: Config, flags: Object): Promise): Promise { const manifests: Array = await getManifests(config, flags); + const manifestsByLicense = new Map(); + + for (const {name, version, license, repository, homepage, author} of manifests) { + const licenseKey = license || 'UNKNOWN'; + const url = repository ? repository.url : homepage; + const vendorUrl = homepage || (author && author.url); + const vendorName = author && author.name; + + if (!manifestsByLicense.has(licenseKey)) { + manifestsByLicense.set(licenseKey, new Map()); + } + + const byLicense = manifestsByLicense.get(licenseKey); + invariant(byLicense, 'expected value'); + byLicense.set(`${name}@${version}`, { + name, + version, + url, + vendorUrl, + vendorName, + }); + } if (flags.json) { const body = []; - for (const {name, version, license, repository, homepage, author} of manifests) { - const url = repository ? repository.url : homepage; - const vendorUrl = homepage || (author && author.url); - const vendorName = author && author.name; - body.push([ - name, - version, - license || 'Unknown', - url || 'Unknown', - vendorUrl || 'Unknown', - vendorName || 'Unknown', - ]); - } + manifestsByLicense.forEach((license, licenseKey) => { + license.forEach(({name, version, url, vendorUrl, vendorName}) => { + body.push([name, version, licenseKey, url || 'Unknown', vendorUrl || 'Unknown', vendorName || 'Unknown']); + }); + }); reporter.table(['Name', 'Version', 'License', 'URL', 'VendorUrl', 'VendorName'], body); } else { const trees = []; - for (const {name, version, license, repository, homepage} of manifests) { - const children = []; - children.push({ - name: `${reporter.format.bold('License:')} ${license || reporter.format.red('UNKNOWN')}`, - }); + manifestsByLicense.forEach((license, licenseKey) => { + const licenseTree = []; - const url = repository ? repository.url : homepage; - if (url) { - children.push({name: `${reporter.format.bold('URL:')} ${url}`}); - } + license.forEach(({name, version, url, vendorUrl, vendorName}) => { + const children = []; + + if (url) { + children.push({name: `${reporter.format.bold('URL:')} ${url}`}); + } + + if (vendorUrl) { + children.push({name: `${reporter.format.bold('VendorUrl:')} ${vendorUrl}`}); + } + + if (vendorName) { + children.push({name: `${reporter.format.bold('VendorName:')} ${vendorName}`}); + } + + licenseTree.push({ + name: `${name}@${version}`, + children, + }); + }); trees.push({ - name: `${name}@${version}`, - children, + name: licenseKey, + children: licenseTree, }); - } + }); reporter.tree('licenses', trees); } @@ -121,16 +148,23 @@ export const {run, examples} = buildSubCommands('licenses', { // the same license text are grouped together. const manifestsByLicense: Map> = new Map(); for (const manifest of manifests) { - const {licenseText} = manifest; + const {licenseText, noticeText} = manifest; + let licenseKey; if (!licenseText) { continue; } - if (!manifestsByLicense.has(licenseText)) { - manifestsByLicense.set(licenseText, new Map()); + if (!noticeText) { + licenseKey = licenseText; + } else { + licenseKey = `${licenseText}\n\nNOTICE\n\n${noticeText}`; + } + + if (!manifestsByLicense.has(licenseKey)) { + manifestsByLicense.set(licenseKey, new Map()); } - const byLicense = manifestsByLicense.get(licenseText); + const byLicense = manifestsByLicense.get(licenseKey); invariant(byLicense, 'expected value'); byLicense.set(manifest.name, manifest); } @@ -141,7 +175,7 @@ export const {run, examples} = buildSubCommands('licenses', { ); console.log(); - for (const [licenseText, manifests] of manifestsByLicense) { + for (const [licenseKey, manifests] of manifestsByLicense) { console.log('-----'); console.log(); @@ -164,8 +198,8 @@ export const {run, examples} = buildSubCommands('licenses', { console.log(heading.join(' ')); console.log(); - if (licenseText) { - console.log(licenseText.trim()); + if (licenseKey) { + console.log(licenseKey.trim()); } else { // what do we do here? base it on `license`? } diff --git a/src/cli/commands/list.js b/src/cli/commands/list.js index 8952f21dab..f0dff3ea04 100644 --- a/src/cli/commands/list.js +++ b/src/cli/commands/list.js @@ -184,7 +184,11 @@ export function filterTree(tree: Tree, filters: Array, pattern: string = } export function getDevDeps(manifest: Object): Set { - return new Set(Object.keys(manifest.devDependencies).map(key => `${key}@${manifest.devDependencies[key]}`)); + if (manifest.devDependencies) { + return new Set(Object.keys(manifest.devDependencies).map(key => `${key}@${manifest.devDependencies[key]}`)); + } else { + return new Set(); + } } export async function run(config: Config, reporter: Reporter, flags: Object, args: Array): Promise { diff --git a/src/cli/commands/publish.js b/src/cli/commands/publish.js index ee16431e4b..d53ed1ebe7 100644 --- a/src/cli/commands/publish.js +++ b/src/cli/commands/publish.js @@ -27,8 +27,15 @@ export function hasWrapper(commander: Object, args: Array): boolean { } async function publish(config: Config, pkg: any, flags: Object, dir: string): Promise { + let access = flags.access; + + // if no access level is provided, check package.json for `publishConfig.access` + // see: https://docs.npmjs.com/files/package.json#publishconfig + if (!access && pkg && pkg.publishConfig && pkg.publishConfig.access) { + access = pkg.publishConfig.access; + } + // validate access argument - const access = flags.access; if (access && access !== 'public' && access !== 'restricted') { throw new MessageError(config.reporter.lang('invalidAccess')); } @@ -69,7 +76,7 @@ async function publish(config: Config, pkg: any, flags: Object, dir: string): Pr // create body const root = { _id: pkg.name, - access: flags.access, + access, name: pkg.name, description: pkg.description, 'dist-tags': { diff --git a/src/cli/commands/run.js b/src/cli/commands/run.js index b512e6d3f7..300acf89f2 100644 --- a/src/cli/commands/run.js +++ b/src/cli/commands/run.js @@ -81,7 +81,12 @@ export async function run(config: Config, reporter: Reporter, flags: Object, arg for (const [stage, cmd] of cmds) { // only tack on trailing arguments for default script, ignore for pre and post - #1595 const cmdWithArgs = stage === action ? sh`${unquoted(cmd)} ${args}` : cmd; - await execCommand(stage, config, cmdWithArgs, config.cwd); + const customShell = config.getOption('script-shell'); + if (customShell) { + await execCommand(stage, config, cmdWithArgs, config.cwd, String(customShell)); + } else { + await execCommand(stage, config, cmdWithArgs, config.cwd); + } } } else if (action === 'env') { reporter.log(JSON.stringify(await makeEnv('env', config.cwd, config), null, 2), {force: true}); diff --git a/src/cli/commands/upgrade-interactive.js b/src/cli/commands/upgrade-interactive.js index f106f4f23a..090341f53a 100644 --- a/src/cli/commands/upgrade-interactive.js +++ b/src/cli/commands/upgrade-interactive.js @@ -169,13 +169,17 @@ export async function run(config: Config, reporter: Reporter, flags: Object, arg acc[workspaceLoc] = xs.concat(dep); return acc; }, {}); + const cwd = config.cwd; for (const loc of Object.keys(depsByWorkspace)) { const patterns = depsByWorkspace[loc].map(getPattern); cleanLockfile(lockfile, deps, packagePatterns, reporter); reporter.info(reporter.lang('updateInstalling', getNameFromHint(hint))); - config.cwd = path.resolve(path.dirname(loc)); + if (loc !== '') { + config.cwd = path.resolve(path.dirname(loc)); + } const add = new Add(patterns, flags, config, reporter, lockfile); await add.init(); + config.cwd = cwd; } } } diff --git a/src/cli/commands/version.js b/src/cli/commands/version.js index c75ae40b07..2229be03bb 100644 --- a/src/cli/commands/version.js +++ b/src/cli/commands/version.js @@ -77,6 +77,7 @@ export async function setVersion( newVersion = await reporter.question(reporter.lang('newVersion')); if (!required && !newVersion) { + reporter.info(`${reporter.lang('noVersionOnPublish')}: ${oldVersion}`); return function(): Promise { return Promise.resolve(); }; @@ -116,6 +117,8 @@ export async function setVersion( } await config.saveRootManifests(manifests); + await runLifecycle('version'); + // check if committing the new version to git is overriden if (!flags.gitTagVersion || !config.getOption('version-git-tag')) { // Don't tag the version in Git @@ -137,8 +140,6 @@ export async function setVersion( } } - await runLifecycle('version'); - if (isGit) { const message = (flags.message || String(config.getOption('version-git-message'))).replace(/%s/g, newVersion); const sign: boolean = Boolean(config.getOption('version-sign-git-tag')); diff --git a/src/cli/commands/why.js b/src/cli/commands/why.js index 3ef50b145f..9d43c440f6 100644 --- a/src/cli/commands/why.js +++ b/src/cli/commands/why.js @@ -116,6 +116,15 @@ export function hasWrapper(commander: Object, args: Array): boolean { return true; } +// to conform to the current standard '#' as package tree separator +function toStandardPathString(pathString: string): string { + const str = pathString.replace(/\//g, '#'); + if (str[0] === '#') { + return str.slice(1); + } + return str; +} + export async function run(config: Config, reporter: Reporter, flags: Object, args: Array): Promise { if (!args.length) { throw new MessageError(reporter.lang('missingWhyDependency')); @@ -143,124 +152,122 @@ export async function run(config: Config, reporter: Reporter, flags: Object, arg // finding reporter.step(3, 4, reporter.lang('whyFinding'), emoji.get('mag')); - let match; - for (const [loc, info] of hoisted) { - if (info.key === query || info.previousKeys.indexOf(query) >= 0) { - match = [loc, info]; - break; - } - } + const matches = queryWhy(query, hoisted); - if (!match) { + if (matches.length <= 0) { reporter.error(reporter.lang('whyUnknownMatch')); return; } - const [, matchInfo] = match; - const matchRef = matchInfo.pkg._reference; - invariant(matchRef, 'expected reference'); + const processMatch = async (match: HoistManifestTuple) => { + const [, matchInfo] = match; + const matchRef = matchInfo.pkg._reference; + invariant(matchRef, 'expected reference'); - const matchPatterns = matchRef.patterns; - const matchRequests = matchRef.requests; + const distinctMatchPatterns = new Set(matchRef.patterns); + const reasons = []; - const reasons = []; - // reason: dependency of these modules - for (const request of matchRequests) { - const parentRequest = request.parentRequest; - if (!parentRequest) { - continue; + // reason: dependency of these modules + if (matchInfo.originalParentPath.length > 0) { + reasons.push({ + type: 'whyDependedOn', + typeSimple: 'whyDependedOnSimple', + value: toStandardPathString(matchInfo.originalParentPath), + }); } - const dependent = install.resolver.getResolvedPattern(parentRequest.pattern); - if (!dependent) { - continue; + // reason: exists in manifest + let rootType; + for (const pattern of distinctMatchPatterns) { + rootType = install.rootPatternsToOrigin[pattern]; + if (rootType) { + reasons.push({ + type: 'whySpecified', + typeSimple: 'whySpecifiedSimple', + value: rootType, + }); + } } - const chain = []; - - let delegator = parentRequest; - do { - chain.push(install.resolver.getStrictResolvedPattern(delegator.pattern).name); - } while ((delegator = delegator.parentRequest)); - - reasons.push({ - type: 'whyDependedOn', - typeSimple: 'whyDependedOnSimple', - value: chain.reverse().join('#'), - }); - } - - // reason: exists in manifest - let rootType; - for (const pattern of matchPatterns) { - rootType = install.rootPatternsToOrigin[pattern]; - if (rootType) { + // reason: this is hoisted from these modules + for (const path of matchInfo.previousPaths) { reasons.push({ - type: 'whySpecified', - typeSimple: 'whySpecifiedSimple', - value: rootType, + type: 'whyHoistedFrom', + typeSimple: 'whyHoistedFromSimple', + value: toStandardPathString(path), }); } - } - // reason: this is hoisted from these modules - for (const pattern of matchInfo.previousKeys) { - if (pattern !== matchInfo.key) { + // package sizes + let packageSize = 0; + let directSizes = []; + let transitiveSizes = []; + try { + packageSize = await getPackageSize(match); + } catch (e) {} + + const dependencies = Array.from(collect(hoisted, new Set(), match)); + const transitiveDependencies = Array.from(collect(hoisted, new Set(), match, {recursive: true})); + + try { + directSizes = await Promise.all(dependencies.map(getPackageSize)); + transitiveSizes = await Promise.all(transitiveDependencies.map(getPackageSize)); + } catch (e) {} + + const transitiveKeys = new Set(transitiveDependencies.map(([, info]) => info.key)); + const sharedDependencies = getSharedDependencies(hoisted, transitiveKeys); + + // prepare output: populate reporter + reporter.info(reporter.lang('whyMatch', `${matchInfo.key}@${matchInfo.pkg.version}`)); + // + // reason: hoisted/nohoist + if (matchInfo.isNohoist) { reasons.push({ - type: 'whyHoistedFrom', - typeSimple: 'whyHoistedFromSimple', - value: pattern, + type: 'whyNotHoisted', + typeSimple: 'whyNotHoistedSimple', + value: matchInfo.nohoistList, }); + } else if (query === matchInfo.originalKey) { + reporter.info(reporter.lang('whyHoistedTo', matchInfo.key)); } - } - - // package sizes - reporter.step(4, 4, reporter.lang('whyCalculating'), emoji.get('aerial_tramway')); - let packageSize = 0; - let directSizes = []; - let transitiveSizes = []; - try { - packageSize = await getPackageSize(match); - } catch (e) {} + if (reasons.length === 1) { + reporter.info(reporter.lang(reasons[0].typeSimple, reasons[0].value)); + } else if (reasons.length > 1) { + reporter.info(reporter.lang('whyReasons')); + reporter.list('reasons', reasons.map(reason => reporter.lang(reason.type, reason.value))); + } else { + reporter.error(reporter.lang('whyWhoKnows')); + } - const dependencies = Array.from(collect(hoisted, new Set(), match)); - const transitiveDependencies = Array.from(collect(hoisted, new Set(), match, {recursive: true})); + if (packageSize) { + // stats: file size of this dependency without any dependencies + reporter.info(reporter.lang('whyDiskSizeWithout', bytes(packageSize))); - try { - directSizes = await Promise.all(dependencies.map(getPackageSize)); - transitiveSizes = await Promise.all(transitiveDependencies.map(getPackageSize)); - } catch (e) {} + // stats: file size of this dependency including dependencies that aren't shared + reporter.info(reporter.lang('whyDiskSizeUnique', bytes(packageSize + sum(directSizes)))); - const transitiveKeys = new Set(transitiveDependencies.map(([, info]) => info.key)); - const sharedDependencies = getSharedDependencies(hoisted, transitiveKeys); + // stats: file size of this dependency including dependencies + reporter.info(reporter.lang('whyDiskSizeTransitive', bytes(packageSize + sum(transitiveSizes)))); - // - // reason: hoisted - if (query === matchInfo.originalKey) { - reporter.info(reporter.lang('whyHoistedTo', matchInfo.key)); - } + // stats: shared transitive dependencies + reporter.info(reporter.lang('whySharedDependencies', sharedDependencies.size)); + } + }; - if (reasons.length === 1) { - reporter.info(reporter.lang(reasons[0].typeSimple, reasons[0].value)); - } else if (reasons.length > 1) { - reporter.info(reporter.lang('whyReasons')); - reporter.list('reasons', reasons.map(reason => reporter.lang(reason.type, reason.value))); - } else { - reporter.error(reporter.lang('whyWhoKnows')); + reporter.step(4, 4, reporter.lang('whyCalculating'), emoji.get('aerial_tramway')); + for (const match of matches) { + await processMatch(match); } +} - if (packageSize) { - // stats: file size of this dependency without any dependencies - reporter.info(reporter.lang('whyDiskSizeWithout', bytes(packageSize))); - - // stats: file size of this dependency including dependencies that aren't shared - reporter.info(reporter.lang('whyDiskSizeUnique', bytes(packageSize + sum(directSizes)))); - - // stats: file size of this dependency including dependencies - reporter.info(reporter.lang('whyDiskSizeTransitive', bytes(packageSize + sum(transitiveSizes)))); - - // stats: shared transitive dependencies - reporter.info(reporter.lang('whySharedDependencies', sharedDependencies.size)); +export function queryWhy(pattern: string, hoisted: HoistManifestTuples): Array { + const nohoistPattern = `#${pattern}`; + const found: Array = []; + for (const [loc, info] of hoisted) { + if (info.key === pattern || info.previousPaths.indexOf(pattern) >= 0 || info.key.endsWith(nohoistPattern)) { + found.push([loc, info]); + } } + return found; } diff --git a/src/config.js b/src/config.js index 21300ac5e8..071beec009 100644 --- a/src/config.js +++ b/src/config.js @@ -2,7 +2,7 @@ import type {RegistryNames, ConfigRegistries} from './registries/index.js'; import type {Reporter} from './reporters/index.js'; -import type {Manifest, PackageRemote, WorkspacesManifestMap} from './types.js'; +import type {Manifest, PackageRemote, WorkspacesManifestMap, WorkspacesConfig} from './types.js'; import type PackageReference from './package-reference.js'; import {execFromManifest} from './util/execute-lifecycle-script.js'; import {resolveWithHome} from './util/path.js'; @@ -156,6 +156,7 @@ export default class Config { nonInteractive: boolean; workspacesEnabled: boolean; + workspacesNohoistEnabled: boolean; // cwd: string; @@ -321,6 +322,7 @@ export default class Config { this._cacheRootFolder = String(cacheRootFolder); } this.workspacesEnabled = this.getOption('workspaces-experimental') !== false; + this.workspacesNohoistEnabled = this.getOption('workspaces-nohoist-experimental') !== false; this.pruneOfflineMirror = Boolean(this.getOption('yarn-offline-mirror-pruning')); this.enableMetaFolder = Boolean(this.getOption('enable-meta-folder')); @@ -612,12 +614,16 @@ export default class Config { async findWorkspaceRoot(initial: string): Promise { let previous = null; let current = path.normalize(initial); + if (!await fs.exists(current)) { + throw new MessageError(this.reporter.lang('folderMissing', current)); + } do { const manifest = await this.findManifest(current, true); - if (manifest && manifest.workspaces) { + const ws = extractWorkspaces(manifest); + if (ws && ws.packages) { const relativePath = path.relative(current, initial); - if (relativePath === '' || micromatch([relativePath], manifest.workspaces).length > 0) { + if (relativePath === '' || micromatch([relativePath], ws.packages).length > 0) { return current; } else { return null; @@ -633,12 +639,15 @@ export default class Config { async resolveWorkspaces(root: string, rootManifest: Manifest): Promise { const workspaces = {}; - const patterns = rootManifest.workspaces || []; if (!this.workspacesEnabled) { return workspaces; } - if (!rootManifest.private && patterns.length > 0) { - throw new MessageError(this.reporter.lang('workspacesRequirePrivateProjects')); + + const ws = this.getWorkspaces(rootManifest, true); + const patterns = ws && ws.packages ? ws.packages : []; + + if (!Array.isArray(patterns)) { + throw new MessageError(this.reporter.lang('workspacesSettingMustBeArray')); } const registryFilenames = registryNames @@ -683,6 +692,49 @@ export default class Config { return workspaces; } + // workspaces functions + getWorkspaces(manifest: ?Manifest, shouldThrow: boolean = false): ?WorkspacesConfig { + if (!manifest || !this.workspacesEnabled) { + return undefined; + } + + const ws = extractWorkspaces(manifest); + + if (!ws) { + return ws; + } + + // validate eligibility + let wsCopy = {...ws}; + const warnings: Array = []; + + // packages + if (wsCopy.packages && wsCopy.packages.length > 0 && !manifest.private) { + warnings.push(this.reporter.lang('workspacesRequirePrivateProjects')); + wsCopy = undefined; + } + // nohoist + if (wsCopy && wsCopy.nohoist && wsCopy.nohoist.length > 0) { + if (!this.workspacesNohoistEnabled) { + warnings.push(this.reporter.lang('workspacesNohoistDisabled', manifest.name)); + wsCopy.nohoist = undefined; + } else if (!manifest.private) { + warnings.push(this.reporter.lang('workspacesNohoistRequirePrivatePackages', manifest.name)); + wsCopy.nohoist = undefined; + } + } + + if (warnings.length > 0) { + const msg = warnings.join('\n'); + if (shouldThrow) { + throw new MessageError(msg); + } else { + this.reporter.warn(msg); + } + } + return wsCopy; + } + /** * Description */ @@ -766,3 +818,22 @@ export default class Config { return config; } } + +export function extractWorkspaces(manifest: ?Manifest): ?WorkspacesConfig { + if (!manifest || !manifest.workspaces) { + return undefined; + } + + if (Array.isArray(manifest.workspaces)) { + return {packages: manifest.workspaces}; + } + + if ( + (manifest.workspaces.packages && Array.isArray(manifest.workspaces.packages)) || + (manifest.workspaces.nohoist && Array.isArray(manifest.workspaces.nohoist)) + ) { + return manifest.workspaces; + } + + return undefined; +} diff --git a/src/package-hoister.js b/src/package-hoister.js index 3ac70dc57c..f8c2a00c5a 100644 --- a/src/package-hoister.js +++ b/src/package-hoister.js @@ -1,9 +1,10 @@ /* @flow */ import type PackageResolver from './package-resolver.js'; -import type Config from './config.js'; +import Config from './config.js'; import type {Manifest} from './types.js'; import {sortAlpha} from './util/misc.js'; +import mm from 'micromatch'; const invariant = require('invariant'); const path = require('path'); @@ -12,6 +13,12 @@ type Parts = Array; let historyCounter = 0; +const LINK_TYPES = new Set(['workspace', 'link']); +type NewPartsType = { + parts: Parts, + duplicate: boolean, +}; + export class HoistManifest { constructor( key: string, @@ -31,10 +38,13 @@ export class HoistManifest { this.key = key; this.parts = parts; this.originalKey = key; - this.previousKeys = []; + this.previousPaths = []; this.history = []; this.addHistory(`Start position = ${key}`); + + this.isNohoist = false; + this.originalParentPath = ''; } isRequired: boolean; @@ -43,11 +53,16 @@ export class HoistManifest { pkg: Manifest; loc: string; parts: Parts; - previousKeys: Array; + previousPaths: Array; history: Array; key: string; originalKey: string; + // nohoist info + isNohoist: boolean; + nohoistList: ?Array; + originalParentPath: string; + addHistory(msg: string) { this.history.push(`${++historyCounter}: ${msg}`); } @@ -63,10 +78,13 @@ export default class PackageHoister { this.taintedKeys = new Map(); this.levelQueue = []; this.tree = new Map(); + + this.nohoistResolver = new NohoistResolver(config, resolver); } resolver: PackageResolver; config: Config; + nohoistResolver: NohoistResolver; ignoreOptional: ?boolean; @@ -202,7 +220,9 @@ export default class PackageHoister { const parts = parentParts.concat(pkg.name); const key: string = this.implodeKey(parts); const info: HoistManifest = new HoistManifest(key, parts, pkg, loc, isDirectRequire, isRequired, isIncompatible); - // + + this.nohoistResolver.initNohoist(info, parent); + this.tree.set(key, info); this.taintKey(key, info); @@ -216,7 +236,7 @@ export default class PackageHoister { /** * Propagate inherited ignore statuses from non-ignored to ignored packages - */ + */ _propagateRequired() { // @@ -254,7 +274,7 @@ export default class PackageHoister { /** * Looks up the package a dependency resolves to - */ + */ _lookupDependency(info: HoistManifest, depPattern: string): ?HoistManifest { // @@ -279,21 +299,19 @@ export default class PackageHoister { * Find the highest position we can hoist this module to. */ - getNewParts( - key: string, - info: HoistManifest, - parts: Parts, - ): { - parts: Parts, - duplicate: boolean, - } { + getNewParts(key: string, info: HoistManifest, parts: Parts): NewPartsType { let stepUp = false; + const highestHoistingPoint = this.nohoistResolver.highestHoistingPoint(info) || 0; const fullKey = this.implodeKey(parts); const stack = []; // stack of removed parts const name = parts.pop(); - for (let i = parts.length - 1; i >= 0; i--) { + if (info.isNohoist) { + info.addHistory(`Marked as nohoist, will not be hoisted above '${parts[highestHoistingPoint]}'`); + } + + for (let i = parts.length - 1; i >= highestHoistingPoint; i--) { const checkParts = parts.slice(0, i).concat(name); const checkKey = this.implodeKey(checkParts); info.addHistory(`Looked at ${checkKey} for a match`); @@ -328,7 +346,7 @@ export default class PackageHoister { const peerDependencies = Object.keys(info.pkg.peerDependencies || {}); // remove redundant parts that wont collide - hoistLoop: while (parts.length) { + hoistLoop: while (parts.length > highestHoistingPoint) { // we must not hoist a package higher than its peer dependencies for (const peerDependency of peerDependencies) { const checkParts = parts.concat(peerDependency); @@ -369,6 +387,10 @@ export default class PackageHoister { // const isValidPosition = (parts: Parts): boolean => { + // nohoist package can't be hoisted to the "root" + if (parts.length <= highestHoistingPoint) { + return false; + } const key = this.implodeKey(parts); const existing = this.tree.get(key); if (existing && existing.loc === info.loc) { @@ -415,18 +437,19 @@ export default class PackageHoister { // remove this item from the `tree` map so we can ignore it this.tree.delete(oldKey); - const {parts, duplicate} = this.getNewParts(oldKey, info, rawParts.slice()); + const newKey = this.implodeKey(parts); if (duplicate) { info.addHistory(`Satisfied from above by ${newKey}`); this.declareRename(info, rawParts, parts); + this.updateHoistHistory(this.nohoistResolver._originalPath(info), this.implodeKey(parts)); return; } // update to the new key if (oldKey === newKey) { - info.addHistory("Didn't hoist - conflicts above"); + info.addHistory(`Didn't hoist - see reason above`); this.setKey(info, oldKey, rawParts); return; } @@ -460,6 +483,12 @@ export default class PackageHoister { } } + updateHoistHistory(fromPath: string, toKey: string) { + const info = this.tree.get(toKey); + invariant(info, `expect to find hoist-to ${toKey}`); + info.previousPaths.push(fromPath); + } + /** * Update the key of a module and update our references. */ @@ -475,7 +504,9 @@ export default class PackageHoister { return; } - info.previousKeys.push(newKey); + const fromInfo = this.tree.get(newKey); + invariant(fromInfo, `expect to find hoist-from ${newKey}`); + info.previousPaths.push(this.nohoistResolver._originalPath(fromInfo)); info.addHistory(`New position = ${newKey}`); } @@ -660,5 +691,105 @@ export default class PackageHoister { } } +const WS_ROOT_ALIAS = '_project_'; +export class NohoistResolver { + constructor(config: Config, resolver: PackageResolver) { + this._resolver = resolver; + this._config = config; + if (resolver.workspaceLayout) { + this._wsRootPackageName = resolver.workspaceLayout.virtualManifestName; + const {manifest} = resolver.workspaceLayout.getWorkspaceManifest(this._wsRootPackageName); + this._wsRootNohoistList = this._extractNohoistList(manifest, manifest.name); + } + } + _resolver: PackageResolver; + _config: Config; + _wsRootNohoistList: ?Array; + _wsRootPackageName: ?string; + + /** + * examine the top level packages to find the root package + */ + initNohoist = (info: HoistManifest, parent: ?HoistManifest) => { + let parentNohoistList: ?Array; + let originalParentPath: string = info.originalParentPath; + + if (parent) { + parentNohoistList = parent.nohoistList; + originalParentPath = this._originalPath(parent); + } else { + invariant(this._isTopPackage(info), `${info.key} doesn't have parent nor a top package`); + if (info.pkg.name !== this._wsRootPackageName) { + parentNohoistList = this._wsRootNohoistList; + originalParentPath = this._wsRootPackageName || ''; + } + } + + info.originalParentPath = originalParentPath; + let nohoistList = this._extractNohoistList(info.pkg, this._originalPath(info)) || []; + if (parentNohoistList) { + nohoistList = nohoistList.concat(parentNohoistList); + } + info.nohoistList = nohoistList.length > 0 ? nohoistList : null; + info.isNohoist = this._isNohoist(info); + }; + + /** + * find the highest hoisting point for the given HoistManifest. + * algorithm: a nohoist package should never be hoisted beyond the top of its branch, i.e. + * the first element of its parts. Therefore the highest possible hoisting index is 1, + * unless the package has only 1 part (itself), in such case returns null just like any hoisted package + * + */ + + highestHoistingPoint = (info: HoistManifest): ?number => { + return info.isNohoist && info.parts.length > 1 ? 1 : null; + }; + + // private functions + _isNohoist = (info: HoistManifest): boolean => { + if (!info.nohoistList || info.nohoistList.length <= 0) { + return false; + } + const path = this._originalPath(info); + + // top package can not be marked 'nohoist' because it is already at the top (hoisted). + return !this._isTopPackage(info) && mm.any(path, info.nohoistList); + }; + _isRootPackage = (pkg: Manifest): boolean => { + return pkg.name === this._wsRootPackageName; + }; + _originalPath = (info: HoistManifest): string => { + return this._makePath(info.originalParentPath, info.pkg.name); + }; + _makePath(...args: Array): string { + const parts = args.map(s => (s === this._wsRootPackageName ? WS_ROOT_ALIAS : s)); + return parts.join('/'); + } + _isTopPackage = (info: HoistManifest): boolean => { + const parentParts = info.parts.slice(0, -1); + const result = + !parentParts || + parentParts.length <= 0 || + (parentParts.length === 1 && parentParts[0] === this._wsRootPackageName); + return result; + }; + _isLink = (info: HoistManifest): boolean => { + return info.pkg._remote != null && LINK_TYPES.has(info.pkg._remote.type); + }; + + // extract nohoist from package.json then prefix them with branch path + // so we can matched against the branch tree ("originalPath") later + _extractNohoistList = (pkg: Manifest, pathPrefix: string): ?Array => { + let nohoistList: ?Array; + const ws = this._config.getWorkspaces(pkg); + + if (ws && ws.nohoist) { + nohoistList = ws.nohoist.map(p => this._makePath(pathPrefix, p)); + } + return nohoistList; + }; +} + export type HoistManifestTuple = [string, HoistManifest]; export type HoistManifestTuples = Array; diff --git a/src/package-linker.js b/src/package-linker.js index e32fc2480c..31236c36e2 100644 --- a/src/package-linker.js +++ b/src/package-linker.js @@ -401,7 +401,7 @@ export default class PackageLinker { // create binary links if (this.config.binLinks) { - const topLevelDependencies = this.determineTopLevelBinLinks(flatTree); + const topLevelDependencies = this.determineTopLevelBinLinkOrder(flatTree); const tickBin = this.reporter.progress(flatTree.length + topLevelDependencies.length); // create links in transient dependencies @@ -420,7 +420,7 @@ export default class PackageLinker { // create links at top level for all dependencies. await promise.queue( topLevelDependencies, - async ([dest, pkg]) => { + async ([dest, {pkg}]) => { if (pkg._reference && pkg._reference.location && pkg.bin && Object.keys(pkg.bin).length) { const binLoc = path.join(this.config.lockfileFolder, this.config.getFolder(pkg)); await this.linkSelfDependencies(pkg, dest, binLoc); @@ -436,17 +436,32 @@ export default class PackageLinker { } } - determineTopLevelBinLinks(flatTree: HoistManifestTuples): Array<[string, Manifest]> { + determineTopLevelBinLinkOrder(flatTree: HoistManifestTuples): HoistManifestTuples { const linksToCreate = new Map(); - for (const [dest, {pkg, isDirectRequire}] of flatTree) { + for (const [dest, hoistManifest] of flatTree) { + const {pkg, isDirectRequire} = hoistManifest; const {name} = pkg; if (isDirectRequire || (this.topLevelBinLinking && !linksToCreate.has(name))) { - linksToCreate.set(name, [dest, pkg]); + linksToCreate.set(name, [dest, hoistManifest]); } } - return Array.from(linksToCreate.values()); + // Sort the array so that direct dependencies will be linked last. + // Bin links are overwritten if they already exist, so this will cause direct deps to take precedence. + // If someone finds this to be incorrect later, you could also consider sorting descending by + // `linkToCreate.level` which is the dependency tree depth. Direct deps will have level 0 and transitive + // deps will have level > 0. + const transientBins = []; + const topLevelBins = []; + for (const linkToCreate of Array.from(linksToCreate.values())) { + if (linkToCreate[1].isDirectRequire) { + topLevelBins.push(linkToCreate); + } else { + transientBins.push(linkToCreate); + } + } + return [...transientBins, ...topLevelBins]; } resolvePeerModules() { diff --git a/src/package-request.js b/src/package-request.js index 25a1bbd0ac..e2ae710dbd 100644 --- a/src/package-request.js +++ b/src/package-request.js @@ -39,8 +39,10 @@ export default class PackageRequest { this.pattern = req.pattern; this.config = resolver.config; this.foundInfo = null; + } - resolver.usedRegistries.add(req.registry); + init() { + this.resolver.usedRegistries.add(this.registry); } parentRequest: ?PackageRequest; @@ -109,7 +111,18 @@ export default class PackageRequest { const Resolver = this.getRegistryResolver(); const resolver = new Resolver(this, name, range); - return resolver.resolve(); + try { + return await resolver.resolve(); + } catch (err) { + // if it is not an error thrown by yarn and it has a parent request, + // thow a more readable error + if (!(err instanceof MessageError) && this.parentRequest && this.parentRequest.pattern) { + throw new MessageError( + this.reporter.lang('requiredPackageNotFoundRegistry', pattern, this.parentRequest.pattern, this.registry), + ); + } + throw err; + } } /** diff --git a/src/package-resolver.js b/src/package-resolver.js index 19b7f92e4e..65fdccfb26 100644 --- a/src/package-resolver.js +++ b/src/package-resolver.js @@ -490,33 +490,36 @@ export default class PackageResolver { return; } + const request = new PackageRequest(req, this); const fetchKey = `${req.registry}:${req.pattern}:${String(req.optional)}`; - if (this.fetchingPatterns.has(fetchKey)) { - return; - } - this.fetchingPatterns.add(fetchKey); + const initialFetch = !this.fetchingPatterns.has(fetchKey); + let fresh = false; if (this.activity) { this.activity.tick(req.pattern); } - const lockfileEntry = this.lockfile.getLocked(req.pattern); - let fresh = false; + if (initialFetch) { + this.fetchingPatterns.add(fetchKey); - if (lockfileEntry) { - const {range, hasVersion} = normalizePattern(req.pattern); + const lockfileEntry = this.lockfile.getLocked(req.pattern); - if (this.isLockfileEntryOutdated(lockfileEntry.version, range, hasVersion)) { - this.reporter.warn(this.reporter.lang('incorrectLockfileEntry', req.pattern)); - this.removePattern(req.pattern); - this.lockfile.removePattern(req.pattern); + if (lockfileEntry) { + const {range, hasVersion} = normalizePattern(req.pattern); + + if (this.isLockfileEntryOutdated(lockfileEntry.version, range, hasVersion)) { + this.reporter.warn(this.reporter.lang('incorrectLockfileEntry', req.pattern)); + this.removePattern(req.pattern); + this.lockfile.removePattern(req.pattern); + fresh = true; + } + } else { fresh = true; } - } else { - fresh = true; + + request.init(); } - const request = new PackageRequest(req, this); await request.find({fresh, frozen: this.frozen}); } diff --git a/src/registries/npm-registry.js b/src/registries/npm-registry.js index 501ef18a48..3a553d1131 100644 --- a/src/registries/npm-registry.js +++ b/src/registries/npm-registry.js @@ -72,6 +72,19 @@ function normalizePath(val: mixed): ?string { return resolveWithHome(val); } +type UrlParts = { + host: string, + path: string, +}; + +function urlParts(requestUrl: string): UrlParts { + const normalizedUrl = normalizeUrl(requestUrl); + const parsed = url.parse(normalizedUrl); + const host = parsed.host || ''; + const path = parsed.path || ''; + return {host, path}; +} + export default class NpmRegistry extends Registry { constructor(cwd: string, registries: ConfigRegistries, requestManager: RequestManager, reporter: Reporter) { super(cwd, registries, requestManager, reporter); @@ -100,21 +113,18 @@ export default class NpmRegistry extends Registry { } isRequestToRegistry(requestUrl: string, registryUrl: string): boolean { - const normalizedRequestUrl = normalizeUrl(requestUrl); - const normalizedRegistryUrl = normalizeUrl(registryUrl); - const requestParsed = url.parse(normalizedRequestUrl); - const registryParsed = url.parse(normalizedRegistryUrl); - const requestHost = requestParsed.host || ''; - const registryHost = registryParsed.host || ''; - const requestPath = requestParsed.path || ''; - const registryPath = registryParsed.path || ''; + const request = urlParts(requestUrl); + const registry = urlParts(registryUrl); const customHostSuffix = this.getRegistryOrGlobalOption(registryUrl, 'custom-host-suffix'); + const requestToRegistryHost = () => request.host === registry.host; + const requestToYarn = () => YARN_REGISTRY.includes(request.host) && DEFAULT_REGISTRY.includes(registry.host); + return ( - requestHost === registryHost && - (requestPath.startsWith(registryPath) || + (requestToRegistryHost() || requestToYarn()) && + (request.path.startsWith(registry.path) || // For some registries, the package path does not prefix with the registry path - (typeof customHostSuffix === 'string' && requestHost.endsWith(customHostSuffix))) + (typeof customHostSuffix === 'string' && request.host.endsWith(customHostSuffix))) ); } @@ -133,7 +143,7 @@ export default class NpmRegistry extends Registry { opts.headers, ); - const isToRegistry = this.isRequestToRegistry(requestUrl, registry); + const isToRegistry = this.isRequestToRegistry(requestUrl, registry) || this.requestNeedsAuth(requestUrl); // this.token must be checked to account for publish requests on non-scopped packages if (this.token || (isToRegistry && (alwaysAuth || this.isScopedPackage(packageIdent)))) { @@ -156,6 +166,21 @@ export default class NpmRegistry extends Registry { }); } + requestNeedsAuth(requestUrl: string): boolean { + const config = this.config; + const requestParts = urlParts(requestUrl); + return !!Object.keys(config).find(option => { + const parts = option.split(':'); + if (parts.length === 2 && parts[1] === '_authToken') { + const registryParts = urlParts(parts[0]); + if (requestParts.host === registryParts.host && requestParts.path.startsWith(registryParts.path)) { + return true; + } + } + return false; + }); + } + async checkOutdated(config: Config, name: string, range: string): CheckOutdatedReturn { const req = await this.request(NpmRegistry.escapeName(name), { headers: {Accept: 'application/json'}, diff --git a/src/reporters/buffer-reporter.js b/src/reporters/buffer-reporter.js index d0271790c9..09a10f9c22 100644 --- a/src/reporters/buffer-reporter.js +++ b/src/reporters/buffer-reporter.js @@ -4,7 +4,7 @@ import JSONReporter from './json-reporter.js'; type Buffer = Array<{ type: string, - data: string | Object | number, + data: Object, error: boolean, }>; diff --git a/src/reporters/console/console-reporter.js b/src/reporters/console/console-reporter.js index a1e047c602..48e7208f0f 100644 --- a/src/reporters/console/console-reporter.js +++ b/src/reporters/console/console-reporter.js @@ -230,6 +230,7 @@ export default class ConsoleReporter extends BaseReporter { } // handles basic tree output to console tree(key: string, trees: Trees) { + this.stopProgress(); // const output = ({name, children, hint, color}, titlePrefix, childrenPrefix) => { const formatter = this.format; diff --git a/src/reporters/lang/en.js b/src/reporters/lang/en.js index ac12f341b5..0fc262aa51 100644 --- a/src/reporters/lang/en.js +++ b/src/reporters/lang/en.js @@ -80,7 +80,8 @@ const messages = { invalidVersion: 'Invalid version supplied.', requiredVersionInRange: 'Required version in range.', packageNotFoundRegistry: "Couldn't find package $0 on the $1 registry.", - doesntExist: "$0 doesn't exist.", + requiredPackageNotFoundRegistry: "Couldn't find package $0 required by $1 on the $2 registry.", + doesntExist: "Package $1 refers to a non-existing file '$0'.", missingRequiredPackageKey: `Package $0 doesn't have a $1.`, invalidAccess: 'Invalid argument for access, expected public or restricted.', invalidCommand: 'Invalid subcommand. Try $0', @@ -98,7 +99,7 @@ const messages = { ignoredScripts: 'Ignored scripts due to flag.', missingAddDependencies: 'Missing list of packages to add to your project.', yesWarning: - 'The yes flag has been set. This will automatically answer yes to all questions which may have security implications.', + 'The yes flag has been set. This will automatically answer yes to all questions, which may have security implications.', networkWarning: "You don't appear to have an internet connection. Try the --offline flag to use the cache for registry queries.", flatGlobalError: @@ -118,14 +119,14 @@ const messages = { frozenLockfileError: 'Your lockfile needs to be updated, but yarn was run with `--frozen-lockfile`.', fileWriteError: 'Could not write file $0: $1', multiplePackagesCantUnpackInSameDestination: - 'Pattern $0 is trying to unpack in the same destination $1 as pattern $2. This could result in a non deterministic behavior, skipping.', + 'Pattern $0 is trying to unpack in the same destination $1 as pattern $2. This could result in non-deterministic behavior, skipping.', incorrectLockfileEntry: 'Lockfile has incorrect entry for $0. Ignoring it.', invalidResolutionName: 'Resolution field $0 does not end with a valid package name and will be ignored', invalidResolutionVersion: 'Resolution field $0 has an invalid version entry and may be ignored', incompatibleResolutionVersion: 'Resolution field $0 is incompatible with requested version $1', - yarnOutdated: "Your current version of Yarn is out of date. The latest version is $0 while you're on $1.", + yarnOutdated: "Your current version of Yarn is out of date. The latest version is $0, while you're on $1.", yarnOutdatedInstaller: 'To upgrade, download the latest installer at $0.', yarnOutdatedCommand: 'To upgrade, run the following command:', @@ -181,9 +182,15 @@ const messages = { workspacesAddRootCheck: 'Running this command will add the dependency to the workspace root rather than workspace itself, which might not be what you want - if you really meant it, make it explicit by running this command again with the -W flag (or --ignore-workspace-root-check).', - workspacesRequirePrivateProjects: 'Workspaces can only be enabled in private projects', + workspacesRequirePrivateProjects: 'Workspaces can only be enabled in private projects.', + workspacesSettingMustBeArray: 'The workspaces field in package.json must be an array.', workspacesDisabled: 'Your project root defines workspaces but the feature is disabled in your Yarn config. Please check "workspaces-experimental" in your .yarnrc file.', + + workspacesNohoistRequirePrivatePackages: + 'nohoist config is ignored in $0 because it is not a private package. If you think nohoist should be allowed in public packages, please submit an issue for your use case.', + workspacesNohoistDisabled: `$0 defines nohoist but the feature is disabled in your Yarn config. Please check "workspaces-nohoist-experimental" in your .yarnrc file.`, + workspaceRootNotFound: "Cannot find the root of your workspace - are you sure you're currently in a workspace?", workspaceMissingWorkspace: 'Missing workspace name.', workspaceMissingCommand: 'Missing command name.', @@ -232,6 +239,8 @@ const messages = { savedNewDependency: 'Saved 1 new dependency.', savedNewDependencies: 'Saved $0 new dependencies.', + directDependencies: 'Direct dependencies', + allDependencies: 'All dependencies', foundWarnings: 'Found $0 warnings.', foundErrors: 'Found $0 errors.', @@ -245,6 +254,7 @@ const messages = { invalidSemver: 'Invalid semver version', newVersion: 'New version', currentVersion: 'Current version', + noVersionOnPublish: 'Proceeding with current version', manualVersionResolution: 'Unable to find a suitable version for $0, please choose one by typing one of the numbers below:', @@ -271,13 +281,17 @@ const messages = { whyHoistedTo: `Has been hoisted to $0`, whyHoistedFromSimple: `This module exists because it's hoisted from $0.`, + whyNotHoistedSimple: `This module exists here because it's in the nohoist list $0.`, whyDependedOnSimple: `This module exists because $0 depends on it.`, whySpecifiedSimple: `This module exists because it's specified in $0.`, whyReasons: 'Reasons this module exists', whyHoistedFrom: 'Hoisted from $0', + whyNotHoisted: `in the nohoist list $0`, whyDependedOn: '$0 depends on it', whySpecified: `Specified in $0`, + whyMatch: `\r=> Found $0`, + uninstalledPackages: 'Uninstalled packages.', uninstallRegenerate: 'Regenerating lockfile and installing missing dependencies', @@ -373,6 +387,7 @@ const messages = { verboseUpgradeBecauseOutdated: 'Considering upgrade of $0 to $1 because a newer version exists in the registry.', verboseUpgradeNotUnlocking: 'Not unlocking $0 in the lockfile because it is a new or direct dependency.', verboseUpgradeUnlocking: 'Unlocking $0 in the lockfile.', + folderMissing: "Directory $0 doesn't exist", }; export type LanguageKeys = $Keys; diff --git a/src/resolvers/exotics/file-resolver.js b/src/resolvers/exotics/file-resolver.js index 1ee891336c..cea7c18dc9 100644 --- a/src/resolvers/exotics/file-resolver.js +++ b/src/resolvers/exotics/file-resolver.js @@ -49,7 +49,7 @@ export default class FileResolver extends ExoticResolver { return manifest; } if (!await fs.exists(loc)) { - throw new MessageError(this.reporter.lang('doesntExist', loc)); + throw new MessageError(this.reporter.lang('doesntExist', loc, this.pattern.split('@')[0])); } const manifest: Manifest = await (async () => { diff --git a/src/resolvers/exotics/hosted-git-resolver.js b/src/resolvers/exotics/hosted-git-resolver.js index 49bc1a436e..d4b68d0c87 100644 --- a/src/resolvers/exotics/hosted-git-resolver.js +++ b/src/resolvers/exotics/hosted-git-resolver.js @@ -55,7 +55,7 @@ export function explodeHostedGitFragment(fragment: string, reporter: Reporter): if (repoParts.length <= 3) { return { user, - repo: repoParts[0].replace('.git', ''), + repo: repoParts[0].replace(/\.git$/, ''), hash: repoParts[1] || '', }; } diff --git a/src/resolvers/exotics/registry-resolver.js b/src/resolvers/exotics/registry-resolver.js index a8c3437e73..f75f673e86 100644 --- a/src/resolvers/exotics/registry-resolver.js +++ b/src/resolvers/exotics/registry-resolver.js @@ -9,7 +9,7 @@ export default class RegistryResolver extends ExoticResolver { constructor(request: PackageRequest, fragment: string) { super(request, fragment); - const match = fragment.match(/^(\S+):(.*?)(@(.*?)|)$/); + const match = fragment.match(/^(\S+):(@?.*?)(@(.*?)|)$/); if (match) { this.range = match[4] || 'latest'; this.name = match[2]; diff --git a/src/types.js b/src/types.js index 63b3a459e2..7d267d1c29 100644 --- a/src/types.js +++ b/src/types.js @@ -48,6 +48,11 @@ type Dependencies = { [key: string]: string, }; +export type WorkspacesConfig = { + packages?: Array, + nohoist?: Array, +}; + // package.json export type Manifest = { _registry?: ?RegistryNames, @@ -68,6 +73,7 @@ export type Manifest = { flat?: boolean, license?: string, licenseText?: string, + noticeText?: string, readme?: string, readmeFilename?: string, @@ -129,7 +135,7 @@ export type Manifest = { files?: Array, main?: string, - workspaces?: Array, + workspaces?: Array | WorkspacesConfig, // This flag is true when we add a new package with `yarn add `. // We need to preserve the flag because we print a list of new packages in diff --git a/src/util/execute-lifecycle-script.js b/src/util/execute-lifecycle-script.js index b89d002355..bacf91bca7 100644 --- a/src/util/execute-lifecycle-script.js +++ b/src/util/execute-lifecycle-script.js @@ -137,6 +137,10 @@ export async function makeEnv( pathParts.unshift( path.join(path.dirname(process.execPath), '..', 'lib', 'node_modules', 'npm', 'bin', 'node-gyp-bin'), ); + // Include node-gyp version from homebrew managed npm, if available. + pathParts.unshift( + path.join(path.dirname(process.execPath), '..', 'libexec', 'lib', 'node_modules', 'npm', 'bin', 'node-gyp-bin'), + ); // Add global bin folder if it is not present already, as some packages depend // on a globally-installed version of node-gyp. @@ -171,6 +175,7 @@ export async function executeLifecycleScript( cwd: string, cmd: string, spinner?: ReporterSpinner, + customShell?: string, ): LifecycleReturn { // if we don't have a spinner then pipe everything to the terminal const stdio = spinner ? undefined : 'inherit'; @@ -180,7 +185,17 @@ export async function executeLifecycleScript( await checkForGypIfNeeded(config, cmd, env[constants.ENV_PATH_KEY].split(path.delimiter)); // get shell - if (process.platform === 'win32') { + let sh = 'sh'; + let shFlag = '-c'; + + let windowsVerbatimArguments = undefined; + + if (customShell) { + sh = customShell; + } else if (process.platform === 'win32') { + sh = process.env.comspec || 'cmd'; + shFlag = '/d /s /c'; + windowsVerbatimArguments = true; // handle windows run scripts starting with a relative path cmd = fixCmdWinSlashes(cmd); } @@ -204,7 +219,7 @@ export async function executeLifecycleScript( } }; } - const stdout = await child.spawn(cmd, [], {shell: true, cwd, env, stdio}, updateProgress); + const stdout = await child.spawn(sh, [shFlag, cmd], {cwd, env, stdio, windowsVerbatimArguments}, updateProgress); return {cwd, command: cmd, stdout}; } @@ -260,11 +275,17 @@ export async function execFromManifest(config: Config, commandName: string, cwd: } } -export async function execCommand(stage: string, config: Config, cmd: string, cwd: string): Promise { +export async function execCommand( + stage: string, + config: Config, + cmd: string, + cwd: string, + customShell?: string, +): Promise { const {reporter} = config; try { reporter.command(cmd); - await executeLifecycleScript(stage, config, cwd, cmd); + await executeLifecycleScript(stage, config, cwd, cmd, undefined, customShell); return Promise.resolve(); } catch (err) { if (err instanceof ProcessTermError) { diff --git a/src/util/git/git-ref-resolver.js b/src/util/git/git-ref-resolver.js index 2c011f2f32..532f9eb555 100644 --- a/src/util/git/git-ref-resolver.js +++ b/src/util/git/git-ref-resolver.js @@ -94,7 +94,7 @@ const tryVersionAsTagSemver = async ( {version, config, refs}: ResolveVersionOptions, names: Names, ): Promise => { - const result = await findSemver(version, config, names.tags); + const result = await findSemver(version.replace(/^semver:/, ''), config, names.tags); return result ? tryRef(refs, `${REF_TAG_PREFIX}${result}`) : null; }; @@ -102,7 +102,7 @@ const tryVersionAsBranchSemver = async ( {version, config, refs}: ResolveVersionOptions, names: Names, ): Promise => { - const result = await findSemver(version, config, names.heads); + const result = await findSemver(version.replace(/^semver:/, ''), config, names.heads); return result ? tryRef(refs, `${REF_BRANCH_PREFIX}${result}`) : null; }; diff --git a/src/util/guess-name.js b/src/util/guess-name.js index a922718412..88352c89df 100644 --- a/src/util/guess-name.js +++ b/src/util/guess-name.js @@ -4,7 +4,7 @@ import url from 'url'; function cleanup(name: string): string { name = name.replace(/-\d+\.\d+\.\d+/, ''); - return name.split('.')[0]; + return name.replace(/\.git$|\.zip$|\.tar\.gz$|\.tar\.bz2$/, ''); } function guessNameFallback(source: string): string { diff --git a/src/util/normalize-manifest/fix.js b/src/util/normalize-manifest/fix.js index 8ce398e6b6..53845efead 100644 --- a/src/util/normalize-manifest/fix.js +++ b/src/util/normalize-manifest/fix.js @@ -308,6 +308,19 @@ export default (async function( } } + // get notice file + const noticeFile = files.find((filename): boolean => { + const lower = filename.toLowerCase(); + return lower === 'notice' || lower.startsWith('notice.'); + }); + if (noticeFile) { + const noticeFilepath = path.join(moduleLoc, noticeFile); + const noticeFileStats = await fs.stat(noticeFilepath); + if (noticeFileStats.isFile()) { + info.noticeText = await fs.readFile(noticeFilepath); + } + } + for (const dependencyType of MANIFEST_FIELDS) { const dependencyList = info[dependencyType]; if (dependencyList && typeof dependencyList === 'object') { diff --git a/yarn.lock b/yarn.lock index e74ecdb1c6..76e5e39bbd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1245,6 +1245,10 @@ builtin-modules@^1.0.0, builtin-modules@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" +builtin-modules@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-2.0.0.tgz#60b7ef5ae6546bd7deefa74b08b62a43a232648e" + builtin-status-codes@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" @@ -1963,7 +1967,7 @@ eslint-plugin-react@^7.1.0: has "^1.0.1" jsx-ast-utils "^1.4.1" -eslint-plugin-relay@0.0.8: +eslint-plugin-relay@^0.0.8: version "0.0.8" resolved "https://registry.yarnpkg.com/eslint-plugin-relay/-/eslint-plugin-relay-0.0.8.tgz#68d99f9fdc518a146bb8aee7519538aa56528dc8" dependencies: @@ -3001,6 +3005,12 @@ is-builtin-module@^1.0.0: dependencies: builtin-modules "^1.0.0" +is-builtin-module@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-2.0.0.tgz#431104b3b4ba838ec7a17d82bb3bccd2233e8cd9" + dependencies: + builtin-modules "^2.0.0" + is-callable@^1.1.1, is-callable@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.3.tgz#86eb75392805ddc33af71c92a0eedf74ee7604b2" @@ -3471,7 +3481,7 @@ jest-validate@^21.2.1: leven "^2.1.0" pretty-format "^21.2.1" -jest@21.2.1: +jest@^21.2.1: version "21.2.1" resolved "https://registry.yarnpkg.com/jest/-/jest-21.2.1.tgz#c964e0b47383768a1438e3ccf3c3d470327604e1" dependencies: