From 71f1419b62beef723e68aaf709f111101cc6234c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Mon, 19 Feb 2018 16:42:57 +0000 Subject: [PATCH 001/111] Initial pnp implementation --- src/cli/commands/install.js | 8 ++ src/package-hoister.js | 13 +- src/package-linker.js | 16 ++- src/util/fs.js | 3 +- src/util/generate-pnp-map.js | 242 +++++++++++++++++++++++++++++++++++ 5 files changed, 271 insertions(+), 11 deletions(-) create mode 100644 src/util/generate-pnp-map.js diff --git a/src/cli/commands/install.js b/src/cli/commands/install.js index 737ca16a5d..b0e3db6fff 100644 --- a/src/cli/commands/install.js +++ b/src/cli/commands/install.js @@ -26,6 +26,7 @@ import {normalizePattern} from '../../util/normalize-pattern.js'; import * as fs from '../../util/fs.js'; import map from '../../util/map.js'; import {version as YARN_VERSION, getInstallationMethod} from '../../util/yarn-version.js'; +import {generatePnpMap} from '../../util/generate-pnp-map.js'; import WorkspaceLayout from '../../workspace-layout.js'; import ResolutionMap from '../../resolution-map.js'; import guessName from '../../util/guess-name'; @@ -575,6 +576,13 @@ export class Install { }), ); + steps.push((curr: number, total: number) => + callThroughHook('pnpStep', async () => { + let code = await generatePnpMap(flattenedTopLevelPatterns, {resolver: this.resolver}); + await fs.writeFile(`${this.config.lockfileFolder}/.pnp.js`, code); + }), + ); + steps.push((curr: number, total: number) => callThroughHook('buildStep', async () => { this.reporter.step( diff --git a/src/package-hoister.js b/src/package-hoister.js index 20ec4aec51..d4e509e2b6 100644 --- a/src/package-hoister.js +++ b/src/package-hoister.js @@ -739,7 +739,7 @@ export class NohoistResolver { * 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 => { @@ -748,13 +748,14 @@ export class NohoistResolver { // private functions _isNohoist = (info: HoistManifest): boolean => { - if (!info.nohoistList || info.nohoistList.length <= 0) { + if (this._isTopPackage(info)) { 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); + if (info.nohoistList && info.nohoistList.length > 0 && mm.any(this._originalPath(info), info.nohoistList)) { + return true; + } + return true; + return false; }; _isRootPackage = (pkg: Manifest): boolean => { return pkg.name === this._wsRootPackageName; diff --git a/src/package-linker.js b/src/package-linker.js index 34269f1bd5..04a3ebe9a4 100644 --- a/src/package-linker.js +++ b/src/package-linker.js @@ -135,6 +135,7 @@ export default class PackageLinker { // write the executables for (const {dep, loc} of deps) { if (dep._reference && dep._reference.location) { + invariant(!pkg._reference.isPlugnplay, "Plug'n'play packages should not be referenced here"); await this.linkSelfDependencies(dep, loc, dir); } } @@ -207,6 +208,12 @@ export default class PackageLinker { } } + if (true) { + ref.isPlugnplay = true; + ref.setLocation(src); + continue; + } + ref.setLocation(dest); const integrityArtifacts = this.artifacts[`${pkg.name}@${pkg.version}`]; @@ -370,6 +377,7 @@ export default class PackageLinker { } }, }); + await fs.hardlinkBulk(Array.from(hardlinkQueue.values()), this.reporter, { possibleExtraneous, artifactFiles, @@ -408,11 +416,11 @@ export default class PackageLinker { await promise.queue( flatTree, async ([dest, {pkg}]) => { - if (pkg._reference && pkg._reference.location) { + if (pkg._reference && pkg._reference.location && !pkg._reference.isPlugnplay) { const binLoc = path.join(dest, this.config.getFolder(pkg)); await this.linkBinDependencies(pkg, binLoc); - tickBin(); } + tickBin(); }, linkBinConcurrency, ); @@ -421,11 +429,11 @@ export default class PackageLinker { await promise.queue( topLevelDependencies, async ([dest, {pkg}]) => { - if (pkg._reference && pkg._reference.location && pkg.bin && Object.keys(pkg.bin).length) { + if (pkg._reference && pkg._reference.location && !pkg._reference.isPlugnplay && pkg.bin && Object.keys(pkg.bin).length) { const binLoc = path.join(this.config.lockfileFolder, this.config.getFolder(pkg)); await this.linkSelfDependencies(pkg, dest, binLoc); - tickBin(); } + tickBin(); }, linkBinConcurrency, ); diff --git a/src/util/fs.js b/src/util/fs.js index a1fb8b117b..8387ff0e32 100644 --- a/src/util/fs.js +++ b/src/util/fs.js @@ -33,7 +33,8 @@ export const rename: (oldPath: string, newPath: string) => Promise = promi export const access: (path: string, mode?: number) => Promise = promisify(fs.access); export const stat: (path: string) => Promise = promisify(fs.stat); export const unlink: (path: string) => Promise = promisify(require('rimraf')); -export const mkdirp: (path: string) => Promise = promisify(require('mkdirp')); +export const mkdirpx: (path: string) => Promise = promisify(require('mkdirp')); +export const mkdirp = async path => await mkdirpx((console.log(path, new Error().stack), path)); export const exists: (path: string) => Promise = promisify(fs.exists, true); export const lstat: (path: string) => Promise = promisify(fs.lstat); export const chmod: (path: string, mode: number | string) => Promise = promisify(fs.chmod); diff --git a/src/util/generate-pnp-map.js b/src/util/generate-pnp-map.js new file mode 100644 index 0000000000..52cd498523 --- /dev/null +++ b/src/util/generate-pnp-map.js @@ -0,0 +1,242 @@ +import * as fs from './fs.js'; + +function generateMaps(packageInformationStores, sharedDependencies) { + + let code = ``; + + // Bake the information stores into our generated code + code += `let packageInformationStores = new Map([\n`; + + for (let [ packageName, packageInformationStore ] of packageInformationStores) { + + code += ` [ ${JSON.stringify(packageName)}, new Map([\n`; + + for (let [ packageReference, { packageLocation, packageDependencies } ] of packageInformationStore) { + + code += ` [ ${JSON.stringify(packageReference)}, {\n`; + code += ` packageLocation: ${JSON.stringify(packageLocation)},\n`; + code += ` packageDependencies: new Map([\n`; + + for (let [ dependencyName, dependencyReference ] of packageDependencies.entries()) + code += ` [ ${JSON.stringify(dependencyName)}, ${JSON.stringify(dependencyReference)} ],\n`; + + code += ` ]),\n`; + code += ` } ],\n`; + + } + + code += ` ]) ],\n`; + + } + + code += `]);\n`; + + // Also bake an inverse map that will allow us to find the package information based on the path + code += `let locatorsByLocations = new Map([\n`; + + for (let [ packageName, packageInformationStore ] of packageInformationStores) + for (let [ packageReference, { packageLocation } ] of packageInformationStore) + code += ` [ ${JSON.stringify(packageLocation)}, ${JSON.stringify({ name: packageName, reference: packageReference })} ],\n`; + + code += `]);\n`; + + // Finally, we bake the shared dependencies (ie those that can explicitely be required by everything else) + code += `let sharedDependencies = new Set([\n`; + + for (let sharedDependency of sharedDependencies) + code += ` ${JSON.stringify(sharedDependency)},\n`; + + code += `]);\n`; + + return code; + +} + +function generateFindPackageLocator(packageInformationStores) { + + let code = ``; + + // We get the list of each string length we'll need to check in order to find the current package context + let lengths = new Map(); + + for (let [ packageName, packageInformationStore ] of packageInformationStores) + for (let [ packageReference, { packageLocation } ] of packageInformationStore) + if (packageLocation !== null) + lengths.set(packageLocation.length, (lengths.get(packageLocation.length) || 0) + 1); + + // We sort those lengths by the number of time they are used, so that the more common ones are tested before the others + let sortedLengths = Array.from(lengths.entries()).sort((a, b) => { + return b[1] - a[1]; + }); + + // Generate a function that, given a file path, returns the associated package name + code += `exports.findPackageLocator = function findPackageLocator(path) {\n`; + code += `\n`; + code += ` let match;\n`; + + for (let [ length, count ] of sortedLengths) + code += ` if (match = locatorsByLocations.get(path.substr(0, ${length}))) return match;\n`; + + code += ` return null;\n`; + code += `};\n`; + + return code; + +} + +function generateGetPackageLocation(packageInformationStores) { + + let code = ``; + + // Generate a function that, given a locator, returns the package location on the disk + + code += `exports.getPackageLocation = function getPackageLocation({ name, reference }) {\n`; + code += `\n`; + code += ` let packageInformationStore, packageInformation;\n`; + code += `\n`; + code += ` if (packageInformationStore = packageInformationStores.get(name))\n`; + code += ` if (packageInformation = packageInformationStore.get(reference))\n`; + code += ` return packageInformation.packageLocation;\n`; + code += `\n`; + code += ` return null;\n`; + code += `\n`; + code += `};\n`; + + return code; + +} + +function generateGetPackageDependencies(packageInformationStores) { + + let code = ``; + + // Generate a function that, given a locator, returns the package dependencies + + code += `exports.getPackageDependencies = function getPackageDependencies({ name, reference }) {\n`; + code += `\n`; + code += ` let packageInformationStore, packageInformation;\n`; + code += `\n`; + code += ` if (packageInformationStore = packageInformationStores.get(name))\n`; + code += ` if (packageInformation = packageInformationStore.get(reference))\n`; + code += ` return packageInformation.packageDependencies;\n`; + code += `\n`; + code += ` return null;\n`; + code += `};\n`; + + return code; + +} + +const REQUIRE_HOOK = ` +let Module = require(\`module\`); + +let originalResolver = Module._resolveFilename; +let pathRegExp = /^(?!\\.{0,2}\\/)([^\\/]+)(\\/.*|)$/; + +Module._resolveFilename = function (request, parent, isMain, options) { + + if (Module.builtinModules.includes(request)) + return request; + + let dependencyNameMatch = request.match(pathRegExp); + + if (!dependencyNameMatch) + return originalResolver.call(Module, request, parent, isMain, options); + + let packagePath = parent.filename ? parent.filename : process.cwd(); + let packageLocator = parent.filename ? exports.findPackageLocator(packagePath) : { name: null, reference: null }; + + if (!packageLocator) + throw new Error(\`Could not find to which package belongs the path \${packagePath}\`); + + let packageDependencies = exports.getPackageDependencies(packageLocator); + + let [ , dependencyName, subPath ] = dependencyNameMatch; + let dependencyReference = packageDependencies.get(dependencyName); + + if (!dependencyReference && sharedDependencies.has(dependencyName)) + dependencyReference = exports.getPackageDependencies({ name: null, reference: null }).get(dependencyName); + + if (!dependencyReference) { + if (packageLocator.name === null) { + throw new Error(\`You cannot require a package (\${dependencyName}) that is not declared in your dependencies\`); + } else { + throw new Error(\`Package \${packageLocator.name}@\${packageLocator.reference} is trying to require package \${dependencyName}, which is not declared in its dependencies (\${Array.from(packageDependencies.keys()).join(\`, \`)})\`); + } + } + + let dependencyLocation = exports.getPackageLocation({ name: dependencyName, reference: dependencyReference }); + + return originalResolver.call(Module, \`\${dependencyLocation}/\${subPath}\`, parent, isMain, options); + +}; +`; + +async function getPackageInformationStores(seedPatterns, {resolver}) { + + // We'll need to convert the map of locator=>location into a two-level map of name=>reference=>location (because we won't use Immutable.js, so objects can't be keys) + let packageInformationStores = new Map(); + + const pkgs = resolver.getTopologicalManifests(seedPatterns); + + for (const pkg of pkgs) { + if (pkg._reference && pkg._reference.isPlugnplay) { + let packageInformationStore = packageInformationStores.get(pkg.name); + + if (!packageInformationStore) { + packageInformationStores.set(pkg.name, packageInformationStore = new Map()); + } + + let packageDependencies = new Map(); + + for (const pattern of pkg._reference.dependencies) { + const dep = resolver.getStrictResolvedPattern(pattern); + packageDependencies.set(dep.name, dep.version); + } + + packageInformationStore.set(pkg.version, { + packageLocation: await fs.realpath(pkg._reference.location), + packageDependencies, + }); + } + } + + // Top-level package + if (true) { + let topLevelDependencies = new Map(); + + for (const pattern of seedPatterns) { + const dep = resolver.getStrictResolvedPattern(pattern); + topLevelDependencies.set(dep.name, dep.version); + } + + packageInformationStores.set(null, new Map([ + [ null, { + packageLocation: null, + packageDependencies: topLevelDependencies, + } ], + ])); + } + + return packageInformationStores; + +} + +export async function generatePnpMap(seedPatterns, {resolver}) { + + let packageInformationStores = await getPackageInformationStores(seedPatterns, {resolver}); + let sharedDependencies = new Set(); + + let code = ``; + + code += generateMaps(packageInformationStores, sharedDependencies); + + code += generateFindPackageLocator(packageInformationStores); + code += generateGetPackageLocation(packageInformationStores); + code += generateGetPackageDependencies(packageInformationStores); + + code += REQUIRE_HOOK; + + return code; + +} From b942722f2ae1bb1430b36738f94672fcd40d2712 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Mon, 19 Feb 2018 16:48:57 +0000 Subject: [PATCH 002/111] Adds the pnp-env directory for quick checks --- pnp-env/.gitignore | 3 + pnp-env/.yarnrc | 1 + pnp-env/package.json | 10 + pnp-env/yarn.lock | 2716 ++++++++++++++++++++++++++++++++++ src/cli/commands/install.js | 2 +- src/config.js | 4 + src/package-hoister.js | 4 +- src/package-linker.js | 12 +- src/package-reference.js | 3 + src/util/fs.js | 3 +- src/util/generate-pnp-map.js | 288 ++-- src/util/hooks.js | 2 +- 12 files changed, 2898 insertions(+), 150 deletions(-) create mode 100644 pnp-env/.gitignore create mode 100644 pnp-env/.yarnrc create mode 100644 pnp-env/package.json create mode 100644 pnp-env/yarn.lock diff --git a/pnp-env/.gitignore b/pnp-env/.gitignore new file mode 100644 index 0000000000..4f513c2e2c --- /dev/null +++ b/pnp-env/.gitignore @@ -0,0 +1,3 @@ +node_modules +yarn-error.log +.pnp.js diff --git a/pnp-env/.yarnrc b/pnp-env/.yarnrc new file mode 100644 index 0000000000..26211b285f --- /dev/null +++ b/pnp-env/.yarnrc @@ -0,0 +1 @@ +plugnplay-experimental true diff --git a/pnp-env/package.json b/pnp-env/package.json new file mode 100644 index 0000000000..803ca5078d --- /dev/null +++ b/pnp-env/package.json @@ -0,0 +1,10 @@ +{ + "dependencies": { + "babel-core": "^6.26.0", + "babel-preset-env": "^1.6.1", + "lodash": "^4.17.5", + "react": "^16.2.0", + "react-dom": "^16.2.0", + "webpack": "^3.11.0" + } +} diff --git a/pnp-env/yarn.lock b/pnp-env/yarn.lock new file mode 100644 index 0000000000..6eddbcf761 --- /dev/null +++ b/pnp-env/yarn.lock @@ -0,0 +1,2716 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +abbrev@1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" + +acorn-dynamic-import@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/acorn-dynamic-import/-/acorn-dynamic-import-2.0.2.tgz#c752bd210bef679501b6c6cb7fc84f8f47158cc4" + dependencies: + acorn "^4.0.3" + +acorn@^4.0.3: + version "4.0.13" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.13.tgz#105495ae5361d697bd195c825192e1ad7f253787" + +acorn@^5.0.0: + version "5.4.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.4.1.tgz#fdc58d9d17f4a4e98d102ded826a9b9759125102" + +ajv-keywords@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.1.0.tgz#ac2b27939c543e95d2c06e7f7f5c27be4aa543be" + +ajv@^4.9.1: + version "4.11.8" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536" + dependencies: + co "^4.6.0" + json-stable-stringify "^1.0.1" + +ajv@^6.1.0: + version "6.1.1" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.1.1.tgz#978d597fbc2b7d0e5a5c3ddeb149a682f2abfa0e" + dependencies: + fast-deep-equal "^1.0.0" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.3.0" + +align-text@^0.1.1, align-text@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117" + dependencies: + kind-of "^3.0.2" + longest "^1.0.1" + repeat-string "^1.5.2" + +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + +ansi-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" + +ansi-styles@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" + +anymatch@^1.3.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.2.tgz#553dcb8f91e3c889845dfdba34c77721b90b9d7a" + dependencies: + micromatch "^2.1.5" + normalize-path "^2.0.0" + +aproba@^1.0.3: + version "1.2.0" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" + +are-we-there-yet@~1.1.2: + version "1.1.4" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz#bb5dca382bb94f05e15194373d16fd3ba1ca110d" + dependencies: + delegates "^1.0.0" + readable-stream "^2.0.6" + +arr-diff@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" + dependencies: + arr-flatten "^1.0.1" + +arr-flatten@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" + +array-unique@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" + +asap@~2.0.3: + version "2.0.6" + resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" + +asn1.js@^4.0.0: + version "4.10.1" + resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.10.1.tgz#b9c2bf5805f1e64aadeed6df3a2bfafb5a73f5a0" + dependencies: + bn.js "^4.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + +asn1@~0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" + +assert-plus@1.0.0, assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + +assert-plus@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234" + +assert@^1.1.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/assert/-/assert-1.4.1.tgz#99912d591836b5a6f5b345c0f07eefc08fc65d91" + dependencies: + util "0.10.3" + +async-each@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" + +async@^2.1.2: + version "2.6.0" + resolved "https://registry.yarnpkg.com/async/-/async-2.6.0.tgz#61a29abb6fcc026fea77e56d1c6ec53a795951f4" + dependencies: + lodash "^4.14.0" + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + +aws-sign2@~0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" + +aws4@^1.2.1: + version "1.6.0" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e" + +babel-code-frame@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" + dependencies: + chalk "^1.1.3" + esutils "^2.0.2" + js-tokens "^3.0.2" + +babel-core@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.26.0.tgz#af32f78b31a6fcef119c87b0fd8d9753f03a0bb8" + dependencies: + babel-code-frame "^6.26.0" + babel-generator "^6.26.0" + babel-helpers "^6.24.1" + babel-messages "^6.23.0" + babel-register "^6.26.0" + babel-runtime "^6.26.0" + babel-template "^6.26.0" + babel-traverse "^6.26.0" + babel-types "^6.26.0" + babylon "^6.18.0" + convert-source-map "^1.5.0" + debug "^2.6.8" + json5 "^0.5.1" + lodash "^4.17.4" + minimatch "^3.0.4" + path-is-absolute "^1.0.1" + private "^0.1.7" + slash "^1.0.0" + source-map "^0.5.6" + +babel-generator@^6.26.0: + version "6.26.1" + resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.26.1.tgz#1844408d3b8f0d35a404ea7ac180f087a601bd90" + dependencies: + babel-messages "^6.23.0" + babel-runtime "^6.26.0" + babel-types "^6.26.0" + detect-indent "^4.0.0" + jsesc "^1.3.0" + lodash "^4.17.4" + source-map "^0.5.7" + trim-right "^1.0.1" + +babel-helper-builder-binary-assignment-operator-visitor@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz#cce4517ada356f4220bcae8a02c2b346f9a56664" + dependencies: + babel-helper-explode-assignable-expression "^6.24.1" + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-helper-call-delegate@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz#ece6aacddc76e41c3461f88bfc575bd0daa2df8d" + dependencies: + babel-helper-hoist-variables "^6.24.1" + babel-runtime "^6.22.0" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-define-map@^6.24.1: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz#a5f56dab41a25f97ecb498c7ebaca9819f95be5f" + dependencies: + babel-helper-function-name "^6.24.1" + babel-runtime "^6.26.0" + babel-types "^6.26.0" + lodash "^4.17.4" + +babel-helper-explode-assignable-expression@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz#f25b82cf7dc10433c55f70592d5746400ac22caa" + dependencies: + babel-runtime "^6.22.0" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-function-name@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz#d3475b8c03ed98242a25b48351ab18399d3580a9" + dependencies: + babel-helper-get-function-arity "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-get-function-arity@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz#8f7782aa93407c41d3aa50908f89b031b1b6853d" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-helper-hoist-variables@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz#1ecb27689c9d25513eadbc9914a73f5408be7a76" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-helper-optimise-call-expression@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz#f7a13427ba9f73f8f4fa993c54a97882d1244257" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-helper-regex@^6.24.1: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz#325c59f902f82f24b74faceed0363954f6495e72" + dependencies: + babel-runtime "^6.26.0" + babel-types "^6.26.0" + lodash "^4.17.4" + +babel-helper-remap-async-to-generator@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz#5ec581827ad723fecdd381f1c928390676e4551b" + dependencies: + babel-helper-function-name "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-replace-supers@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz#bf6dbfe43938d17369a213ca8a8bf74b6a90ab1a" + dependencies: + babel-helper-optimise-call-expression "^6.24.1" + babel-messages "^6.23.0" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helpers@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.24.1.tgz#3471de9caec388e5c850e597e58a26ddf37602b2" + dependencies: + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-messages@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-check-es2015-constants@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz#35157b101426fd2ffd3da3f75c7d1e91835bbf8a" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-syntax-async-functions@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95" + +babel-plugin-syntax-exponentiation-operator@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de" + +babel-plugin-syntax-trailing-function-commas@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz#ba0360937f8d06e40180a43fe0d5616fff532cf3" + +babel-plugin-transform-async-to-generator@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz#6536e378aff6cb1d5517ac0e40eb3e9fc8d08761" + dependencies: + babel-helper-remap-async-to-generator "^6.24.1" + babel-plugin-syntax-async-functions "^6.8.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-arrow-functions@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz#452692cb711d5f79dc7f85e440ce41b9f244d221" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-block-scoped-functions@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz#bbc51b49f964d70cb8d8e0b94e820246ce3a6141" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-block-scoping@^6.23.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz#d70f5299c1308d05c12f463813b0a09e73b1895f" + dependencies: + babel-runtime "^6.26.0" + babel-template "^6.26.0" + babel-traverse "^6.26.0" + babel-types "^6.26.0" + lodash "^4.17.4" + +babel-plugin-transform-es2015-classes@^6.23.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz#5a4c58a50c9c9461e564b4b2a3bfabc97a2584db" + dependencies: + babel-helper-define-map "^6.24.1" + babel-helper-function-name "^6.24.1" + babel-helper-optimise-call-expression "^6.24.1" + babel-helper-replace-supers "^6.24.1" + babel-messages "^6.23.0" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-computed-properties@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz#6fe2a8d16895d5634f4cd999b6d3480a308159b3" + dependencies: + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-es2015-destructuring@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz#997bb1f1ab967f682d2b0876fe358d60e765c56d" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-duplicate-keys@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz#73eb3d310ca969e3ef9ec91c53741a6f1576423e" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-for-of@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz#f47c95b2b613df1d3ecc2fdb7573623c75248691" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-function-name@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz#834c89853bc36b1af0f3a4c5dbaa94fd8eacaa8b" + dependencies: + babel-helper-function-name "^6.24.1" + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-literals@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz#4f54a02d6cd66cf915280019a31d31925377ca2e" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-modules-amd@^6.22.0, babel-plugin-transform-es2015-modules-amd@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz#3b3e54017239842d6d19c3011c4bd2f00a00d154" + dependencies: + babel-plugin-transform-es2015-modules-commonjs "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-es2015-modules-commonjs@^6.23.0, babel-plugin-transform-es2015-modules-commonjs@^6.24.1: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.0.tgz#0d8394029b7dc6abe1a97ef181e00758dd2e5d8a" + dependencies: + babel-plugin-transform-strict-mode "^6.24.1" + babel-runtime "^6.26.0" + babel-template "^6.26.0" + babel-types "^6.26.0" + +babel-plugin-transform-es2015-modules-systemjs@^6.23.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz#ff89a142b9119a906195f5f106ecf305d9407d23" + dependencies: + babel-helper-hoist-variables "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-es2015-modules-umd@^6.23.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz#ac997e6285cd18ed6176adb607d602344ad38468" + dependencies: + babel-plugin-transform-es2015-modules-amd "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-es2015-object-super@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz#24cef69ae21cb83a7f8603dad021f572eb278f8d" + dependencies: + babel-helper-replace-supers "^6.24.1" + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-parameters@^6.23.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz#57ac351ab49caf14a97cd13b09f66fdf0a625f2b" + dependencies: + babel-helper-call-delegate "^6.24.1" + babel-helper-get-function-arity "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-shorthand-properties@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz#24f875d6721c87661bbd99a4622e51f14de38aa0" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-spread@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz#d6d68a99f89aedc4536c81a542e8dd9f1746f8d1" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-sticky-regex@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz#00c1cdb1aca71112cdf0cf6126c2ed6b457ccdbc" + dependencies: + babel-helper-regex "^6.24.1" + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-template-literals@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz#a84b3450f7e9f8f1f6839d6d687da84bb1236d8d" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-typeof-symbol@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz#dec09f1cddff94b52ac73d505c84df59dcceb372" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-unicode-regex@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz#d38b12f42ea7323f729387f18a7c5ae1faeb35e9" + dependencies: + babel-helper-regex "^6.24.1" + babel-runtime "^6.22.0" + regexpu-core "^2.0.0" + +babel-plugin-transform-exponentiation-operator@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz#2ab0c9c7f3098fa48907772bb813fe41e8de3a0e" + dependencies: + babel-helper-builder-binary-assignment-operator-visitor "^6.24.1" + babel-plugin-syntax-exponentiation-operator "^6.8.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-regenerator@^6.22.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz#e0703696fbde27f0a3efcacf8b4dca2f7b3a8f2f" + dependencies: + regenerator-transform "^0.10.0" + +babel-plugin-transform-strict-mode@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz#d5faf7aa578a65bbe591cf5edae04a0c67020758" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-preset-env@^1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/babel-preset-env/-/babel-preset-env-1.6.1.tgz#a18b564cc9b9afdf4aae57ae3c1b0d99188e6f48" + dependencies: + babel-plugin-check-es2015-constants "^6.22.0" + babel-plugin-syntax-trailing-function-commas "^6.22.0" + babel-plugin-transform-async-to-generator "^6.22.0" + babel-plugin-transform-es2015-arrow-functions "^6.22.0" + babel-plugin-transform-es2015-block-scoped-functions "^6.22.0" + babel-plugin-transform-es2015-block-scoping "^6.23.0" + babel-plugin-transform-es2015-classes "^6.23.0" + babel-plugin-transform-es2015-computed-properties "^6.22.0" + babel-plugin-transform-es2015-destructuring "^6.23.0" + babel-plugin-transform-es2015-duplicate-keys "^6.22.0" + babel-plugin-transform-es2015-for-of "^6.23.0" + babel-plugin-transform-es2015-function-name "^6.22.0" + babel-plugin-transform-es2015-literals "^6.22.0" + babel-plugin-transform-es2015-modules-amd "^6.22.0" + babel-plugin-transform-es2015-modules-commonjs "^6.23.0" + babel-plugin-transform-es2015-modules-systemjs "^6.23.0" + babel-plugin-transform-es2015-modules-umd "^6.23.0" + babel-plugin-transform-es2015-object-super "^6.22.0" + babel-plugin-transform-es2015-parameters "^6.23.0" + babel-plugin-transform-es2015-shorthand-properties "^6.22.0" + babel-plugin-transform-es2015-spread "^6.22.0" + babel-plugin-transform-es2015-sticky-regex "^6.22.0" + babel-plugin-transform-es2015-template-literals "^6.22.0" + babel-plugin-transform-es2015-typeof-symbol "^6.23.0" + babel-plugin-transform-es2015-unicode-regex "^6.22.0" + babel-plugin-transform-exponentiation-operator "^6.22.0" + babel-plugin-transform-regenerator "^6.22.0" + browserslist "^2.1.2" + invariant "^2.2.2" + semver "^5.3.0" + +babel-register@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.26.0.tgz#6ed021173e2fcb486d7acb45c6009a856f647071" + dependencies: + babel-core "^6.26.0" + babel-runtime "^6.26.0" + core-js "^2.5.0" + home-or-tmp "^2.0.0" + lodash "^4.17.4" + mkdirp "^0.5.1" + source-map-support "^0.4.15" + +babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" + dependencies: + core-js "^2.4.0" + regenerator-runtime "^0.11.0" + +babel-template@^6.24.1, babel-template@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.26.0.tgz#de03e2d16396b069f46dd9fff8521fb1a0e35e02" + dependencies: + babel-runtime "^6.26.0" + babel-traverse "^6.26.0" + babel-types "^6.26.0" + babylon "^6.18.0" + lodash "^4.17.4" + +babel-traverse@^6.24.1, babel-traverse@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee" + dependencies: + babel-code-frame "^6.26.0" + babel-messages "^6.23.0" + babel-runtime "^6.26.0" + babel-types "^6.26.0" + babylon "^6.18.0" + debug "^2.6.8" + globals "^9.18.0" + invariant "^2.2.2" + lodash "^4.17.4" + +babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497" + dependencies: + babel-runtime "^6.26.0" + esutils "^2.0.2" + lodash "^4.17.4" + to-fast-properties "^1.0.3" + +babylon@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" + +balanced-match@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + +base64-js@^1.0.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.3.tgz#fb13668233d9614cf5fb4bce95a9ba4096cdf801" + +bcrypt-pbkdf@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d" + dependencies: + tweetnacl "^0.14.3" + +big.js@^3.1.3: + version "3.2.0" + resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.2.0.tgz#a5fc298b81b9e0dca2e458824784b65c52ba588e" + +binary-extensions@^1.0.0: + version "1.11.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.11.0.tgz#46aa1751fb6a2f93ee5e689bb1087d4b14c6c205" + +block-stream@*: + version "0.0.9" + resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" + dependencies: + inherits "~2.0.0" + +bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0: + version "4.11.8" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" + +boom@2.x.x: + version "2.10.1" + resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f" + dependencies: + hoek "2.x.x" + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@^1.8.2: + version "1.8.5" + resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" + dependencies: + expand-range "^1.8.1" + preserve "^0.2.0" + repeat-element "^1.1.2" + +brorand@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" + +browserify-aes@^1.0.0, browserify-aes@^1.0.4: + version "1.1.1" + resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.1.1.tgz#38b7ab55edb806ff2dcda1a7f1620773a477c49f" + dependencies: + buffer-xor "^1.0.3" + cipher-base "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.3" + inherits "^2.0.1" + safe-buffer "^5.0.1" + +browserify-cipher@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.0.tgz#9988244874bf5ed4e28da95666dcd66ac8fc363a" + dependencies: + browserify-aes "^1.0.4" + browserify-des "^1.0.0" + evp_bytestokey "^1.0.0" + +browserify-des@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.0.tgz#daa277717470922ed2fe18594118a175439721dd" + dependencies: + cipher-base "^1.0.1" + des.js "^1.0.0" + inherits "^2.0.1" + +browserify-rsa@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.0.1.tgz#21e0abfaf6f2029cf2fafb133567a701d4135524" + dependencies: + bn.js "^4.1.0" + randombytes "^2.0.1" + +browserify-sign@^4.0.0: + version "4.0.4" + resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.0.4.tgz#aa4eb68e5d7b658baa6bf6a57e630cbd7a93d298" + dependencies: + bn.js "^4.1.1" + browserify-rsa "^4.0.0" + create-hash "^1.1.0" + create-hmac "^1.1.2" + elliptic "^6.0.0" + inherits "^2.0.1" + parse-asn1 "^5.0.0" + +browserify-zlib@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.2.0.tgz#2869459d9aa3be245fe8fe2ca1f46e2e7f54d73f" + dependencies: + pako "~1.0.5" + +browserslist@^2.1.2: + version "2.11.3" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-2.11.3.tgz#fe36167aed1bbcde4827ebfe71347a2cc70b99b2" + dependencies: + caniuse-lite "^1.0.30000792" + electron-to-chromium "^1.3.30" + +buffer-xor@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" + +buffer@^4.3.0: + version "4.9.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298" + dependencies: + base64-js "^1.0.2" + ieee754 "^1.1.4" + isarray "^1.0.0" + +builtin-modules@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" + +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" + +camelcase@^1.0.2: + version "1.2.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39" + +camelcase@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" + +caniuse-lite@^1.0.30000792: + version "1.0.30000809" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000809.tgz#1e12c1344b8f74d56737ee2614bcedb648943479" + +caseless@~0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" + +center-align@^0.1.1: + version "0.1.3" + resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad" + dependencies: + align-text "^0.1.3" + lazy-cache "^1.0.3" + +chalk@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" + dependencies: + ansi-styles "^2.2.1" + escape-string-regexp "^1.0.2" + has-ansi "^2.0.0" + strip-ansi "^3.0.0" + supports-color "^2.0.0" + +chokidar@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468" + dependencies: + anymatch "^1.3.0" + async-each "^1.0.0" + glob-parent "^2.0.0" + inherits "^2.0.1" + is-binary-path "^1.0.0" + is-glob "^2.0.0" + path-is-absolute "^1.0.0" + readdirp "^2.0.0" + optionalDependencies: + fsevents "^1.0.0" + +cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +cliui@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1" + dependencies: + center-align "^0.1.1" + right-align "^0.1.1" + wordwrap "0.0.2" + +cliui@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + wrap-ansi "^2.0.0" + +co@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + +code-point-at@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + +combined-stream@^1.0.5, combined-stream@~1.0.5: + version "1.0.6" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.6.tgz#723e7df6e801ac5613113a7e445a9b69cb632818" + dependencies: + delayed-stream "~1.0.0" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + +console-browserify@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10" + dependencies: + date-now "^0.1.4" + +console-control-strings@^1.0.0, console-control-strings@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + +constants-browserify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" + +convert-source-map@^1.5.0: + version "1.5.1" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.1.tgz#b8278097b9bc229365de5c62cf5fcaed8b5599e5" + +core-js@^1.0.0: + version "1.2.7" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" + +core-js@^2.4.0, core-js@^2.5.0: + version "2.5.3" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.3.tgz#8acc38345824f16d8365b7c9b4259168e8ed603e" + +core-util-is@1.0.2, core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + +create-ecdh@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.0.tgz#888c723596cdf7612f6498233eebd7a35301737d" + dependencies: + bn.js "^4.1.0" + elliptic "^6.0.0" + +create-hash@^1.1.0, create-hash@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.1.3.tgz#606042ac8b9262750f483caddab0f5819172d8fd" + dependencies: + cipher-base "^1.0.1" + inherits "^2.0.1" + ripemd160 "^2.0.0" + sha.js "^2.4.0" + +create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4: + version "1.1.6" + resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.6.tgz#acb9e221a4e17bdb076e90657c42b93e3726cf06" + dependencies: + cipher-base "^1.0.3" + create-hash "^1.1.0" + inherits "^2.0.1" + ripemd160 "^2.0.0" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +cross-spawn@^5.0.1: + version "5.1.0" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" + dependencies: + lru-cache "^4.0.1" + shebang-command "^1.2.0" + which "^1.2.9" + +cryptiles@2.x.x: + version "2.0.5" + resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8" + dependencies: + boom "2.x.x" + +crypto-browserify@^3.11.0: + version "3.12.0" + resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" + dependencies: + browserify-cipher "^1.0.0" + browserify-sign "^4.0.0" + create-ecdh "^4.0.0" + create-hash "^1.1.0" + create-hmac "^1.1.0" + diffie-hellman "^5.0.0" + inherits "^2.0.1" + pbkdf2 "^3.0.3" + public-encrypt "^4.0.0" + randombytes "^2.0.0" + randomfill "^1.0.3" + +d@1: + version "1.0.0" + resolved "https://registry.yarnpkg.com/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f" + dependencies: + es5-ext "^0.10.9" + +dashdash@^1.12.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + dependencies: + assert-plus "^1.0.0" + +date-now@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b" + +debug@^2.2.0, debug@^2.6.8: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + dependencies: + ms "2.0.0" + +decamelize@^1.0.0, decamelize@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + +deep-extend@~0.4.0: + version "0.4.2" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.2.tgz#48b699c27e334bf89f10892be432f6e4c7d34a7f" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + +des.js@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.0.tgz#c074d2e2aa6a8a9a07dbd61f9a15c2cd83ec8ecc" + dependencies: + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + +detect-indent@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" + dependencies: + repeating "^2.0.0" + +detect-libc@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" + +diffie-hellman@^5.0.0: + version "5.0.2" + resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.2.tgz#b5835739270cfe26acf632099fded2a07f209e5e" + dependencies: + bn.js "^4.1.0" + miller-rabin "^4.0.0" + randombytes "^2.0.0" + +domain-browser@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda" + +ecc-jsbn@~0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505" + dependencies: + jsbn "~0.1.0" + +electron-to-chromium@^1.3.30: + version "1.3.33" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.33.tgz#bf00703d62a7c65238136578c352d6c5c042a545" + +elliptic@^6.0.0: + version "6.4.0" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.4.0.tgz#cac9af8762c85836187003c8dfe193e5e2eae5df" + dependencies: + bn.js "^4.4.0" + brorand "^1.0.1" + hash.js "^1.0.0" + hmac-drbg "^1.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.0" + +emojis-list@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" + +encoding@^0.1.11: + version "0.1.12" + resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" + dependencies: + iconv-lite "~0.4.13" + +enhanced-resolve@^3.4.0: + version "3.4.1" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-3.4.1.tgz#0421e339fd71419b3da13d129b3979040230476e" + dependencies: + graceful-fs "^4.1.2" + memory-fs "^0.4.0" + object-assign "^4.0.1" + tapable "^0.2.7" + +errno@^0.1.3: + version "0.1.7" + resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618" + dependencies: + prr "~1.0.1" + +error-ex@^1.2.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.1.tgz#f855a86ce61adc4e8621c3cda21e7a7612c3a8dc" + dependencies: + is-arrayish "^0.2.1" + +es5-ext@^0.10.14, es5-ext@^0.10.35, es5-ext@^0.10.9, es5-ext@~0.10.14: + version "0.10.39" + resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.39.tgz#fca21b67559277ca4ac1a1ed7048b107b6f76d87" + dependencies: + es6-iterator "~2.0.3" + es6-symbol "~3.1.1" + +es6-iterator@^2.0.1, es6-iterator@~2.0.1, es6-iterator@~2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7" + dependencies: + d "1" + es5-ext "^0.10.35" + es6-symbol "^3.1.1" + +es6-map@^0.1.3: + version "0.1.5" + resolved "https://registry.yarnpkg.com/es6-map/-/es6-map-0.1.5.tgz#9136e0503dcc06a301690f0bb14ff4e364e949f0" + dependencies: + d "1" + es5-ext "~0.10.14" + es6-iterator "~2.0.1" + es6-set "~0.1.5" + es6-symbol "~3.1.1" + event-emitter "~0.3.5" + +es6-set@~0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/es6-set/-/es6-set-0.1.5.tgz#d2b3ec5d4d800ced818db538d28974db0a73ccb1" + dependencies: + d "1" + es5-ext "~0.10.14" + es6-iterator "~2.0.1" + es6-symbol "3.1.1" + event-emitter "~0.3.5" + +es6-symbol@3.1.1, es6-symbol@^3.1.1, es6-symbol@~3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.1.tgz#bf00ef4fdab6ba1b46ecb7b629b4c7ed5715cc77" + dependencies: + d "1" + es5-ext "~0.10.14" + +es6-weak-map@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/es6-weak-map/-/es6-weak-map-2.0.2.tgz#5e3ab32251ffd1538a1f8e5ffa1357772f92d96f" + dependencies: + d "1" + es5-ext "^0.10.14" + es6-iterator "^2.0.1" + es6-symbol "^3.1.1" + +escape-string-regexp@^1.0.2: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + +escope@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/escope/-/escope-3.6.0.tgz#e01975e812781a163a6dadfdd80398dc64c889c3" + dependencies: + es6-map "^0.1.3" + es6-weak-map "^2.0.1" + esrecurse "^4.1.0" + estraverse "^4.1.1" + +esrecurse@^4.1.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.0.tgz#fa9568d98d3823f9a41d91e902dcab9ea6e5b163" + dependencies: + estraverse "^4.1.0" + object-assign "^4.0.1" + +estraverse@^4.1.0, estraverse@^4.1.1: + version "4.2.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" + +esutils@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" + +event-emitter@~0.3.5: + version "0.3.5" + resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39" + dependencies: + d "1" + es5-ext "~0.10.14" + +events@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" + +evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" + dependencies: + md5.js "^1.3.4" + safe-buffer "^5.1.1" + +execa@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777" + dependencies: + cross-spawn "^5.0.1" + get-stream "^3.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + +expand-brackets@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" + dependencies: + is-posix-bracket "^0.1.0" + +expand-range@^1.8.1: + version "1.8.2" + resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" + dependencies: + fill-range "^2.1.0" + +extend@~3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" + +extglob@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" + dependencies: + is-extglob "^1.0.0" + +extsprintf@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" + +extsprintf@^1.2.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" + +fast-deep-equal@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz#96256a3bc975595eb36d82e9929d060d893439ff" + +fast-json-stable-stringify@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" + +fbjs@^0.8.16: + version "0.8.16" + resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.16.tgz#5e67432f550dc41b572bf55847b8aca64e5337db" + dependencies: + core-js "^1.0.0" + isomorphic-fetch "^2.1.1" + loose-envify "^1.0.0" + object-assign "^4.1.0" + promise "^7.1.1" + setimmediate "^1.0.5" + ua-parser-js "^0.7.9" + +filename-regex@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" + +fill-range@^2.1.0: + version "2.2.3" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723" + dependencies: + is-number "^2.1.0" + isobject "^2.0.0" + randomatic "^1.1.3" + repeat-element "^1.1.2" + repeat-string "^1.5.2" + +find-up@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" + dependencies: + locate-path "^2.0.0" + +for-in@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" + +for-own@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce" + dependencies: + for-in "^1.0.1" + +forever-agent@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + +form-data@~2.1.1: + version "2.1.4" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.4.tgz#33c183acf193276ecaa98143a69e94bfee1750d1" + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.5" + mime-types "^2.1.12" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + +fsevents@^1.0.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.1.3.tgz#11f82318f5fe7bb2cd22965a108e9306208216d8" + dependencies: + nan "^2.3.0" + node-pre-gyp "^0.6.39" + +fstream-ignore@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/fstream-ignore/-/fstream-ignore-1.0.5.tgz#9c31dae34767018fe1d249b24dada67d092da105" + dependencies: + fstream "^1.0.0" + inherits "2" + minimatch "^3.0.0" + +fstream@^1.0.0, fstream@^1.0.10, fstream@^1.0.2: + version "1.0.11" + resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171" + dependencies: + graceful-fs "^4.1.2" + inherits "~2.0.0" + mkdirp ">=0.5 0" + rimraf "2" + +gauge@~2.7.3: + version "2.7.4" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" + dependencies: + aproba "^1.0.3" + console-control-strings "^1.0.0" + has-unicode "^2.0.0" + object-assign "^4.1.0" + signal-exit "^3.0.0" + string-width "^1.0.1" + strip-ansi "^3.0.1" + wide-align "^1.1.0" + +get-caller-file@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5" + +get-stream@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" + +getpass@^0.1.1: + version "0.1.7" + resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" + dependencies: + assert-plus "^1.0.0" + +glob-base@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" + dependencies: + glob-parent "^2.0.0" + is-glob "^2.0.0" + +glob-parent@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" + dependencies: + is-glob "^2.0.0" + +glob@^7.0.5: + version "7.1.2" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +globals@^9.18.0: + version "9.18.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" + +graceful-fs@^4.1.2: + version "4.1.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" + +har-schema@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-1.0.5.tgz#d263135f43307c02c602afc8fe95970c0151369e" + +har-validator@~4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-4.2.1.tgz#33481d0f1bbff600dd203d75812a6a5fba002e2a" + dependencies: + ajv "^4.9.1" + har-schema "^1.0.5" + +has-ansi@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" + dependencies: + ansi-regex "^2.0.0" + +has-flag@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51" + +has-unicode@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + +hash-base@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-2.0.2.tgz#66ea1d856db4e8a5470cadf6fce23ae5244ef2e1" + dependencies: + inherits "^2.0.1" + +hash-base@^3.0.0: + version "3.0.4" + resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.0.4.tgz#5fc8686847ecd73499403319a6b0a3f3f6ae4918" + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +hash.js@^1.0.0, hash.js@^1.0.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.3.tgz#340dedbe6290187151c1ea1d777a3448935df846" + dependencies: + inherits "^2.0.3" + minimalistic-assert "^1.0.0" + +hawk@3.1.3, hawk@~3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" + dependencies: + boom "2.x.x" + cryptiles "2.x.x" + hoek "2.x.x" + sntp "1.x.x" + +hmac-drbg@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" + dependencies: + hash.js "^1.0.3" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.1" + +hoek@2.x.x: + version "2.16.3" + resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" + +home-or-tmp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.1" + +hosted-git-info@^2.1.4: + version "2.5.0" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.5.0.tgz#6d60e34b3abbc8313062c3b798ef8d901a07af3c" + +http-signature@~1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf" + dependencies: + assert-plus "^0.2.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + +https-browserify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" + +iconv-lite@~0.4.13: + version "0.4.19" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" + +ieee754@^1.1.4: + version "1.1.8" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4" + +indexof@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + +inherits@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" + +ini@~1.3.0: + version "1.3.5" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" + +interpret@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.1.0.tgz#7ed1b1410c6a0e0f78cf95d3b8440c63f78b8614" + +invariant@^2.2.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.2.tgz#9e1f56ac0acdb6bf303306f338be3b204ae60360" + dependencies: + loose-envify "^1.0.0" + +invert-kv@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + +is-binary-path@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" + dependencies: + binary-extensions "^1.0.0" + +is-buffer@^1.1.5: + version "1.1.6" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + +is-builtin-module@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe" + dependencies: + builtin-modules "^1.0.0" + +is-dotfile@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" + +is-equal-shallow@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" + dependencies: + is-primitive "^2.0.0" + +is-extendable@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + +is-extglob@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" + +is-finite@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + +is-glob@^2.0.0, is-glob@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" + dependencies: + is-extglob "^1.0.0" + +is-number@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" + dependencies: + kind-of "^3.0.2" + +is-number@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" + dependencies: + kind-of "^3.0.2" + +is-posix-bracket@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" + +is-primitive@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" + +is-stream@^1.0.1, is-stream@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + +is-typedarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + +isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + +isobject@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + dependencies: + isarray "1.0.0" + +isomorphic-fetch@^2.1.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9" + dependencies: + node-fetch "^1.0.1" + whatwg-fetch ">=0.10.0" + +isstream@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + +js-tokens@^3.0.0, js-tokens@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" + +jsbn@~0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" + +jsesc@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" + +jsesc@~0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + +json-loader@^0.5.4: + version "0.5.7" + resolved "https://registry.yarnpkg.com/json-loader/-/json-loader-0.5.7.tgz#dca14a70235ff82f0ac9a3abeb60d337a365185d" + +json-schema-traverse@^0.3.0: + version "0.3.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340" + +json-schema@0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" + +json-stable-stringify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" + dependencies: + jsonify "~0.0.0" + +json-stringify-safe@~5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + +json5@^0.5.0, json5@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" + +jsonify@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" + +jsprim@^1.2.2: + version "1.4.1" + resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" + dependencies: + assert-plus "1.0.0" + extsprintf "1.3.0" + json-schema "0.2.3" + verror "1.10.0" + +kind-of@^3.0.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" + dependencies: + is-buffer "^1.1.5" + +kind-of@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" + dependencies: + is-buffer "^1.1.5" + +lazy-cache@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e" + +lcid@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" + dependencies: + invert-kv "^1.0.0" + +load-json-file@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8" + dependencies: + graceful-fs "^4.1.2" + parse-json "^2.2.0" + pify "^2.0.0" + strip-bom "^3.0.0" + +loader-runner@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.3.0.tgz#f482aea82d543e07921700d5a46ef26fdac6b8a2" + +loader-utils@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.1.0.tgz#c98aef488bcceda2ffb5e2de646d6a754429f5cd" + dependencies: + big.js "^3.1.3" + emojis-list "^2.0.0" + json5 "^0.5.0" + +locate-path@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" + dependencies: + p-locate "^2.0.0" + path-exists "^3.0.0" + +lodash@^4.14.0, lodash@^4.17.4, lodash@^4.17.5: + version "4.17.5" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.5.tgz#99a92d65c0272debe8c96b6057bc8fbfa3bed511" + +longest@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" + +loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848" + dependencies: + js-tokens "^3.0.0" + +lru-cache@^4.0.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.1.tgz#622e32e82488b49279114a4f9ecf45e7cd6bba55" + dependencies: + pseudomap "^1.0.2" + yallist "^2.1.2" + +md5.js@^1.3.4: + version "1.3.4" + resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.4.tgz#e9bdbde94a20a5ac18b04340fc5764d5b09d901d" + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + +mem@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/mem/-/mem-1.1.0.tgz#5edd52b485ca1d900fe64895505399a0dfa45f76" + dependencies: + mimic-fn "^1.0.0" + +memory-fs@^0.4.0, memory-fs@~0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552" + dependencies: + errno "^0.1.3" + readable-stream "^2.0.1" + +micromatch@^2.1.5: + version "2.3.11" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" + dependencies: + arr-diff "^2.0.0" + array-unique "^0.2.1" + braces "^1.8.2" + expand-brackets "^0.1.4" + extglob "^0.3.1" + filename-regex "^2.0.0" + is-extglob "^1.0.0" + is-glob "^2.0.1" + kind-of "^3.0.2" + normalize-path "^2.0.1" + object.omit "^2.0.0" + parse-glob "^3.0.4" + regex-cache "^0.4.2" + +miller-rabin@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" + dependencies: + bn.js "^4.0.0" + brorand "^1.0.1" + +mime-db@~1.33.0: + version "1.33.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.33.0.tgz#a3492050a5cb9b63450541e39d9788d2272783db" + +mime-types@^2.1.12, mime-types@~2.1.7: + version "2.1.18" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.18.tgz#6f323f60a83d11146f831ff11fd66e2fe5503bb8" + dependencies: + mime-db "~1.33.0" + +mimic-fn@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" + +minimalistic-assert@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz#702be2dda6b37f4836bcb3f5db56641b64a1d3d3" + +minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" + +minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + dependencies: + brace-expansion "^1.1.7" + +minimist@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" + +minimist@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" + +"mkdirp@>=0.5 0", mkdirp@^0.5.1, mkdirp@~0.5.0: + version "0.5.1" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" + dependencies: + minimist "0.0.8" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + +nan@^2.3.0: + version "2.8.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.8.0.tgz#ed715f3fe9de02b57a5e6252d90a96675e1f085a" + +node-fetch@^1.0.1: + version "1.7.3" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef" + dependencies: + encoding "^0.1.11" + is-stream "^1.0.1" + +node-libs-browser@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.1.0.tgz#5f94263d404f6e44767d726901fff05478d600df" + dependencies: + assert "^1.1.1" + browserify-zlib "^0.2.0" + buffer "^4.3.0" + console-browserify "^1.1.0" + constants-browserify "^1.0.0" + crypto-browserify "^3.11.0" + domain-browser "^1.1.1" + events "^1.0.0" + https-browserify "^1.0.0" + os-browserify "^0.3.0" + path-browserify "0.0.0" + process "^0.11.10" + punycode "^1.2.4" + querystring-es3 "^0.2.0" + readable-stream "^2.3.3" + stream-browserify "^2.0.1" + stream-http "^2.7.2" + string_decoder "^1.0.0" + timers-browserify "^2.0.4" + tty-browserify "0.0.0" + url "^0.11.0" + util "^0.10.3" + vm-browserify "0.0.4" + +node-pre-gyp@^0.6.39: + version "0.6.39" + resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.39.tgz#c00e96860b23c0e1420ac7befc5044e1d78d8649" + dependencies: + detect-libc "^1.0.2" + hawk "3.1.3" + mkdirp "^0.5.1" + nopt "^4.0.1" + npmlog "^4.0.2" + rc "^1.1.7" + request "2.81.0" + rimraf "^2.6.1" + semver "^5.3.0" + tar "^2.2.1" + tar-pack "^3.4.0" + +nopt@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" + dependencies: + abbrev "1" + osenv "^0.1.4" + +normalize-package-data@^2.3.2: + version "2.4.0" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.4.0.tgz#12f95a307d58352075a04907b84ac8be98ac012f" + dependencies: + hosted-git-info "^2.1.4" + is-builtin-module "^1.0.0" + semver "2 || 3 || 4 || 5" + validate-npm-package-license "^3.0.1" + +normalize-path@^2.0.0, normalize-path@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" + dependencies: + remove-trailing-separator "^1.0.1" + +npm-run-path@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" + dependencies: + path-key "^2.0.0" + +npmlog@^4.0.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" + dependencies: + are-we-there-yet "~1.1.2" + console-control-strings "~1.1.0" + gauge "~2.7.3" + set-blocking "~2.0.0" + +number-is-nan@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + +oauth-sign@~0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" + +object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + +object.omit@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" + dependencies: + for-own "^0.1.4" + is-extendable "^0.1.1" + +once@^1.3.0, once@^1.3.3: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + dependencies: + wrappy "1" + +os-browserify@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" + +os-homedir@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + +os-locale@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-2.1.0.tgz#42bc2900a6b5b8bd17376c8e882b65afccf24bf2" + dependencies: + execa "^0.7.0" + lcid "^1.0.0" + mem "^1.1.0" + +os-tmpdir@^1.0.0, os-tmpdir@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + +osenv@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.0" + +p-finally@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + +p-limit@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.2.0.tgz#0e92b6bedcb59f022c13d0f1949dc82d15909f1c" + dependencies: + p-try "^1.0.0" + +p-locate@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" + dependencies: + p-limit "^1.1.0" + +p-try@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" + +pako@~1.0.5: + version "1.0.6" + resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.6.tgz#0101211baa70c4bca4a0f63f2206e97b7dfaf258" + +parse-asn1@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.0.tgz#37c4f9b7ed3ab65c74817b5f2480937fbf97c712" + dependencies: + asn1.js "^4.0.0" + browserify-aes "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.0" + pbkdf2 "^3.0.3" + +parse-glob@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" + dependencies: + glob-base "^0.3.0" + is-dotfile "^1.0.0" + is-extglob "^1.0.0" + is-glob "^2.0.0" + +parse-json@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" + dependencies: + error-ex "^1.2.0" + +path-browserify@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.0.tgz#a0b870729aae214005b7d5032ec2cbbb0fb4451a" + +path-exists@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + +path-is-absolute@^1.0.0, path-is-absolute@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + +path-key@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + +path-type@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73" + dependencies: + pify "^2.0.0" + +pbkdf2@^3.0.3: + version "3.0.14" + resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.14.tgz#a35e13c64799b06ce15320f459c230e68e73bade" + dependencies: + create-hash "^1.1.2" + create-hmac "^1.1.4" + ripemd160 "^2.0.1" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +performance-now@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5" + +pify@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + +preserve@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" + +private@^0.1.6, private@^0.1.7: + version "0.1.8" + resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" + +process-nextick-args@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" + +process@^0.11.10: + version "0.11.10" + resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" + +promise@^7.1.1: + version "7.3.1" + resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf" + dependencies: + asap "~2.0.3" + +prop-types@^15.6.0: + version "15.6.0" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.0.tgz#ceaf083022fc46b4a35f69e13ef75aed0d639856" + dependencies: + fbjs "^0.8.16" + loose-envify "^1.3.1" + object-assign "^4.1.1" + +prr@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" + +pseudomap@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" + +public-encrypt@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.0.tgz#39f699f3a46560dd5ebacbca693caf7c65c18cc6" + dependencies: + bn.js "^4.1.0" + browserify-rsa "^4.0.0" + create-hash "^1.1.0" + parse-asn1 "^5.0.0" + randombytes "^2.0.1" + +punycode@1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" + +punycode@^1.2.4, punycode@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + +qs@~6.4.0: + version "6.4.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233" + +querystring-es3@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" + +querystring@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" + +randomatic@^1.1.3: + version "1.1.7" + resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.7.tgz#c7abe9cc8b87c0baa876b19fde83fd464797e38c" + dependencies: + is-number "^3.0.0" + kind-of "^4.0.0" + +randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5: + version "2.0.6" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.0.6.tgz#d302c522948588848a8d300c932b44c24231da80" + dependencies: + safe-buffer "^5.1.0" + +randomfill@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458" + dependencies: + randombytes "^2.0.5" + safe-buffer "^5.1.0" + +rc@^1.1.7: + version "1.2.5" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.5.tgz#275cd687f6e3b36cc756baa26dfee80a790301fd" + dependencies: + deep-extend "~0.4.0" + ini "~1.3.0" + minimist "^1.2.0" + strip-json-comments "~2.0.1" + +react-dom@^16.2.0: + version "16.2.0" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.2.0.tgz#69003178601c0ca19b709b33a83369fe6124c044" + dependencies: + fbjs "^0.8.16" + loose-envify "^1.1.0" + object-assign "^4.1.1" + prop-types "^15.6.0" + +react@^16.2.0: + version "16.2.0" + resolved "https://registry.yarnpkg.com/react/-/react-16.2.0.tgz#a31bd2dab89bff65d42134fa187f24d054c273ba" + dependencies: + fbjs "^0.8.16" + loose-envify "^1.1.0" + object-assign "^4.1.1" + prop-types "^15.6.0" + +read-pkg-up@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be" + dependencies: + find-up "^2.0.0" + read-pkg "^2.0.0" + +read-pkg@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8" + dependencies: + load-json-file "^2.0.0" + normalize-package-data "^2.3.2" + path-type "^2.0.0" + +readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.3.3: + version "2.3.4" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.4.tgz#c946c3f47fa7d8eabc0b6150f4a12f69a4574071" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.0.3" + util-deprecate "~1.0.1" + +readdirp@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78" + dependencies: + graceful-fs "^4.1.2" + minimatch "^3.0.2" + readable-stream "^2.0.2" + set-immediate-shim "^1.0.1" + +regenerate@^1.2.1: + version "1.3.3" + resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.3.tgz#0c336d3980553d755c39b586ae3b20aa49c82b7f" + +regenerator-runtime@^0.11.0: + version "0.11.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" + +regenerator-transform@^0.10.0: + version "0.10.1" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.10.1.tgz#1e4996837231da8b7f3cf4114d71b5691a0680dd" + dependencies: + babel-runtime "^6.18.0" + babel-types "^6.19.0" + private "^0.1.6" + +regex-cache@^0.4.2: + version "0.4.4" + resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd" + dependencies: + is-equal-shallow "^0.1.3" + +regexpu-core@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240" + dependencies: + regenerate "^1.2.1" + regjsgen "^0.2.0" + regjsparser "^0.1.4" + +regjsgen@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7" + +regjsparser@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c" + dependencies: + jsesc "~0.5.0" + +remove-trailing-separator@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" + +repeat-element@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" + +repeat-string@^1.5.2: + version "1.6.1" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + +repeating@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" + dependencies: + is-finite "^1.0.0" + +request@2.81.0: + version "2.81.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0" + dependencies: + aws-sign2 "~0.6.0" + aws4 "^1.2.1" + caseless "~0.12.0" + combined-stream "~1.0.5" + extend "~3.0.0" + forever-agent "~0.6.1" + form-data "~2.1.1" + har-validator "~4.2.1" + hawk "~3.1.3" + http-signature "~1.1.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.7" + oauth-sign "~0.8.1" + performance-now "^0.2.0" + qs "~6.4.0" + safe-buffer "^5.0.1" + stringstream "~0.0.4" + tough-cookie "~2.3.0" + tunnel-agent "^0.6.0" + uuid "^3.0.0" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + +require-main-filename@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" + +right-align@^0.1.1: + version "0.1.3" + resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef" + dependencies: + align-text "^0.1.1" + +rimraf@2, rimraf@^2.5.1, rimraf@^2.6.1: + version "2.6.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" + dependencies: + glob "^7.0.5" + +ripemd160@^2.0.0, ripemd160@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.1.tgz#0f4584295c53a3628af7e6d79aca21ce57d1c6e7" + dependencies: + hash-base "^2.0.0" + inherits "^2.0.1" + +safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" + +"semver@2 || 3 || 4 || 5", semver@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" + +set-blocking@^2.0.0, set-blocking@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + +set-immediate-shim@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" + +setimmediate@^1.0.4, setimmediate@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" + +sha.js@^2.4.0, sha.js@^2.4.8: + version "2.4.10" + resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.10.tgz#b1fde5cd7d11a5626638a07c604ab909cfa31f9b" + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +shebang-command@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + dependencies: + shebang-regex "^1.0.0" + +shebang-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + +signal-exit@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" + +slash@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" + +sntp@1.x.x: + version "1.0.9" + resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198" + dependencies: + hoek "2.x.x" + +source-list-map@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.0.tgz#aaa47403f7b245a92fbc97ea08f250d6087ed085" + +source-map-support@^0.4.15: + version "0.4.18" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f" + dependencies: + source-map "^0.5.6" + +source-map@^0.5.3, source-map@^0.5.6, source-map@^0.5.7, source-map@~0.5.1: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + +source-map@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + +spdx-correct@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-1.0.2.tgz#4b3073d933ff51f3912f03ac5519498a4150db40" + dependencies: + spdx-license-ids "^1.0.2" + +spdx-expression-parse@~1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz#9bdf2f20e1f40ed447fbe273266191fced51626c" + +spdx-license-ids@^1.0.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz#c9df7a3424594ade6bd11900d596696dc06bac57" + +sshpk@^1.7.0: + version "1.13.1" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.13.1.tgz#512df6da6287144316dc4c18fe1cf1d940739be3" + dependencies: + asn1 "~0.2.3" + assert-plus "^1.0.0" + dashdash "^1.12.0" + getpass "^0.1.1" + optionalDependencies: + bcrypt-pbkdf "^1.0.0" + ecc-jsbn "~0.1.1" + jsbn "~0.1.0" + tweetnacl "~0.14.0" + +stream-browserify@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.1.tgz#66266ee5f9bdb9940a4e4514cafb43bb71e5c9db" + dependencies: + inherits "~2.0.1" + readable-stream "^2.0.2" + +stream-http@^2.7.2: + version "2.8.0" + resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.8.0.tgz#fd86546dac9b1c91aff8fc5d287b98fafb41bc10" + dependencies: + builtin-status-codes "^3.0.0" + inherits "^2.0.1" + readable-stream "^2.3.3" + to-arraybuffer "^1.0.0" + xtend "^4.0.0" + +string-width@^1.0.1, string-width@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + +string-width@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^4.0.0" + +string_decoder@^1.0.0, string_decoder@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.3.tgz#0fc67d7c141825de94282dd536bec6b9bce860ab" + dependencies: + safe-buffer "~5.1.0" + +stringstream@~0.0.4: + version "0.0.5" + resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" + +strip-ansi@^3.0.0, strip-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + dependencies: + ansi-regex "^2.0.0" + +strip-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + dependencies: + ansi-regex "^3.0.0" + +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + +strip-eof@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" + +strip-json-comments@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + +supports-color@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" + +supports-color@^4.2.1: + version "4.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-4.5.0.tgz#be7a0de484dec5c5cddf8b3d59125044912f635b" + dependencies: + has-flag "^2.0.0" + +tapable@^0.2.7: + version "0.2.8" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-0.2.8.tgz#99372a5c999bf2df160afc0d74bed4f47948cd22" + +tar-pack@^3.4.0: + version "3.4.1" + resolved "https://registry.yarnpkg.com/tar-pack/-/tar-pack-3.4.1.tgz#e1dbc03a9b9d3ba07e896ad027317eb679a10a1f" + dependencies: + debug "^2.2.0" + fstream "^1.0.10" + fstream-ignore "^1.0.5" + once "^1.3.3" + readable-stream "^2.1.4" + rimraf "^2.5.1" + tar "^2.2.1" + uid-number "^0.0.6" + +tar@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1" + dependencies: + block-stream "*" + fstream "^1.0.2" + inherits "2" + +timers-browserify@^2.0.4: + version "2.0.6" + resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.6.tgz#241e76927d9ca05f4d959819022f5b3664b64bae" + dependencies: + setimmediate "^1.0.4" + +to-arraybuffer@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" + +to-fast-properties@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" + +tough-cookie@~2.3.0: + version "2.3.3" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.3.tgz#0b618a5565b6dea90bf3425d04d55edc475a7561" + dependencies: + punycode "^1.4.1" + +trim-right@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" + +tty-browserify@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" + +tunnel-agent@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + dependencies: + safe-buffer "^5.0.1" + +tweetnacl@^0.14.3, tweetnacl@~0.14.0: + version "0.14.5" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + +ua-parser-js@^0.7.9: + version "0.7.17" + resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.17.tgz#e9ec5f9498b9ec910e7ae3ac626a805c4d09ecac" + +uglify-js@^2.8.29: + version "2.8.29" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.29.tgz#29c5733148057bb4e1f75df35b7a9cb72e6a59dd" + dependencies: + source-map "~0.5.1" + yargs "~3.10.0" + optionalDependencies: + uglify-to-browserify "~1.0.0" + +uglify-to-browserify@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7" + +uglifyjs-webpack-plugin@^0.4.6: + version "0.4.6" + resolved "https://registry.yarnpkg.com/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-0.4.6.tgz#b951f4abb6bd617e66f63eb891498e391763e309" + dependencies: + source-map "^0.5.6" + uglify-js "^2.8.29" + webpack-sources "^1.0.1" + +uid-number@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" + +url@^0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" + dependencies: + punycode "1.3.2" + querystring "0.2.0" + +util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + +util@0.10.3, util@^0.10.3: + version "0.10.3" + resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" + dependencies: + inherits "2.0.1" + +uuid@^3.0.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.2.1.tgz#12c528bb9d58d0b9265d9a2f6f0fe8be17ff1f14" + +validate-npm-package-license@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz#2804babe712ad3379459acfbe24746ab2c303fbc" + dependencies: + spdx-correct "~1.0.0" + spdx-expression-parse "~1.0.0" + +verror@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" + dependencies: + assert-plus "^1.0.0" + core-util-is "1.0.2" + extsprintf "^1.2.0" + +vm-browserify@0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-0.0.4.tgz#5d7ea45bbef9e4a6ff65f95438e0a87c357d5a73" + dependencies: + indexof "0.0.1" + +watchpack@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.4.0.tgz#4a1472bcbb952bd0a9bb4036801f954dfb39faac" + dependencies: + async "^2.1.2" + chokidar "^1.7.0" + graceful-fs "^4.1.2" + +webpack-sources@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.1.0.tgz#a101ebae59d6507354d71d8013950a3a8b7a5a54" + dependencies: + source-list-map "^2.0.0" + source-map "~0.6.1" + +webpack@^3.11.0: + version "3.11.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-3.11.0.tgz#77da451b1d7b4b117adaf41a1a93b5742f24d894" + dependencies: + acorn "^5.0.0" + acorn-dynamic-import "^2.0.0" + ajv "^6.1.0" + ajv-keywords "^3.1.0" + async "^2.1.2" + enhanced-resolve "^3.4.0" + escope "^3.6.0" + interpret "^1.0.0" + json-loader "^0.5.4" + json5 "^0.5.1" + loader-runner "^2.3.0" + loader-utils "^1.1.0" + memory-fs "~0.4.1" + mkdirp "~0.5.0" + node-libs-browser "^2.0.0" + source-map "^0.5.3" + supports-color "^4.2.1" + tapable "^0.2.7" + uglifyjs-webpack-plugin "^0.4.6" + watchpack "^1.4.0" + webpack-sources "^1.0.1" + yargs "^8.0.2" + +whatwg-fetch@>=0.10.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz#9c84ec2dcf68187ff00bc64e1274b442176e1c84" + +which-module@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" + +which@^1.2.9: + version "1.3.0" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.0.tgz#ff04bdfc010ee547d780bec38e1ac1c2777d253a" + dependencies: + isexe "^2.0.0" + +wide-align@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.2.tgz#571e0f1b0604636ebc0dfc21b0339bbe31341710" + dependencies: + string-width "^1.0.2" + +window-size@0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" + +wordwrap@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" + +wrap-ansi@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + +xtend@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" + +y18n@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" + +yallist@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" + +yargs-parser@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-7.0.0.tgz#8d0ac42f16ea55debd332caf4c4038b3e3f5dfd9" + dependencies: + camelcase "^4.1.0" + +yargs@^8.0.2: + version "8.0.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-8.0.2.tgz#6299a9055b1cefc969ff7e79c1d918dceb22c360" + dependencies: + camelcase "^4.1.0" + cliui "^3.2.0" + decamelize "^1.1.1" + get-caller-file "^1.0.1" + os-locale "^2.0.0" + read-pkg-up "^2.0.0" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^2.0.0" + which-module "^2.0.0" + y18n "^3.2.1" + yargs-parser "^7.0.0" + +yargs@~3.10.0: + version "3.10.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1" + dependencies: + camelcase "^1.0.2" + cliui "^2.1.0" + decamelize "^1.0.0" + window-size "0.1.0" diff --git a/src/cli/commands/install.js b/src/cli/commands/install.js index b0e3db6fff..957f4f27a1 100644 --- a/src/cli/commands/install.js +++ b/src/cli/commands/install.js @@ -578,7 +578,7 @@ export class Install { steps.push((curr: number, total: number) => callThroughHook('pnpStep', async () => { - let code = await generatePnpMap(flattenedTopLevelPatterns, {resolver: this.resolver}); + const code = await generatePnpMap(flattenedTopLevelPatterns, {resolver: this.resolver}); await fs.writeFile(`${this.config.lockfileFolder}/.pnp.js`, code); }), ); diff --git a/src/config.js b/src/config.js index a37eaee047..f784729087 100644 --- a/src/config.js +++ b/src/config.js @@ -158,6 +158,8 @@ export default class Config { nonInteractive: boolean; + plugnplayEnabled: boolean; + workspacesEnabled: boolean; workspacesNohoistEnabled: boolean; @@ -324,6 +326,8 @@ export default class Config { } else { this._cacheRootFolder = String(cacheRootFolder); } + this.plugnplayEnabled = this.getOption('plugnplay-experimental') !== false; + this.workspacesEnabled = this.getOption('workspaces-experimental') !== false; this.workspacesNohoistEnabled = this.getOption('workspaces-nohoist-experimental') !== false; diff --git a/src/package-hoister.js b/src/package-hoister.js index d4e509e2b6..8fc9f6abbc 100644 --- a/src/package-hoister.js +++ b/src/package-hoister.js @@ -754,7 +754,9 @@ export class NohoistResolver { if (info.nohoistList && info.nohoistList.length > 0 && mm.any(this._originalPath(info), info.nohoistList)) { return true; } - return true; + if (this._config.plugnplayEnabled) { + return true; + } return false; }; _isRootPackage = (pkg: Manifest): boolean => { diff --git a/src/package-linker.js b/src/package-linker.js index 04a3ebe9a4..ff7f76d275 100644 --- a/src/package-linker.js +++ b/src/package-linker.js @@ -135,7 +135,7 @@ export default class PackageLinker { // write the executables for (const {dep, loc} of deps) { if (dep._reference && dep._reference.location) { - invariant(!pkg._reference.isPlugnplay, "Plug'n'play packages should not be referenced here"); + invariant(!dep._reference.isPlugnplay, "Plug'n'play packages should not be referenced here"); await this.linkSelfDependencies(dep, loc, dir); } } @@ -208,7 +208,7 @@ export default class PackageLinker { } } - if (true) { + if (this.config.plugnplayEnabled) { ref.isPlugnplay = true; ref.setLocation(src); continue; @@ -429,7 +429,13 @@ export default class PackageLinker { await promise.queue( topLevelDependencies, async ([dest, {pkg}]) => { - if (pkg._reference && pkg._reference.location && !pkg._reference.isPlugnplay && pkg.bin && Object.keys(pkg.bin).length) { + if ( + pkg._reference && + pkg._reference.location && + !pkg._reference.isPlugnplay && + pkg.bin && + Object.keys(pkg.bin).length + ) { const binLoc = path.join(this.config.lockfileFolder, this.config.getFolder(pkg)); await this.linkSelfDependencies(pkg, dest, binLoc); } diff --git a/src/package-reference.js b/src/package-reference.js index 06995d978c..7ee47dc7e8 100644 --- a/src/package-reference.js +++ b/src/package-reference.js @@ -15,6 +15,8 @@ export default class PackageReference { this.requests = []; this.config = request.config; + this.isPlugnplay = false; + this.registry = remote.registry; this.version = info.version; this.name = info.name; @@ -39,6 +41,7 @@ export default class PackageReference { lockfile: Lockfile; config: Config; + isPlugnplay: boolean; level: number; name: string; version: string; diff --git a/src/util/fs.js b/src/util/fs.js index 8387ff0e32..a1fb8b117b 100644 --- a/src/util/fs.js +++ b/src/util/fs.js @@ -33,8 +33,7 @@ export const rename: (oldPath: string, newPath: string) => Promise = promi export const access: (path: string, mode?: number) => Promise = promisify(fs.access); export const stat: (path: string) => Promise = promisify(fs.stat); export const unlink: (path: string) => Promise = promisify(require('rimraf')); -export const mkdirpx: (path: string) => Promise = promisify(require('mkdirp')); -export const mkdirp = async path => await mkdirpx((console.log(path, new Error().stack), path)); +export const mkdirp: (path: string) => Promise = promisify(require('mkdirp')); export const exists: (path: string) => Promise = promisify(fs.exists, true); export const lstat: (path: string) => Promise = promisify(fs.lstat); export const chmod: (path: string, mode: number | string) => Promise = promisify(fs.chmod); diff --git a/src/util/generate-pnp-map.js b/src/util/generate-pnp-map.js index 52cd498523..68f2925377 100644 --- a/src/util/generate-pnp-map.js +++ b/src/util/generate-pnp-map.js @@ -1,132 +1,132 @@ -import * as fs from './fs.js'; - -function generateMaps(packageInformationStores, sharedDependencies) { - - let code = ``; - - // Bake the information stores into our generated code - code += `let packageInformationStores = new Map([\n`; +// @flow - for (let [ packageName, packageInformationStore ] of packageInformationStores) { +import type PackageResolver from '../package-resolver.js'; +import * as fs from './fs.js'; - code += ` [ ${JSON.stringify(packageName)}, new Map([\n`; +const path = require('path'); - for (let [ packageReference, { packageLocation, packageDependencies } ] of packageInformationStore) { +type PackageInformation = {|packageLocation: string, packageDependencies: Map|}; +type PackageInformationStore = Map; +type PackageInformationStores = Map; - code += ` [ ${JSON.stringify(packageReference)}, {\n`; - code += ` packageLocation: ${JSON.stringify(packageLocation)},\n`; - code += ` packageDependencies: new Map([\n`; +function generateMaps(packageInformationStores: PackageInformationStores): string { + let code = ``; - for (let [ dependencyName, dependencyReference ] of packageDependencies.entries()) - code += ` [ ${JSON.stringify(dependencyName)}, ${JSON.stringify(dependencyReference)} ],\n`; + // Bake the information stores into our generated code + code += `let packageInformationStores = new Map([\n`; - code += ` ]),\n`; - code += ` } ],\n`; + for (const [packageName, packageInformationStore] of packageInformationStores) { + code += ` [ ${JSON.stringify(packageName)}, new Map([\n`; - } + for (const [packageReference, {packageLocation, packageDependencies}] of packageInformationStore) { + code += ` [ ${JSON.stringify(packageReference)}, {\n`; + code += ` packageLocation: ${JSON.stringify(packageLocation)},\n`; + code += ` packageDependencies: new Map([\n`; - code += ` ]) ],\n`; + for (const [dependencyName, dependencyReference] of packageDependencies.entries()) { + code += ` [ ${JSON.stringify(dependencyName)}, ${JSON.stringify(dependencyReference)} ],\n`; + } + code += ` ]),\n`; + code += ` } ],\n`; } - code += `]);\n`; - - // Also bake an inverse map that will allow us to find the package information based on the path - code += `let locatorsByLocations = new Map([\n`; + code += ` ]) ],\n`; + } - for (let [ packageName, packageInformationStore ] of packageInformationStores) - for (let [ packageReference, { packageLocation } ] of packageInformationStore) - code += ` [ ${JSON.stringify(packageLocation)}, ${JSON.stringify({ name: packageName, reference: packageReference })} ],\n`; + code += `]);\n`; - code += `]);\n`; + // Also bake an inverse map that will allow us to find the package information based on the path + code += `let locatorsByLocations = new Map([\n`; - // Finally, we bake the shared dependencies (ie those that can explicitely be required by everything else) - code += `let sharedDependencies = new Set([\n`; - - for (let sharedDependency of sharedDependencies) - code += ` ${JSON.stringify(sharedDependency)},\n`; - - code += `]);\n`; + for (const [packageName, packageInformationStore] of packageInformationStores) { + for (const [packageReference, {packageLocation}] of packageInformationStore) { + code += ` [ ${JSON.stringify(packageLocation)}, ${JSON.stringify({ + name: packageName, + reference: packageReference, + })} ],\n`; + } + } - return code; + code += `]);\n`; + return code; } -function generateFindPackageLocator(packageInformationStores) { - - let code = ``; +function generateFindPackageLocator(packageInformationStores: PackageInformationStores): string { + let code = ``; - // We get the list of each string length we'll need to check in order to find the current package context - let lengths = new Map(); + // We get the list of each string length we'll need to check in order to find the current package context + const lengths = new Map(); - for (let [ packageName, packageInformationStore ] of packageInformationStores) - for (let [ packageReference, { packageLocation } ] of packageInformationStore) - if (packageLocation !== null) - lengths.set(packageLocation.length, (lengths.get(packageLocation.length) || 0) + 1); - - // We sort those lengths by the number of time they are used, so that the more common ones are tested before the others - let sortedLengths = Array.from(lengths.entries()).sort((a, b) => { - return b[1] - a[1]; - }); + for (const packageInformationStore of packageInformationStores.values()) { + for (const {packageLocation} of packageInformationStore.values()) { + if (packageLocation !== null) { + lengths.set(packageLocation.length, (lengths.get(packageLocation.length) || 0) + 1); + } + } + } - // Generate a function that, given a file path, returns the associated package name - code += `exports.findPackageLocator = function findPackageLocator(path) {\n`; - code += `\n`; - code += ` let match;\n`; + // We sort the lengths by the number of time they are used, so that the more common ones are tested before the others + const sortedLengths = Array.from(lengths.entries()).sort((a, b) => { + return b[1] - a[1]; + }); - for (let [ length, count ] of sortedLengths) - code += ` if (match = locatorsByLocations.get(path.substr(0, ${length}))) return match;\n`; + // Generate a function that, given a file path, returns the associated package name + code += `exports.findPackageLocator = function findPackageLocator(path) {\n`; + code += `\n`; + code += ` let match;\n`; - code += ` return null;\n`; - code += `};\n`; + for (const length of sortedLengths.keys()) { + code += ` if (match = locatorsByLocations.get(path.substr(0, ${length}))) return match;\n`; + } - return code; + code += ` return null;\n`; + code += `};\n`; + return code; } -function generateGetPackageLocation(packageInformationStores) { +function generateGetPackageLocation(packageInformationStores: PackageInformationStores): string { + let code = ``; - let code = ``; + // Generate a function that, given a locator, returns the package location on the disk - // Generate a function that, given a locator, returns the package location on the disk - - code += `exports.getPackageLocation = function getPackageLocation({ name, reference }) {\n`; - code += `\n`; - code += ` let packageInformationStore, packageInformation;\n`; - code += `\n`; - code += ` if (packageInformationStore = packageInformationStores.get(name))\n`; - code += ` if (packageInformation = packageInformationStore.get(reference))\n`; - code += ` return packageInformation.packageLocation;\n`; - code += `\n`; - code += ` return null;\n`; - code += `\n`; - code += `};\n`; - - return code; + code += `exports.getPackageLocation = function getPackageLocation({ name, reference }) {\n`; + code += `\n`; + code += ` let packageInformationStore, packageInformation;\n`; + code += `\n`; + code += ` if (packageInformationStore = packageInformationStores.get(name))\n`; + code += ` if (packageInformation = packageInformationStore.get(reference))\n`; + code += ` return packageInformation.packageLocation;\n`; + code += `\n`; + code += ` return null;\n`; + code += `\n`; + code += `};\n`; + return code; } -function generateGetPackageDependencies(packageInformationStores) { - - let code = ``; - - // Generate a function that, given a locator, returns the package dependencies +function generateGetPackageDependencies(packageInformationStores: PackageInformationStores): string { + let code = ``; - code += `exports.getPackageDependencies = function getPackageDependencies({ name, reference }) {\n`; - code += `\n`; - code += ` let packageInformationStore, packageInformation;\n`; - code += `\n`; - code += ` if (packageInformationStore = packageInformationStores.get(name))\n`; - code += ` if (packageInformation = packageInformationStore.get(reference))\n`; - code += ` return packageInformation.packageDependencies;\n`; - code += `\n`; - code += ` return null;\n`; - code += `};\n`; + // Generate a function that, given a locator, returns the package dependencies - return code; + code += `exports.getPackageDependencies = function getPackageDependencies({ name, reference }) {\n`; + code += `\n`; + code += ` let packageInformationStore, packageInformation;\n`; + code += `\n`; + code += ` if (packageInformationStore = packageInformationStores.get(name))\n`; + code += ` if (packageInformation = packageInformationStore.get(reference))\n`; + code += ` return packageInformation.packageDependencies;\n`; + code += `\n`; + code += ` return null;\n`; + code += `};\n`; + return code; } +/* eslint-disable max-len */ const REQUIRE_HOOK = ` let Module = require(\`module\`); @@ -154,9 +154,6 @@ Module._resolveFilename = function (request, parent, isMain, options) { let [ , dependencyName, subPath ] = dependencyNameMatch; let dependencyReference = packageDependencies.get(dependencyName); - if (!dependencyReference && sharedDependencies.has(dependencyName)) - dependencyReference = exports.getPackageDependencies({ name: null, reference: null }).get(dependencyName); - if (!dependencyReference) { if (packageLocator.name === null) { throw new Error(\`You cannot require a package (\${dependencyName}) that is not declared in your dependencies\`); @@ -171,72 +168,79 @@ Module._resolveFilename = function (request, parent, isMain, options) { }; `; +/* eslint-enable */ -async function getPackageInformationStores(seedPatterns, {resolver}) { - - // We'll need to convert the map of locator=>location into a two-level map of name=>reference=>location (because we won't use Immutable.js, so objects can't be keys) - let packageInformationStores = new Map(); +async function getPackageInformationStores( + seedPatterns: Array, + {resolver}: {resolver: PackageResolver}, +): PackageInformationStores { + const packageInformationStores = new Map(); - const pkgs = resolver.getTopologicalManifests(seedPatterns); + const pkgs = resolver.getTopologicalManifests(seedPatterns); - for (const pkg of pkgs) { - if (pkg._reference && pkg._reference.isPlugnplay) { - let packageInformationStore = packageInformationStores.get(pkg.name); - - if (!packageInformationStore) { - packageInformationStores.set(pkg.name, packageInformationStore = new Map()); - } + for (const pkg of pkgs) { + if (pkg._reference && pkg._reference.location && pkg._reference.isPlugnplay) { + const ref = pkg._reference; + const loc = ref.location; - let packageDependencies = new Map(); + let packageInformationStore = packageInformationStores.get(pkg.name); - for (const pattern of pkg._reference.dependencies) { - const dep = resolver.getStrictResolvedPattern(pattern); - packageDependencies.set(dep.name, dep.version); - } - - packageInformationStore.set(pkg.version, { - packageLocation: await fs.realpath(pkg._reference.location), - packageDependencies, - }); + if (!packageInformationStore) { + packageInformationStores.set(pkg.name, (packageInformationStore = new Map())); } - } - // Top-level package - if (true) { - let topLevelDependencies = new Map(); + const packageDependencies = new Map(); - for (const pattern of seedPatterns) { + for (const pattern of ref.dependencies) { const dep = resolver.getStrictResolvedPattern(pattern); - topLevelDependencies.set(dep.name, dep.version); + packageDependencies.set(dep.name, dep.version); } - packageInformationStores.set(null, new Map([ - [ null, { - packageLocation: null, - packageDependencies: topLevelDependencies, - } ], - ])); + packageInformationStore.set(pkg.version, { + packageLocation: (await fs.realpath(loc)).replace(/\/$/, path.sep), + packageDependencies, + }); } + } - return packageInformationStores; + // Top-level package + if (true) { + const topLevelDependencies = new Map(); -} - -export async function generatePnpMap(seedPatterns, {resolver}) { + for (const pattern of seedPatterns) { + const dep = resolver.getStrictResolvedPattern(pattern); + topLevelDependencies.set(dep.name, dep.version); + } - let packageInformationStores = await getPackageInformationStores(seedPatterns, {resolver}); - let sharedDependencies = new Set(); + packageInformationStores.set( + null, + new Map([ + [ + null, + { + packageLocation: null, + packageDependencies: topLevelDependencies, + }, + ], + ]), + ); + } + + return packageInformationStores; +} - let code = ``; +export async function generatePnpMap(seedPatterns: Array, {resolver}: {resolver: PackageResolver}): string { + const packageInformationStores = await getPackageInformationStores(seedPatterns, {resolver}); - code += generateMaps(packageInformationStores, sharedDependencies); + let code = ``; - code += generateFindPackageLocator(packageInformationStores); - code += generateGetPackageLocation(packageInformationStores); - code += generateGetPackageDependencies(packageInformationStores); + code += generateMaps(packageInformationStores); - code += REQUIRE_HOOK; + code += generateFindPackageLocator(packageInformationStores); + code += generateGetPackageLocation(packageInformationStores); + code += generateGetPackageDependencies(packageInformationStores); - return code; + code += REQUIRE_HOOK; + return code; } diff --git a/src/util/hooks.js b/src/util/hooks.js index d9f00e0592..4417b37f5c 100644 --- a/src/util/hooks.js +++ b/src/util/hooks.js @@ -1,6 +1,6 @@ /* @flow */ -export type YarnHook = 'resolveStep' | 'fetchStep' | 'linkStep' | 'buildStep'; +export type YarnHook = 'resolveStep' | 'fetchStep' | 'linkStep' | 'buildStep' | 'pnpStep'; const YARN_HOOKS_KEY = 'experimentalYarnHooks'; From efb50bed4056ab641afea5d9d6209bd00dc7e348 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Wed, 28 Feb 2018 11:43:46 +0000 Subject: [PATCH 003/111] Improves the "yarn node" command so that it works with pnp Branch: yarn-node-pnp --- src/cli/commands/install.js | 4 ++-- src/cli/commands/node.js | 9 ++++++++- src/constants.js | 2 ++ 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/cli/commands/install.js b/src/cli/commands/install.js index 957f4f27a1..fbe01e3c6a 100644 --- a/src/cli/commands/install.js +++ b/src/cli/commands/install.js @@ -578,8 +578,8 @@ export class Install { steps.push((curr: number, total: number) => callThroughHook('pnpStep', async () => { - const code = await generatePnpMap(flattenedTopLevelPatterns, {resolver: this.resolver}); - await fs.writeFile(`${this.config.lockfileFolder}/.pnp.js`, code); + const code = await generatePnpMap(this.config, flattenedTopLevelPatterns, {resolver: this.resolver}); + await fs.writeFile(`${this.config.lockfileFolder}/${constants.PNP_FILENAME}`, code); }), ); diff --git a/src/cli/commands/node.js b/src/cli/commands/node.js index 2f994e5787..be0db3ab60 100644 --- a/src/cli/commands/node.js +++ b/src/cli/commands/node.js @@ -3,7 +3,8 @@ import type Config from '../../config.js'; import type {Reporter} from '../../reporters/index.js'; import * as child from '../../util/child.js'; -import {NODE_BIN_PATH} from '../../constants'; +import * as fs from '../../util/fs.js'; +import {NODE_BIN_PATH, PNP_FILENAME} from '../../constants'; export function setFlags(commander: Object) {} @@ -12,6 +13,12 @@ export function hasWrapper(commander: Object, args: Array): boolean { } export async function run(config: Config, reporter: Reporter, flags: Object, args: Array): Promise { + const pnpPath = `${config.lockfileFolder}/${PNP_FILENAME}`; + + if (await fs.exists(pnpPath)) { + args = ['-r', pnpPath, ... args]; + } + try { await child.spawn(NODE_BIN_PATH, args, { stdio: 'inherit', diff --git a/src/constants.js b/src/constants.js index 59dc4b89a0..a4ba0cd50b 100644 --- a/src/constants.js +++ b/src/constants.js @@ -77,6 +77,8 @@ function getYarnBinPath(): string { export const NODE_MODULES_FOLDER = 'node_modules'; export const NODE_PACKAGE_JSON = 'package.json'; +export const PNP_FILENAME = '.pnp.js'; + export const POSIX_GLOBAL_PREFIX = `${process.env.DESTDIR || ''}/usr/local`; export const FALLBACK_GLOBAL_PREFIX = path.join(userHome, '.yarn'); From 9ba4b7ea1546ea757e1419dedb02bb087da897e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Wed, 28 Feb 2018 12:59:45 +0000 Subject: [PATCH 004/111] Adds the pnp tests to the pkg-tests testsuite Branch: pkg-tests --- packages/pkg-tests/package.json | 2 +- .../pkg-tests-specs/sources/index.js | 1 + .../pkg-tests/pkg-tests-specs/sources/pnp.js | 126 +++++++++ packages/pkg-tests/yarn.lock | 250 +++++++++--------- packages/pkg-tests/yarn.test.js | 18 +- 5 files changed, 271 insertions(+), 126 deletions(-) create mode 100644 packages/pkg-tests/pkg-tests-specs/sources/pnp.js diff --git a/packages/pkg-tests/package.json b/packages/pkg-tests/package.json index a76d9d413e..be7e96f5b8 100644 --- a/packages/pkg-tests/package.json +++ b/packages/pkg-tests/package.json @@ -10,7 +10,7 @@ "babel-preset-env": "^1.6.1", "babel-preset-flow": "^6.23.0", "flow-bin": "^0.66.0", - "jest": "^22.3.0", + "jest": "^22.4.2", "prettier": "^1.10.2" }, "scripts": { diff --git a/packages/pkg-tests/pkg-tests-specs/sources/index.js b/packages/pkg-tests/pkg-tests-specs/sources/index.js index 02f1b0b27d..000310a08f 100644 --- a/packages/pkg-tests/pkg-tests-specs/sources/index.js +++ b/packages/pkg-tests/pkg-tests-specs/sources/index.js @@ -2,3 +2,4 @@ exports.basic = require('./basic'); exports.dragon = require('./dragon'); +exports.pnp = require('./pnp'); diff --git a/packages/pkg-tests/pkg-tests-specs/sources/pnp.js b/packages/pkg-tests/pkg-tests-specs/sources/pnp.js new file mode 100644 index 0000000000..91e870c526 --- /dev/null +++ b/packages/pkg-tests/pkg-tests-specs/sources/pnp.js @@ -0,0 +1,126 @@ +const {fs: {writeFile}, tests: {getPackageDirectoryPath}} = require('pkg-tests-core'); +const {basic: basicSpecs} = require('pkg-tests-specs'); + +module.exports = makeTemporaryEnv => { + describe(`Plug'n'Play`, () => { + basicSpecs( + makeTemporaryEnv.withConfig({ + plugNPlay: true, + }), + ); + + test( + `it should resolve two identical packages with the same object (easy)`, + makeTemporaryEnv( + { + dependencies: { + [`one-fixed-dep-1`]: getPackageDirectoryPath(`one-fixed-dep`, `1.0.0`), + [`one-fixed-dep-2`]: getPackageDirectoryPath(`one-fixed-dep`, `1.0.0`), + [`no-deps`]: `1.0.0`, + }, + }, + async ({path, run, source}) => { + await run(`install`); + + await expect( + source(`require('one-fixed-dep-1').dependencies['no-deps'] === require('no-deps')`), + ).resolves.toEqual(true); + await expect( + source(`require('one-fixed-dep-2').dependencies['no-deps'] === require('no-deps')`), + ).resolves.toEqual(true); + }, + ), + ); + + test( + `it should resolve two identical packages with the same object (complex)`, + makeTemporaryEnv( + { + dependencies: { + [`one-fixed-dep-1`]: getPackageDirectoryPath(`one-fixed-dep`, `1.0.0`), + [`one-fixed-dep-2`]: getPackageDirectoryPath(`one-fixed-dep`, `1.0.0`), + [`no-deps`]: `2.0.0`, + }, + }, + async ({path, run, source}) => { + await run(`install`); + + await expect( + source( + `require('one-fixed-dep-1').dependencies['no-deps'] === require('one-fixed-dep-2').dependencies['no-deps']`, + ), + ).resolves.toEqual(true); + + await expect( + source(`require('one-fixed-dep-1').dependencies['no-deps'] !== require('no-deps')`), + ).resolves.toEqual(true); + await expect( + source(`require('one-fixed-dep-2').dependencies['no-deps'] !== require('no-deps')`), + ).resolves.toEqual(true); + }, + ), + ); + + test( + `it should correctly resolve native Node modules`, + makeTemporaryEnv({}, async ({path, run, source}) => { + await run(`install`); + + await expect(source(`require('fs') ? true : false`)).resolves.toEqual(true); + }), + ); + + test( + `it should correctly resolve relative imports`, + makeTemporaryEnv({}, async ({path, run, source}) => { + await writeFile(`${path}/foo.js`, `module.exports = 42;\n`); + + await run(`install`); + + await expect(source(`require('./foo.js')`)).resolves.toEqual(42); + }), + ); + + test( + `it should correctly resolve deep imports`, + makeTemporaryEnv( + { + dependencies: {[`various-requires`]: `1.0.0`}, + }, + async ({path, run, source}) => { + await run(`install`); + + await expect(source(`require('various-requires/alternative-index')`)).resolves.toEqual(42); + }, + ), + ); + + test( + `it should correctly resolve relative imports from within dependencies`, + makeTemporaryEnv( + { + dependencies: { + [`various-requires`]: `1.0.0`, + }, + }, + async ({path, run, source}) => { + await run(`install`); + + await expect(source(`require('various-requires/relative-require')`)).resolves.toEqual(42); + }, + ), + ); + + test( + `it should throw an exception if a dependency tries to require something it doesn't own`, + makeTemporaryEnv( + {dependencies: {[`various-requires`]: `1.0.0`, [`no-deps`]: `1.0.0`}}, + async ({path, run, source}) => { + await run(`install`); + + await expect(source(`require('various-requires/invalid-require')`)).rejects.toBeTruthy(); + }, + ), + ); + }); +}; diff --git a/packages/pkg-tests/yarn.lock b/packages/pkg-tests/yarn.lock index ca2fe69ee2..1bd61b0d0e 100644 --- a/packages/pkg-tests/yarn.lock +++ b/packages/pkg-tests/yarn.lock @@ -336,12 +336,12 @@ babel-helpers@^6.24.1: babel-runtime "^6.22.0" babel-template "^6.24.1" -babel-jest@^22.2.2: - version "22.2.2" - resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-22.2.2.tgz#eda38dca284e32cc5257f96a9b51351975de4e04" +babel-jest@^22.4.1: + version "22.4.1" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-22.4.1.tgz#ff53ebca45957347f27ff4666a31499fbb4c4ddd" dependencies: babel-plugin-istanbul "^4.1.5" - babel-preset-jest "^22.2.0" + babel-preset-jest "^22.4.1" babel-messages@^6.23.0: version "6.23.0" @@ -363,9 +363,9 @@ babel-plugin-istanbul@^4.1.5: istanbul-lib-instrument "^1.7.5" test-exclude "^4.1.1" -babel-plugin-jest-hoist@^22.2.0: - version "22.2.0" - resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-22.2.0.tgz#bd34f39d652406669713b8c89e23ef25c890b993" +babel-plugin-jest-hoist@^22.4.1: + version "22.4.1" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-22.4.1.tgz#d712fe5da8b6965f3191dacddbefdbdf4fb66d63" babel-plugin-syntax-async-functions@^6.8.0: version "6.13.0" @@ -632,11 +632,11 @@ babel-preset-flow@^6.23.0: dependencies: babel-plugin-transform-flow-strip-types "^6.22.0" -babel-preset-jest@^22.2.0: - version "22.2.0" - resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-22.2.0.tgz#f77b43f06ef4d8547214b2e206cc76a25c3ba0e2" +babel-preset-jest@^22.4.1: + version "22.4.1" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-22.4.1.tgz#efa2e5f5334242a9457a068452d7d09735db172a" dependencies: - babel-plugin-jest-hoist "^22.2.0" + babel-plugin-jest-hoist "^22.4.1" babel-plugin-syntax-object-rest-spread "^6.13.0" babel-register@^6.26.0: @@ -1104,15 +1104,15 @@ expand-range@^1.8.1: dependencies: fill-range "^2.1.0" -expect@^22.3.0: - version "22.3.0" - resolved "https://registry.yarnpkg.com/expect/-/expect-22.3.0.tgz#b1cb7db27a951ab6055f43937277152a9f668028" +expect@^22.4.0: + version "22.4.0" + resolved "https://registry.yarnpkg.com/expect/-/expect-22.4.0.tgz#371edf1ae15b83b5bf5ec34b42f1584660a36c16" dependencies: ansi-styles "^3.2.0" - jest-diff "^22.1.0" + jest-diff "^22.4.0" jest-get-type "^22.1.0" - jest-matcher-utils "^22.2.0" - jest-message-util "^22.2.0" + jest-matcher-utils "^22.4.0" + jest-message-util "^22.4.0" jest-regex-util "^22.1.0" extend@~3.0.0, extend@~3.0.1: @@ -1686,9 +1686,9 @@ jest-changed-files@^22.2.0: dependencies: throat "^4.0.0" -jest-cli@^22.3.0: - version "22.3.0" - resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-22.3.0.tgz#3fd986f2674f4168c91965be56ab9917a82a45db" +jest-cli@^22.4.2: + version "22.4.2" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-22.4.2.tgz#e6546dc651e13d164481aa3e76e53ac4f4edab06" dependencies: ansi-escapes "^3.0.0" chalk "^2.0.1" @@ -1702,17 +1702,18 @@ jest-cli@^22.3.0: istanbul-lib-instrument "^1.8.0" istanbul-lib-source-maps "^1.2.1" jest-changed-files "^22.2.0" - jest-config "^22.3.0" - jest-environment-jsdom "^22.3.0" + jest-config "^22.4.2" + jest-environment-jsdom "^22.4.1" jest-get-type "^22.1.0" - jest-haste-map "^22.3.0" - jest-message-util "^22.2.0" + jest-haste-map "^22.4.2" + jest-message-util "^22.4.0" jest-regex-util "^22.1.0" jest-resolve-dependencies "^22.1.0" - jest-runner "^22.3.0" - jest-runtime "^22.3.0" - jest-snapshot "^22.2.0" - jest-util "^22.3.0" + jest-runner "^22.4.2" + jest-runtime "^22.4.2" + jest-snapshot "^22.4.0" + jest-util "^22.4.1" + jest-validate "^22.4.2" jest-worker "^22.2.2" micromatch "^2.3.11" node-notifier "^5.2.1" @@ -1724,100 +1725,101 @@ jest-cli@^22.3.0: which "^1.2.12" yargs "^10.0.3" -jest-config@^22.3.0: - version "22.3.0" - resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-22.3.0.tgz#94c7149f123933a872ee24c1719687419c4a623c" +jest-config@^22.4.2: + version "22.4.2" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-22.4.2.tgz#580ba5819bf81a5e48f4fd470e8b81834f45c855" dependencies: chalk "^2.0.1" glob "^7.1.1" - jest-environment-jsdom "^22.3.0" - jest-environment-node "^22.3.0" + jest-environment-jsdom "^22.4.1" + jest-environment-node "^22.4.1" jest-get-type "^22.1.0" - jest-jasmine2 "^22.3.0" + jest-jasmine2 "^22.4.2" jest-regex-util "^22.1.0" - jest-resolve "^22.3.0" - jest-util "^22.3.0" - jest-validate "^22.2.2" - pretty-format "^22.1.0" + jest-resolve "^22.4.2" + jest-util "^22.4.1" + jest-validate "^22.4.2" + pretty-format "^22.4.0" -jest-diff@^22.1.0: - version "22.1.0" - resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-22.1.0.tgz#0fad9d96c87b453896bf939df3dc8aac6919ac38" +jest-diff@^22.4.0: + version "22.4.0" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-22.4.0.tgz#384c2b78519ca44ca126382df53f134289232525" dependencies: chalk "^2.0.1" diff "^3.2.0" jest-get-type "^22.1.0" - pretty-format "^22.1.0" + pretty-format "^22.4.0" -jest-docblock@^22.2.2: - version "22.2.2" - resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-22.2.2.tgz#617f13edb16ec64202002b3c336cd14ae36c0631" +jest-docblock@^22.4.0: + version "22.4.0" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-22.4.0.tgz#dbf1877e2550070cfc4d9b07a55775a0483159b8" dependencies: detect-newline "^2.1.0" -jest-environment-jsdom@^22.3.0: - version "22.3.0" - resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-22.3.0.tgz#c267a063e5dc16219fba0e07542d8aa2576a1c88" +jest-environment-jsdom@^22.4.1: + version "22.4.1" + resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-22.4.1.tgz#754f408872441740100d3917e5ec40c74de6447f" dependencies: jest-mock "^22.2.0" - jest-util "^22.3.0" + jest-util "^22.4.1" jsdom "^11.5.1" -jest-environment-node@^22.3.0: - version "22.3.0" - resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-22.3.0.tgz#97d34d9706a718d743075149d1950555c10338c0" +jest-environment-node@^22.4.1: + version "22.4.1" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-22.4.1.tgz#418850eb654596b8d6e36c2021cbedbc23df8e16" dependencies: jest-mock "^22.2.0" - jest-util "^22.3.0" + jest-util "^22.4.1" jest-get-type@^22.1.0: version "22.1.0" resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-22.1.0.tgz#4e90af298ed6181edc85d2da500dbd2753e0d5a9" -jest-haste-map@^22.3.0: - version "22.3.0" - resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-22.3.0.tgz#e7f048a88735bae07ca12de8785eb8bc522adeab" +jest-haste-map@^22.4.2: + version "22.4.2" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-22.4.2.tgz#a90178e66146d4378bb076345a949071f3b015b4" dependencies: fb-watchman "^2.0.0" graceful-fs "^4.1.11" - jest-docblock "^22.2.2" + jest-docblock "^22.4.0" + jest-serializer "^22.4.0" jest-worker "^22.2.2" micromatch "^2.3.11" sane "^2.0.0" -jest-jasmine2@^22.3.0: - version "22.3.0" - resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-22.3.0.tgz#ea127dfbb04c6e03998ae0358225435e47520666" +jest-jasmine2@^22.4.2: + version "22.4.2" + resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-22.4.2.tgz#dfd3d259579ed6f52510d8f1ab692808f0d40691" dependencies: - callsites "^2.0.0" chalk "^2.0.1" co "^4.6.0" - expect "^22.3.0" + expect "^22.4.0" graceful-fs "^4.1.11" is-generator-fn "^1.0.0" - jest-diff "^22.1.0" - jest-matcher-utils "^22.2.0" - jest-message-util "^22.2.0" - jest-snapshot "^22.2.0" + jest-diff "^22.4.0" + jest-matcher-utils "^22.4.0" + jest-message-util "^22.4.0" + jest-snapshot "^22.4.0" + jest-util "^22.4.1" source-map-support "^0.5.0" -jest-leak-detector@^22.1.0: - version "22.1.0" - resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-22.1.0.tgz#08376644cee07103da069baac19adb0299b772c2" +jest-leak-detector@^22.4.0: + version "22.4.0" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-22.4.0.tgz#64da77f05b001c96d2062226e079f89989c4aa2f" dependencies: - pretty-format "^22.1.0" + pretty-format "^22.4.0" -jest-matcher-utils@^22.2.0: - version "22.2.0" - resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-22.2.0.tgz#5390f823c18c748543d463825aa8e4df0db253ca" +jest-matcher-utils@^22.4.0: + version "22.4.0" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-22.4.0.tgz#d55f5faf2270462736bdf7c7485ee931c9d4b6a1" dependencies: chalk "^2.0.1" jest-get-type "^22.1.0" - pretty-format "^22.1.0" + pretty-format "^22.4.0" -jest-message-util@^22.2.0: - version "22.2.0" - resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-22.2.0.tgz#84a6bb34186d8b9af7e0732fabbef63f7355f7b2" +jest-message-util@^22.4.0: + version "22.4.0" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-22.4.0.tgz#e3d861df16d2fee60cb2bc8feac2188a42579642" dependencies: "@babel/code-frame" "^7.0.0-beta.35" chalk "^2.0.1" @@ -1839,45 +1841,46 @@ jest-resolve-dependencies@^22.1.0: dependencies: jest-regex-util "^22.1.0" -jest-resolve@^22.3.0: - version "22.3.0" - resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-22.3.0.tgz#648e797f708e8701071a0fa9fac652c577bb66d9" +jest-resolve@^22.4.2: + version "22.4.2" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-22.4.2.tgz#25d88aa4147462c9c1c6a1ba16250d3794c24d00" dependencies: browser-resolve "^1.11.2" chalk "^2.0.1" -jest-runner@^22.3.0: - version "22.3.0" - resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-22.3.0.tgz#70393f62770be754e2d14f5ca3d896e408aa001a" +jest-runner@^22.4.2: + version "22.4.2" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-22.4.2.tgz#19390ea9d99f768973e16f95a1efa351c0017e87" dependencies: exit "^0.1.2" - jest-config "^22.3.0" - jest-docblock "^22.2.2" - jest-haste-map "^22.3.0" - jest-jasmine2 "^22.3.0" - jest-leak-detector "^22.1.0" - jest-message-util "^22.2.0" - jest-runtime "^22.3.0" - jest-util "^22.3.0" + jest-config "^22.4.2" + jest-docblock "^22.4.0" + jest-haste-map "^22.4.2" + jest-jasmine2 "^22.4.2" + jest-leak-detector "^22.4.0" + jest-message-util "^22.4.0" + jest-runtime "^22.4.2" + jest-util "^22.4.1" jest-worker "^22.2.2" throat "^4.0.0" -jest-runtime@^22.3.0: - version "22.3.0" - resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-22.3.0.tgz#1883d6a4227c1f6af276ead3ed27654257d1ef8c" +jest-runtime@^22.4.2: + version "22.4.2" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-22.4.2.tgz#0de0444f65ce15ee4f2e0055133fc7c17b9168f3" dependencies: babel-core "^6.0.0" - babel-jest "^22.2.2" + babel-jest "^22.4.1" babel-plugin-istanbul "^4.1.5" chalk "^2.0.1" convert-source-map "^1.4.0" exit "^0.1.2" graceful-fs "^4.1.11" - jest-config "^22.3.0" - jest-haste-map "^22.3.0" + jest-config "^22.4.2" + jest-haste-map "^22.4.2" jest-regex-util "^22.1.0" - jest-resolve "^22.3.0" - jest-util "^22.3.0" + jest-resolve "^22.4.2" + jest-util "^22.4.1" + jest-validate "^22.4.2" json-stable-stringify "^1.0.1" micromatch "^2.3.11" realpath-native "^1.0.0" @@ -1886,37 +1889,42 @@ jest-runtime@^22.3.0: write-file-atomic "^2.1.0" yargs "^10.0.3" -jest-snapshot@^22.2.0: - version "22.2.0" - resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-22.2.0.tgz#0c0ba152d296ef70fa198cc84977a2cc269ee4cf" +jest-serializer@^22.4.0: + version "22.4.0" + resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-22.4.0.tgz#b5d145b98c4b0d2c20ab686609adbb81fe23b566" + +jest-snapshot@^22.4.0: + version "22.4.0" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-22.4.0.tgz#03d3ce63f8fa7352388afc6a3c8b5ccc3a180ed7" dependencies: chalk "^2.0.1" - jest-diff "^22.1.0" - jest-matcher-utils "^22.2.0" + jest-diff "^22.4.0" + jest-matcher-utils "^22.4.0" mkdirp "^0.5.1" natural-compare "^1.4.0" - pretty-format "^22.1.0" + pretty-format "^22.4.0" -jest-util@^22.3.0: - version "22.3.0" - resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-22.3.0.tgz#d05bff567a3a86c0e9b3838d812f8290aa768097" +jest-util@^22.4.1: + version "22.4.1" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-22.4.1.tgz#dd17c3bdb067f8e90591563ec0c42bf847dc249f" dependencies: callsites "^2.0.0" chalk "^2.0.1" graceful-fs "^4.1.11" is-ci "^1.0.10" - jest-message-util "^22.2.0" - jest-validate "^22.2.2" + jest-message-util "^22.4.0" mkdirp "^0.5.1" + source-map "^0.6.0" -jest-validate@^22.2.2: - version "22.2.2" - resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-22.2.2.tgz#9cdce422c93cc28395e907ac6bbc929158d9a6ba" +jest-validate@^22.4.2: + version "22.4.2" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-22.4.2.tgz#e789a4e056173bf97fe797a2df2d52105c57d4f4" dependencies: chalk "^2.0.1" + jest-config "^22.4.2" jest-get-type "^22.1.0" leven "^2.1.0" - pretty-format "^22.1.0" + pretty-format "^22.4.0" jest-worker@^22.2.2: version "22.2.2" @@ -1924,12 +1932,12 @@ jest-worker@^22.2.2: dependencies: merge-stream "^1.0.1" -jest@^22.3.0: - version "22.3.0" - resolved "https://registry.yarnpkg.com/jest/-/jest-22.3.0.tgz#07434314d2e8662ea936552d950680b7e6551b0d" +jest@^22.4.2: + version "22.4.2" + resolved "https://registry.yarnpkg.com/jest/-/jest-22.4.2.tgz#34012834a49bf1bdd3bc783850ab44e4499afc20" dependencies: import-local "^1.0.0" - jest-cli "^22.3.0" + jest-cli "^22.4.2" js-tokens@^3.0.0, js-tokens@^3.0.2: version "3.0.2" @@ -2461,9 +2469,9 @@ prettier@^1.10.2: version "1.10.2" resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.10.2.tgz#1af8356d1842276a99a5b5529c82dd9e9ad3cc93" -pretty-format@^22.1.0: - version "22.1.0" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-22.1.0.tgz#2277605b40ed4529ae4db51ff62f4be817647914" +pretty-format@^22.4.0: + version "22.4.0" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-22.4.0.tgz#237b1f7e1c50ed03bc65c03ccc29d7c8bb7beb94" dependencies: ansi-regex "^3.0.0" ansi-styles "^3.2.0" diff --git a/packages/pkg-tests/yarn.test.js b/packages/pkg-tests/yarn.test.js index 0f2eb61ebe..0f035eb64f 100644 --- a/packages/pkg-tests/yarn.test.js +++ b/packages/pkg-tests/yarn.test.js @@ -5,12 +5,21 @@ const { exec: {execFile}, } = require(`pkg-tests-core`); -const {basic: basicSpecs, dragon: dragonSpecs} = require(`pkg-tests-specs`); +const {basic: basicSpecs, dragon: dragonSpecs, pnp: pnpSpecs} = require(`pkg-tests-specs`); const pkgDriver = generatePkgDriver({ - runDriver: (path, args, {registryUrl}) => { - const extraArgs = [`--cache-folder`, `${path}/.cache`]; - return execFile(process.execPath, [`${process.cwd()}/../../bin/yarn.js`, ...extraArgs, ...args], { + runDriver: (path, [command, ...args], {registryUrl, plugNPlay}) => { + let extraArgs = []; + + if (command !== 'node') { + extraArgs = [...extraArgs, `--cache-folder`, `${path}/.cache`]; + } + + if (plugNPlay) { + extraArgs; + } + + return execFile(process.execPath, [`${process.cwd()}/../../bin/yarn.js`, command, ...extraArgs, ...args], { env: {[`NPM_CONFIG_REGISTRY`]: registryUrl, [`YARN_SILENT`]: `1`}, cwd: path, }); @@ -24,3 +33,4 @@ beforeEach(async () => { basicSpecs(pkgDriver); dragonSpecs(pkgDriver); +pnpSpecs(pkgDriver); From 3711775298e48d702aaf60585818a4e5b6ccf23a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Wed, 28 Feb 2018 13:12:12 +0000 Subject: [PATCH 005/111] Fixes various issues with the pnp map generation Branch: pnp-map-improvements --- src/util/generate-pnp-map.js | 43 +++++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 13 deletions(-) diff --git a/src/util/generate-pnp-map.js b/src/util/generate-pnp-map.js index 68f2925377..28b76ee86a 100644 --- a/src/util/generate-pnp-map.js +++ b/src/util/generate-pnp-map.js @@ -1,5 +1,6 @@ // @flow +import type Config from '../config.js'; import type PackageResolver from '../package-resolver.js'; import * as fs from './fs.js'; @@ -73,14 +74,18 @@ function generateFindPackageLocator(packageInformationStores: PackageInformation }); // Generate a function that, given a file path, returns the associated package name - code += `exports.findPackageLocator = function findPackageLocator(path) {\n`; + code += `exports.findPackageLocator = function findPackageLocator(location) {\n`; code += `\n`; code += ` let match;\n`; - for (const length of sortedLengths.keys()) { - code += ` if (match = locatorsByLocations.get(path.substr(0, ${length}))) return match;\n`; + for (const [length, count] of sortedLengths) { + code += `\n`; + code += ` if (location.length >= ${length} && location[${length} - 1] === path.sep)\n`; + code += ` if (match = locatorsByLocations.get(location.substr(0, ${length})))\n`; + code += ` return match;\n`; } + code += `\n`; code += ` return null;\n`; code += `};\n`; @@ -127,8 +132,14 @@ function generateGetPackageDependencies(packageInformationStores: PackageInforma } /* eslint-disable max-len */ -const REQUIRE_HOOK = ` -let Module = require(\`module\`); +const PROLOGUE = ` +let path = require('path'); +`; +/* eslint-enable max-len */ + +/* eslint-disable max-len */ +const REQUIRE_HOOK = lockfileFolder => ` +let Module = require('module'); let originalResolver = Module._resolveFilename; let pathRegExp = /^(?!\\.{0,2}\\/)([^\\/]+)(\\/.*|)$/; @@ -143,8 +154,13 @@ Module._resolveFilename = function (request, parent, isMain, options) { if (!dependencyNameMatch) return originalResolver.call(Module, request, parent, isMain, options); - let packagePath = parent.filename ? parent.filename : process.cwd(); - let packageLocator = parent.filename ? exports.findPackageLocator(packagePath) : { name: null, reference: null }; + let caller = parent; + + while (caller && (caller.id === '[eval]' || caller.id === '' || !caller.filename)) + caller = caller.parent; + + let packagePath = caller ? caller.filename : process.cwd() + path.sep; + let packageLocator = exports.findPackageLocator(packagePath); if (!packageLocator) throw new Error(\`Could not find to which package belongs the path \${packagePath}\`); @@ -171,6 +187,7 @@ Module._resolveFilename = function (request, parent, isMain, options) { /* eslint-enable */ async function getPackageInformationStores( + config: Config, seedPatterns: Array, {resolver}: {resolver: PackageResolver}, ): PackageInformationStores { @@ -197,7 +214,7 @@ async function getPackageInformationStores( } packageInformationStore.set(pkg.version, { - packageLocation: (await fs.realpath(loc)).replace(/\/$/, path.sep), + packageLocation: (await fs.realpath(loc)).replace(/[\\\/]?$/, path.sep), packageDependencies, }); } @@ -218,7 +235,7 @@ async function getPackageInformationStores( [ null, { - packageLocation: null, + packageLocation: (await fs.realpath(config.lockfileFolder)).replace(/[\\\/]?$/, path.sep), packageDependencies: topLevelDependencies, }, ], @@ -229,10 +246,10 @@ async function getPackageInformationStores( return packageInformationStores; } -export async function generatePnpMap(seedPatterns: Array, {resolver}: {resolver: PackageResolver}): string { - const packageInformationStores = await getPackageInformationStores(seedPatterns, {resolver}); +export async function generatePnpMap(config: Config, seedPatterns: Array, {resolver}: {resolver: PackageResolver}): string { + const packageInformationStores = await getPackageInformationStores(config, seedPatterns, {resolver}); - let code = ``; + let code = PROLOGUE; code += generateMaps(packageInformationStores); @@ -240,7 +257,7 @@ export async function generatePnpMap(seedPatterns: Array, {resolver}: {r code += generateGetPackageLocation(packageInformationStores); code += generateGetPackageDependencies(packageInformationStores); - code += REQUIRE_HOOK; + code += REQUIRE_HOOK(config.lockfileFolder); return code; } From 51adb4ca923fa6575dd9f5485c53b730d54ebc85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Thu, 1 Mar 2018 19:30:38 +0000 Subject: [PATCH 006/111] Remove the scriptsPrependNodePath option Branch: lifecycle-wrappers-remove-option --- src/cli/index.js | 1 - src/config.js | 1 - src/util/execute-lifecycle-script.js | 3 --- 3 files changed, 5 deletions(-) diff --git a/src/cli/index.js b/src/cli/index.js index b5a17d537a..17a275dcc6 100644 --- a/src/cli/index.js +++ b/src/cli/index.js @@ -489,7 +489,6 @@ export function main({ networkConcurrency: commander.networkConcurrency, networkTimeout: commander.networkTimeout, nonInteractive: commander.nonInteractive, - scriptsPrependNodePath: commander.scriptsPrependNodePath, updateChecksums: commander.updateChecksums, }) .then(() => { diff --git a/src/config.js b/src/config.js index f784729087..2326f27f6c 100644 --- a/src/config.js +++ b/src/config.js @@ -47,7 +47,6 @@ export type ConfigOptions = { childConcurrency?: number, networkTimeout?: number, nonInteractive?: boolean, - scriptsPrependNodePath?: boolean, // Loosely compare semver for invalid cases like "0.01.0" looseSemver?: ?boolean, diff --git a/src/util/execute-lifecycle-script.js b/src/util/execute-lifecycle-script.js index bacf91bca7..d6320c54e0 100644 --- a/src/util/execute-lifecycle-script.js +++ b/src/util/execute-lifecycle-script.js @@ -159,9 +159,6 @@ export async function makeEnv( pathParts.unshift(path.join(cwd, binFolder)); } - if (config.scriptsPrependNodePath) { - pathParts.unshift(path.join(path.dirname(process.execPath))); - } // join path back together env[constants.ENV_PATH_KEY] = pathParts.join(path.delimiter); From 961d24275708529690bf40b067d28682057e2b7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Thu, 1 Mar 2018 19:32:30 +0000 Subject: [PATCH 007/111] Adds tests to ensure that the lifecycle scripts are called with the right binaries Branch: lifecycle-wrappers-tests --- .../pkg-tests-core/sources/utils/fs.js | 12 ++++++++ .../pkg-tests-specs/sources/index.js | 1 + .../pkg-tests/pkg-tests-specs/sources/pnp.js | 17 +++++++++++ .../pkg-tests-specs/sources/script.js | 30 +++++++++++++++++++ packages/pkg-tests/yarn.test.js | 13 ++++++-- 5 files changed, 70 insertions(+), 3 deletions(-) create mode 100644 packages/pkg-tests/pkg-tests-specs/sources/script.js diff --git a/packages/pkg-tests/pkg-tests-core/sources/utils/fs.js b/packages/pkg-tests/pkg-tests-core/sources/utils/fs.js index 16310e1ffe..5ba29aa737 100644 --- a/packages/pkg-tests/pkg-tests-core/sources/utils/fs.js +++ b/packages/pkg-tests/pkg-tests-core/sources/utils/fs.js @@ -173,3 +173,15 @@ exports.readJson = async function readJson(source: string): Promise { throw new Error(`Invalid json file (${source})`); } }; + +exports.chmod = function chmod(target: string, mod: number): Promise { + return fs.chmod(target, mod); +}; + +exports.makeFakeBinary = async function( + target: string, + {output = `Fake binary`, exitCode = 1}: {|output: string, exitCode: number|} = {}, +): Promise { + await exports.writeFile(target, `#!/bin/sh\necho "${output}"\nexit ${exitCode}\n`); + await exports.chmod(target, 0o755); +}; diff --git a/packages/pkg-tests/pkg-tests-specs/sources/index.js b/packages/pkg-tests/pkg-tests-specs/sources/index.js index 000310a08f..383969741e 100644 --- a/packages/pkg-tests/pkg-tests-specs/sources/index.js +++ b/packages/pkg-tests/pkg-tests-specs/sources/index.js @@ -3,3 +3,4 @@ exports.basic = require('./basic'); exports.dragon = require('./dragon'); exports.pnp = require('./pnp'); +exports.script = require('./script'); diff --git a/packages/pkg-tests/pkg-tests-specs/sources/pnp.js b/packages/pkg-tests/pkg-tests-specs/sources/pnp.js index 91e870c526..39b0f3618d 100644 --- a/packages/pkg-tests/pkg-tests-specs/sources/pnp.js +++ b/packages/pkg-tests/pkg-tests-specs/sources/pnp.js @@ -122,5 +122,22 @@ module.exports = makeTemporaryEnv => { }, ), ); + + test( + `it should run scripts using a Node version that auto-injects the hook`, + makeTemporaryEnv( + { + dependencies: {[`no-deps`]: `1.0.0`}, + scripts: {myScript: `node -p 'require("no-deps/package.json").version'`}, + }, + async ({path, run}) => { + await run(`install`); + + await expect(run(`myScript`)).resolves.toMatchObject({ + stdout: `1.0.0\n`, + }); + }, + ), + ); }); }; diff --git a/packages/pkg-tests/pkg-tests-specs/sources/script.js b/packages/pkg-tests/pkg-tests-specs/sources/script.js new file mode 100644 index 0000000000..8f6f659cfd --- /dev/null +++ b/packages/pkg-tests/pkg-tests-specs/sources/script.js @@ -0,0 +1,30 @@ +/* @flow */ + +import type {PackageDriver} from 'pkg-tests-core'; + +const {fs: {makeFakeBinary}} = require(`pkg-tests-core`); + +module.exports = (makeTemporaryEnv: PackageDriver) => { + describe(`Scripts tests`, () => { + test( + `it should run scripts using the same Node than the one used by Yarn`, + makeTemporaryEnv({scripts: {myScript: `node --version`}}, async ({path, run, source}) => { + await makeFakeBinary(`${path}/bin/node`); + + await expect(run(`run`, `myScript`)).resolves.toMatchObject({ + stdout: `${process.version}\n`, + }); + }), + ); + test( + `it should run scripts using the same package manager than the one running the scripts`, + makeTemporaryEnv({scripts: {myScript: `yarn --version`}}, async ({path, run, source}) => { + await makeFakeBinary(`${path}/bin/yarn`); + + await expect(run(`run`, `myScript`)).resolves.toMatchObject({ + stdout: (await run(`--version`)).stdout, + }); + }), + ); + }); +}; diff --git a/packages/pkg-tests/yarn.test.js b/packages/pkg-tests/yarn.test.js index 0f035eb64f..7a5ba38e45 100644 --- a/packages/pkg-tests/yarn.test.js +++ b/packages/pkg-tests/yarn.test.js @@ -1,17 +1,19 @@ /* @flow */ +const {delimiter} = require(`path`); + const { tests: {generatePkgDriver, startPackageServer, getPackageRegistry}, exec: {execFile}, } = require(`pkg-tests-core`); -const {basic: basicSpecs, dragon: dragonSpecs, pnp: pnpSpecs} = require(`pkg-tests-specs`); +const {basic: basicSpecs, dragon: dragonSpecs, pnp: pnpSpecs, script: scriptSpecs} = require(`pkg-tests-specs`); const pkgDriver = generatePkgDriver({ runDriver: (path, [command, ...args], {registryUrl, plugNPlay}) => { let extraArgs = []; - if (command !== 'node') { + if (command === 'install') { extraArgs = [...extraArgs, `--cache-folder`, `${path}/.cache`]; } @@ -20,7 +22,11 @@ const pkgDriver = generatePkgDriver({ } return execFile(process.execPath, [`${process.cwd()}/../../bin/yarn.js`, command, ...extraArgs, ...args], { - env: {[`NPM_CONFIG_REGISTRY`]: registryUrl, [`YARN_SILENT`]: `1`}, + env: { + [`NPM_CONFIG_REGISTRY`]: registryUrl, + [`YARN_SILENT`]: `1`, + [`PATH`]: `${path}/bin${delimiter}${process.env.PATH}`, + }, cwd: path, }); }, @@ -34,3 +40,4 @@ beforeEach(async () => { basicSpecs(pkgDriver); dragonSpecs(pkgDriver); pnpSpecs(pkgDriver); +scriptSpecs(pkgDriver); From cf9dd1a4f9787cb1ba6999909e7eca42249f3c07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Thu, 1 Mar 2018 19:34:52 +0000 Subject: [PATCH 008/111] Fixes linting Branch: lifecycle-wrappers-flowlint --- src/cli/commands/node.js | 2 +- src/util/generate-pnp-map.js | 16 ++++++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/cli/commands/node.js b/src/cli/commands/node.js index be0db3ab60..4f1604b88e 100644 --- a/src/cli/commands/node.js +++ b/src/cli/commands/node.js @@ -16,7 +16,7 @@ export async function run(config: Config, reporter: Reporter, flags: Object, arg const pnpPath = `${config.lockfileFolder}/${PNP_FILENAME}`; if (await fs.exists(pnpPath)) { - args = ['-r', pnpPath, ... args]; + args = ['-r', pnpPath, ...args]; } try { diff --git a/src/util/generate-pnp-map.js b/src/util/generate-pnp-map.js index 28b76ee86a..e9764484f5 100644 --- a/src/util/generate-pnp-map.js +++ b/src/util/generate-pnp-map.js @@ -7,8 +7,8 @@ import * as fs from './fs.js'; const path = require('path'); type PackageInformation = {|packageLocation: string, packageDependencies: Map|}; -type PackageInformationStore = Map; -type PackageInformationStores = Map; +type PackageInformationStore = Map; +type PackageInformationStores = Map; function generateMaps(packageInformationStores: PackageInformationStores): string { let code = ``; @@ -78,7 +78,7 @@ function generateFindPackageLocator(packageInformationStores: PackageInformation code += `\n`; code += ` let match;\n`; - for (const [length, count] of sortedLengths) { + for (const [length] of sortedLengths) { code += `\n`; code += ` if (location.length >= ${length} && location[${length} - 1] === path.sep)\n`; code += ` if (match = locatorsByLocations.get(location.substr(0, ${length})))\n`; @@ -190,7 +190,7 @@ async function getPackageInformationStores( config: Config, seedPatterns: Array, {resolver}: {resolver: PackageResolver}, -): PackageInformationStores { +): Promise { const packageInformationStores = new Map(); const pkgs = resolver.getTopologicalManifests(seedPatterns); @@ -198,7 +198,7 @@ async function getPackageInformationStores( for (const pkg of pkgs) { if (pkg._reference && pkg._reference.location && pkg._reference.isPlugnplay) { const ref = pkg._reference; - const loc = ref.location; + const loc = pkg._reference.location; let packageInformationStore = packageInformationStores.get(pkg.name); @@ -246,7 +246,11 @@ async function getPackageInformationStores( return packageInformationStores; } -export async function generatePnpMap(config: Config, seedPatterns: Array, {resolver}: {resolver: PackageResolver}): string { +export async function generatePnpMap( + config: Config, + seedPatterns: Array, + {resolver}: {resolver: PackageResolver}, +): Promise { const packageInformationStores = await getPackageInformationStores(config, seedPatterns, {resolver}); let code = PROLOGUE; From 17e3d68b8e80ba283d33b6bd04435d9585fe9b57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Thu, 1 Mar 2018 19:35:21 +0000 Subject: [PATCH 009/111] Improve the error message when an optional required dependency hasn't been installed Branch: lifecycle-wrappers-improve-pnp-error --- src/util/generate-pnp-map.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/util/generate-pnp-map.js b/src/util/generate-pnp-map.js index e9764484f5..55d21b7bbf 100644 --- a/src/util/generate-pnp-map.js +++ b/src/util/generate-pnp-map.js @@ -180,6 +180,9 @@ Module._resolveFilename = function (request, parent, isMain, options) { let dependencyLocation = exports.getPackageLocation({ name: dependencyName, reference: dependencyReference }); + if (!dependencyLocation) + throw new Error(\`Package \${dependencyName}@\${dependencyReference} is a valid dependency, but hasn't been installed and thus cannot be required\`); + return originalResolver.call(Module, \`\${dependencyLocation}/\${subPath}\`, parent, isMain, options); }; From 882055d9a112ae795b6144505f5604a0d525b106 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Thu, 1 Mar 2018 19:36:16 +0000 Subject: [PATCH 010/111] Implements lifecycle wrappers Branch: lifecycle-wrappers-main --- src/util/execute-lifecycle-script.js | 46 ++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/src/util/execute-lifecycle-script.js b/src/util/execute-lifecycle-script.js index d6320c54e0..4e3bb05714 100644 --- a/src/util/execute-lifecycle-script.js +++ b/src/util/execute-lifecycle-script.js @@ -5,7 +5,7 @@ import type Config from '../config.js'; import {MessageError, ProcessTermError} from '../errors.js'; import * as constants from '../constants.js'; import * as child from './child.js'; -import {exists} from './fs.js'; +import * as fs from './fs.js'; import {registries} from '../resolvers/index.js'; import {fixCmdWinSlashes} from './fix-cmd-win-slashes.js'; import {run as globalRun, getBinFolder as getGlobalBinFolder} from '../cli/commands/global.js'; @@ -26,6 +26,47 @@ const IGNORE_MANIFEST_KEYS = ['readme']; // See https://github.com/yarnpkg/yarn/issues/2286. const IGNORE_CONFIG_KEYS = ['lastUpdateCheck']; +const NODE_SIMPLE_SH_WRAPPER = (config: Config) => `#!/bin/sh +"${JSON.stringify(process.execPath)}" "$@" +`; + +const NODE_PNP_SH_WRAPPER = (config: Config) => `#!/bin/sh +"${JSON.stringify(process.execPath)}" -r "${config.lockfileFolder}/${constants.PNP_FILENAME}" "$@" +`; + +const NODE_SH_WRAPPER = async (config: Config) => { + if (await fs.exists(`${config.lockfileFolder}/${constants.PNP_FILENAME}`)) { + return NODE_PNP_SH_WRAPPER(config); + } else { + return NODE_SIMPLE_SH_WRAPPER(config); + } +}; + +const YARN_SH_WRAPPER = (config: Config) => `#!/bin/sh +"${JSON.stringify(process.execPath)}" "${process.argv[1]}" "$@" +`; + +const LIFECYCLE_WRAPPERS = [[`yarn`, YARN_SH_WRAPPER], [`node`, NODE_SH_WRAPPER]]; + +let wrappersFolder = null; + +export async function getWrappersFolder(config: Config): Promise { + if (wrappersFolder) { + return wrappersFolder; + } + + wrappersFolder = await fs.makeTempDir(); + + for (const [fileName, content] of LIFECYCLE_WRAPPERS) { + const wrapperPath = `${wrappersFolder}/${fileName}`; + + await fs.writeFile(wrapperPath, await content(config)); + await fs.chmod(wrapperPath, 0o755); + } + + return wrappersFolder; +} + export async function makeEnv( stage: string, cwd: string, @@ -159,6 +200,7 @@ export async function makeEnv( pathParts.unshift(path.join(cwd, binFolder)); } + pathParts.unshift(await getWrappersFolder(config)); // join path back together env[constants.ENV_PATH_KEY] = pathParts.join(path.delimiter); @@ -245,7 +287,7 @@ async function _checkForGyp(config: Config, paths: Array): Promise const {reporter} = config; // Check every directory in the PATH - const allChecks = await Promise.all(paths.map(dir => exists(path.join(dir, 'node-gyp')))); + const allChecks = await Promise.all(paths.map(dir => fs.exists(path.join(dir, 'node-gyp')))); if (allChecks.some(Boolean)) { // node-gyp is available somewhere return; From 0bdb6dd62ecc0ea9cd3bf77d213f167c7fdac479 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Fri, 2 Mar 2018 17:35:18 +0000 Subject: [PATCH 011/111] Adds .pnp.js files to the gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index e6bb801249..809363f43e 100644 --- a/.gitignore +++ b/.gitignore @@ -21,4 +21,5 @@ test/fixtures/**/.fbkpm /__tests__/fixtures/request-cache/GET/localhost/.bin .idea .yarn-meta +.pnp.js /packages/lockfile/index.js From b9f8eaf5e294f3d9b0bbfdf1cc4a7703b79b063b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Fri, 2 Mar 2018 17:48:01 +0000 Subject: [PATCH 012/111] Fallbacks to the toplevel dependencies when a transitive dependency cannot be resolved --- .../pkg-tests/pkg-tests-specs/sources/pnp.js | 17 ++++++++++++++++- src/util/generate-pnp-map.js | 14 ++++++++++---- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/packages/pkg-tests/pkg-tests-specs/sources/pnp.js b/packages/pkg-tests/pkg-tests-specs/sources/pnp.js index 39b0f3618d..44667b6e9e 100644 --- a/packages/pkg-tests/pkg-tests-specs/sources/pnp.js +++ b/packages/pkg-tests/pkg-tests-specs/sources/pnp.js @@ -112,12 +112,27 @@ module.exports = makeTemporaryEnv => { ); test( - `it should throw an exception if a dependency tries to require something it doesn't own`, + `it should fallback to the top-level dependencies when it cannot require a transitive dependency require`, makeTemporaryEnv( {dependencies: {[`various-requires`]: `1.0.0`, [`no-deps`]: `1.0.0`}}, async ({path, run, source}) => { await run(`install`); + await expect(source(`require('various-requires/invalid-require')`)).resolves.toMatchObject({ + name: `no-deps`, + version: `1.0.0`, + }); + }, + ), + ); + + test( + `it should throw an exception if a dependency tries to require something it doesn't own`, + makeTemporaryEnv( + {dependencies: {[`various-requires`]: `1.0.0`}}, + async ({path, run, source}) => { + await run(`install`); + await expect(source(`require('various-requires/invalid-require')`)).rejects.toBeTruthy(); }, ), diff --git a/src/util/generate-pnp-map.js b/src/util/generate-pnp-map.js index 55d21b7bbf..d625194697 100644 --- a/src/util/generate-pnp-map.js +++ b/src/util/generate-pnp-map.js @@ -165,17 +165,23 @@ Module._resolveFilename = function (request, parent, isMain, options) { if (!packageLocator) throw new Error(\`Could not find to which package belongs the path \${packagePath}\`); - let packageDependencies = exports.getPackageDependencies(packageLocator); - let [ , dependencyName, subPath ] = dependencyNameMatch; + + let packageDependencies = exports.getPackageDependencies(packageLocator); let dependencyReference = packageDependencies.get(dependencyName); if (!dependencyReference) { - if (packageLocator.name === null) { + + if (packageLocator.name === null) throw new Error(\`You cannot require a package (\${dependencyName}) that is not declared in your dependencies\`); - } else { + + let topLevelDependencies = exports.getPackageDependencies({ name: null, reference: null }); + dependencyReference = topLevelDependencies.get(dependencyName); + + if (!dependencyReference) { throw new Error(\`Package \${packageLocator.name}@\${packageLocator.reference} is trying to require package \${dependencyName}, which is not declared in its dependencies (\${Array.from(packageDependencies.keys()).join(\`, \`)})\`); } + } let dependencyLocation = exports.getPackageLocation({ name: dependencyName, reference: dependencyReference }); From 40972bca00111b1882495fc563115e3b23a35b99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Fri, 2 Mar 2018 19:05:50 +0000 Subject: [PATCH 013/111] Fixes an issue inside the pkg-tests helper Branch: pkg-tests-helper-definition --- packages/pkg-tests/pkg-tests-core/sources/utils/tests.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/pkg-tests/pkg-tests-core/sources/utils/tests.js b/packages/pkg-tests/pkg-tests-core/sources/utils/tests.js index df06acf79a..eaaa25b071 100644 --- a/packages/pkg-tests/pkg-tests-core/sources/utils/tests.js +++ b/packages/pkg-tests/pkg-tests-core/sources/utils/tests.js @@ -310,6 +310,7 @@ exports.generatePkgDriver = function generatePkgDriver({runDriver}: {|runDriver: const run = (...args) => { return runDriver(path, args, { registryUrl, + ...definition, ...subDefinition, }); }; From cf00d52e0aea194b6feb69d0fc1fafbfe03f93a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Fri, 2 Mar 2018 19:06:52 +0000 Subject: [PATCH 014/111] Improves the fixtures so that they also return info about their dev and peer dependencies Branch: dev-peer-fixtures --- packages/pkg-tests/pkg-tests-fixtures/default-index.js | 8 +++++--- .../packages/dep-loop-entry-1.0.0/index.js | 9 +++++++-- .../packages/dep-loop-exit-1.0.0/index.js | 9 +++++++-- .../pkg-tests-fixtures/packages/dev-deps-1.0.0/index.js | 9 +++++++-- .../packages/dragon-test-1-a-1.0.0/index.js | 9 +++++++-- .../packages/dragon-test-1-b-1.0.0/index.js | 9 +++++++-- .../packages/dragon-test-1-b-2.0.0/index.js | 9 +++++++-- .../packages/dragon-test-1-c-1.0.0/index.js | 9 +++++++-- .../packages/dragon-test-1-d-1.0.0/index.js | 9 +++++++-- .../packages/dragon-test-1-e-1.0.0/index.js | 9 +++++++-- .../packages/hoisting-peer-check-child-1.0.0/index.js | 9 +++++++-- .../packages/hoisting-peer-check-parent-1.0.0/index.js | 9 +++++++-- .../pkg-tests-fixtures/packages/no-deps-1.0.0/index.js | 9 +++++++-- .../pkg-tests-fixtures/packages/no-deps-1.0.1/index.js | 9 +++++++-- .../pkg-tests-fixtures/packages/no-deps-1.1.0/index.js | 9 +++++++-- .../pkg-tests-fixtures/packages/no-deps-2.0.0/index.js | 9 +++++++-- .../packages/no-deps-bins-1.0.0/index.js | 9 +++++++-- .../packages/no-deps-bins-2.0.0/index.js | 9 +++++++-- .../packages/no-deps-checked-1.0.0/index.js | 9 +++++++-- .../packages/no-deps-failing-1.0.0/index.js | 9 +++++++-- .../packages/no-deps-scripted-1.0.0/index.js | 9 +++++++-- .../packages/one-deep1-dep-bins/index.js | 9 +++++++-- .../packages/one-deep2-dep-bins-1.0.0/index.js | 9 +++++++-- .../packages/one-fixed-dep-1.0.0/index.js | 9 +++++++-- .../packages/one-fixed-dep-bins-0.0.0/index.js | 9 +++++++-- .../packages/one-fixed-dep-bins-1.0.0/index.js | 9 +++++++-- .../packages/one-fixed-dep-bins-2.0.0/index.js | 9 +++++++-- .../packages/one-fixed-dep-checked-1.0.0/index.js | 9 +++++++-- .../packages/one-fixed-dep-scripted-1.0.0/index.js | 9 +++++++-- .../packages/one-range-dep-1.0.0/index.js | 9 +++++++-- .../packages/various-requires-1.0.0/index.js | 9 +++++++-- 31 files changed, 215 insertions(+), 63 deletions(-) diff --git a/packages/pkg-tests/pkg-tests-fixtures/default-index.js b/packages/pkg-tests/pkg-tests-fixtures/default-index.js index 1aa13242b9..a6bf8f5865 100644 --- a/packages/pkg-tests/pkg-tests-fixtures/default-index.js +++ b/packages/pkg-tests/pkg-tests-fixtures/default-index.js @@ -2,7 +2,9 @@ module.exports = require(`./package.json`); -for (const key of Object.keys(module.exports.dependencies || {})) { - // $FlowFixMe The whole point of this file is to be dynamic - module.exports.dependencies[key] = require(key); +for (const key of [`dependencies`, `devDependencies`, `peerDependencies`]) { + for (const dep of Object.keys(module.exports[key] || {})) { + // $FlowFixMe The whole point of this file is to be dynamic + module.exports[key][dep] = require(dep); + } } diff --git a/packages/pkg-tests/pkg-tests-fixtures/packages/dep-loop-entry-1.0.0/index.js b/packages/pkg-tests/pkg-tests-fixtures/packages/dep-loop-entry-1.0.0/index.js index b375424a4e..a6bf8f5865 100644 --- a/packages/pkg-tests/pkg-tests-fixtures/packages/dep-loop-entry-1.0.0/index.js +++ b/packages/pkg-tests/pkg-tests-fixtures/packages/dep-loop-entry-1.0.0/index.js @@ -1,5 +1,10 @@ +/* @flow */ + module.exports = require(`./package.json`); -for (const key of Object.keys(module.exports.dependencies || {})) { - module.exports.dependencies[key] = require(key); +for (const key of [`dependencies`, `devDependencies`, `peerDependencies`]) { + for (const dep of Object.keys(module.exports[key] || {})) { + // $FlowFixMe The whole point of this file is to be dynamic + module.exports[key][dep] = require(dep); + } } diff --git a/packages/pkg-tests/pkg-tests-fixtures/packages/dep-loop-exit-1.0.0/index.js b/packages/pkg-tests/pkg-tests-fixtures/packages/dep-loop-exit-1.0.0/index.js index b375424a4e..a6bf8f5865 100644 --- a/packages/pkg-tests/pkg-tests-fixtures/packages/dep-loop-exit-1.0.0/index.js +++ b/packages/pkg-tests/pkg-tests-fixtures/packages/dep-loop-exit-1.0.0/index.js @@ -1,5 +1,10 @@ +/* @flow */ + module.exports = require(`./package.json`); -for (const key of Object.keys(module.exports.dependencies || {})) { - module.exports.dependencies[key] = require(key); +for (const key of [`dependencies`, `devDependencies`, `peerDependencies`]) { + for (const dep of Object.keys(module.exports[key] || {})) { + // $FlowFixMe The whole point of this file is to be dynamic + module.exports[key][dep] = require(dep); + } } diff --git a/packages/pkg-tests/pkg-tests-fixtures/packages/dev-deps-1.0.0/index.js b/packages/pkg-tests/pkg-tests-fixtures/packages/dev-deps-1.0.0/index.js index b375424a4e..a6bf8f5865 100644 --- a/packages/pkg-tests/pkg-tests-fixtures/packages/dev-deps-1.0.0/index.js +++ b/packages/pkg-tests/pkg-tests-fixtures/packages/dev-deps-1.0.0/index.js @@ -1,5 +1,10 @@ +/* @flow */ + module.exports = require(`./package.json`); -for (const key of Object.keys(module.exports.dependencies || {})) { - module.exports.dependencies[key] = require(key); +for (const key of [`dependencies`, `devDependencies`, `peerDependencies`]) { + for (const dep of Object.keys(module.exports[key] || {})) { + // $FlowFixMe The whole point of this file is to be dynamic + module.exports[key][dep] = require(dep); + } } diff --git a/packages/pkg-tests/pkg-tests-fixtures/packages/dragon-test-1-a-1.0.0/index.js b/packages/pkg-tests/pkg-tests-fixtures/packages/dragon-test-1-a-1.0.0/index.js index b375424a4e..a6bf8f5865 100644 --- a/packages/pkg-tests/pkg-tests-fixtures/packages/dragon-test-1-a-1.0.0/index.js +++ b/packages/pkg-tests/pkg-tests-fixtures/packages/dragon-test-1-a-1.0.0/index.js @@ -1,5 +1,10 @@ +/* @flow */ + module.exports = require(`./package.json`); -for (const key of Object.keys(module.exports.dependencies || {})) { - module.exports.dependencies[key] = require(key); +for (const key of [`dependencies`, `devDependencies`, `peerDependencies`]) { + for (const dep of Object.keys(module.exports[key] || {})) { + // $FlowFixMe The whole point of this file is to be dynamic + module.exports[key][dep] = require(dep); + } } diff --git a/packages/pkg-tests/pkg-tests-fixtures/packages/dragon-test-1-b-1.0.0/index.js b/packages/pkg-tests/pkg-tests-fixtures/packages/dragon-test-1-b-1.0.0/index.js index b375424a4e..a6bf8f5865 100644 --- a/packages/pkg-tests/pkg-tests-fixtures/packages/dragon-test-1-b-1.0.0/index.js +++ b/packages/pkg-tests/pkg-tests-fixtures/packages/dragon-test-1-b-1.0.0/index.js @@ -1,5 +1,10 @@ +/* @flow */ + module.exports = require(`./package.json`); -for (const key of Object.keys(module.exports.dependencies || {})) { - module.exports.dependencies[key] = require(key); +for (const key of [`dependencies`, `devDependencies`, `peerDependencies`]) { + for (const dep of Object.keys(module.exports[key] || {})) { + // $FlowFixMe The whole point of this file is to be dynamic + module.exports[key][dep] = require(dep); + } } diff --git a/packages/pkg-tests/pkg-tests-fixtures/packages/dragon-test-1-b-2.0.0/index.js b/packages/pkg-tests/pkg-tests-fixtures/packages/dragon-test-1-b-2.0.0/index.js index b375424a4e..a6bf8f5865 100644 --- a/packages/pkg-tests/pkg-tests-fixtures/packages/dragon-test-1-b-2.0.0/index.js +++ b/packages/pkg-tests/pkg-tests-fixtures/packages/dragon-test-1-b-2.0.0/index.js @@ -1,5 +1,10 @@ +/* @flow */ + module.exports = require(`./package.json`); -for (const key of Object.keys(module.exports.dependencies || {})) { - module.exports.dependencies[key] = require(key); +for (const key of [`dependencies`, `devDependencies`, `peerDependencies`]) { + for (const dep of Object.keys(module.exports[key] || {})) { + // $FlowFixMe The whole point of this file is to be dynamic + module.exports[key][dep] = require(dep); + } } diff --git a/packages/pkg-tests/pkg-tests-fixtures/packages/dragon-test-1-c-1.0.0/index.js b/packages/pkg-tests/pkg-tests-fixtures/packages/dragon-test-1-c-1.0.0/index.js index b375424a4e..a6bf8f5865 100644 --- a/packages/pkg-tests/pkg-tests-fixtures/packages/dragon-test-1-c-1.0.0/index.js +++ b/packages/pkg-tests/pkg-tests-fixtures/packages/dragon-test-1-c-1.0.0/index.js @@ -1,5 +1,10 @@ +/* @flow */ + module.exports = require(`./package.json`); -for (const key of Object.keys(module.exports.dependencies || {})) { - module.exports.dependencies[key] = require(key); +for (const key of [`dependencies`, `devDependencies`, `peerDependencies`]) { + for (const dep of Object.keys(module.exports[key] || {})) { + // $FlowFixMe The whole point of this file is to be dynamic + module.exports[key][dep] = require(dep); + } } diff --git a/packages/pkg-tests/pkg-tests-fixtures/packages/dragon-test-1-d-1.0.0/index.js b/packages/pkg-tests/pkg-tests-fixtures/packages/dragon-test-1-d-1.0.0/index.js index b375424a4e..a6bf8f5865 100644 --- a/packages/pkg-tests/pkg-tests-fixtures/packages/dragon-test-1-d-1.0.0/index.js +++ b/packages/pkg-tests/pkg-tests-fixtures/packages/dragon-test-1-d-1.0.0/index.js @@ -1,5 +1,10 @@ +/* @flow */ + module.exports = require(`./package.json`); -for (const key of Object.keys(module.exports.dependencies || {})) { - module.exports.dependencies[key] = require(key); +for (const key of [`dependencies`, `devDependencies`, `peerDependencies`]) { + for (const dep of Object.keys(module.exports[key] || {})) { + // $FlowFixMe The whole point of this file is to be dynamic + module.exports[key][dep] = require(dep); + } } diff --git a/packages/pkg-tests/pkg-tests-fixtures/packages/dragon-test-1-e-1.0.0/index.js b/packages/pkg-tests/pkg-tests-fixtures/packages/dragon-test-1-e-1.0.0/index.js index b375424a4e..a6bf8f5865 100644 --- a/packages/pkg-tests/pkg-tests-fixtures/packages/dragon-test-1-e-1.0.0/index.js +++ b/packages/pkg-tests/pkg-tests-fixtures/packages/dragon-test-1-e-1.0.0/index.js @@ -1,5 +1,10 @@ +/* @flow */ + module.exports = require(`./package.json`); -for (const key of Object.keys(module.exports.dependencies || {})) { - module.exports.dependencies[key] = require(key); +for (const key of [`dependencies`, `devDependencies`, `peerDependencies`]) { + for (const dep of Object.keys(module.exports[key] || {})) { + // $FlowFixMe The whole point of this file is to be dynamic + module.exports[key][dep] = require(dep); + } } diff --git a/packages/pkg-tests/pkg-tests-fixtures/packages/hoisting-peer-check-child-1.0.0/index.js b/packages/pkg-tests/pkg-tests-fixtures/packages/hoisting-peer-check-child-1.0.0/index.js index b375424a4e..a6bf8f5865 100644 --- a/packages/pkg-tests/pkg-tests-fixtures/packages/hoisting-peer-check-child-1.0.0/index.js +++ b/packages/pkg-tests/pkg-tests-fixtures/packages/hoisting-peer-check-child-1.0.0/index.js @@ -1,5 +1,10 @@ +/* @flow */ + module.exports = require(`./package.json`); -for (const key of Object.keys(module.exports.dependencies || {})) { - module.exports.dependencies[key] = require(key); +for (const key of [`dependencies`, `devDependencies`, `peerDependencies`]) { + for (const dep of Object.keys(module.exports[key] || {})) { + // $FlowFixMe The whole point of this file is to be dynamic + module.exports[key][dep] = require(dep); + } } diff --git a/packages/pkg-tests/pkg-tests-fixtures/packages/hoisting-peer-check-parent-1.0.0/index.js b/packages/pkg-tests/pkg-tests-fixtures/packages/hoisting-peer-check-parent-1.0.0/index.js index b375424a4e..a6bf8f5865 100644 --- a/packages/pkg-tests/pkg-tests-fixtures/packages/hoisting-peer-check-parent-1.0.0/index.js +++ b/packages/pkg-tests/pkg-tests-fixtures/packages/hoisting-peer-check-parent-1.0.0/index.js @@ -1,5 +1,10 @@ +/* @flow */ + module.exports = require(`./package.json`); -for (const key of Object.keys(module.exports.dependencies || {})) { - module.exports.dependencies[key] = require(key); +for (const key of [`dependencies`, `devDependencies`, `peerDependencies`]) { + for (const dep of Object.keys(module.exports[key] || {})) { + // $FlowFixMe The whole point of this file is to be dynamic + module.exports[key][dep] = require(dep); + } } diff --git a/packages/pkg-tests/pkg-tests-fixtures/packages/no-deps-1.0.0/index.js b/packages/pkg-tests/pkg-tests-fixtures/packages/no-deps-1.0.0/index.js index b375424a4e..a6bf8f5865 100644 --- a/packages/pkg-tests/pkg-tests-fixtures/packages/no-deps-1.0.0/index.js +++ b/packages/pkg-tests/pkg-tests-fixtures/packages/no-deps-1.0.0/index.js @@ -1,5 +1,10 @@ +/* @flow */ + module.exports = require(`./package.json`); -for (const key of Object.keys(module.exports.dependencies || {})) { - module.exports.dependencies[key] = require(key); +for (const key of [`dependencies`, `devDependencies`, `peerDependencies`]) { + for (const dep of Object.keys(module.exports[key] || {})) { + // $FlowFixMe The whole point of this file is to be dynamic + module.exports[key][dep] = require(dep); + } } diff --git a/packages/pkg-tests/pkg-tests-fixtures/packages/no-deps-1.0.1/index.js b/packages/pkg-tests/pkg-tests-fixtures/packages/no-deps-1.0.1/index.js index b375424a4e..a6bf8f5865 100644 --- a/packages/pkg-tests/pkg-tests-fixtures/packages/no-deps-1.0.1/index.js +++ b/packages/pkg-tests/pkg-tests-fixtures/packages/no-deps-1.0.1/index.js @@ -1,5 +1,10 @@ +/* @flow */ + module.exports = require(`./package.json`); -for (const key of Object.keys(module.exports.dependencies || {})) { - module.exports.dependencies[key] = require(key); +for (const key of [`dependencies`, `devDependencies`, `peerDependencies`]) { + for (const dep of Object.keys(module.exports[key] || {})) { + // $FlowFixMe The whole point of this file is to be dynamic + module.exports[key][dep] = require(dep); + } } diff --git a/packages/pkg-tests/pkg-tests-fixtures/packages/no-deps-1.1.0/index.js b/packages/pkg-tests/pkg-tests-fixtures/packages/no-deps-1.1.0/index.js index b375424a4e..a6bf8f5865 100644 --- a/packages/pkg-tests/pkg-tests-fixtures/packages/no-deps-1.1.0/index.js +++ b/packages/pkg-tests/pkg-tests-fixtures/packages/no-deps-1.1.0/index.js @@ -1,5 +1,10 @@ +/* @flow */ + module.exports = require(`./package.json`); -for (const key of Object.keys(module.exports.dependencies || {})) { - module.exports.dependencies[key] = require(key); +for (const key of [`dependencies`, `devDependencies`, `peerDependencies`]) { + for (const dep of Object.keys(module.exports[key] || {})) { + // $FlowFixMe The whole point of this file is to be dynamic + module.exports[key][dep] = require(dep); + } } diff --git a/packages/pkg-tests/pkg-tests-fixtures/packages/no-deps-2.0.0/index.js b/packages/pkg-tests/pkg-tests-fixtures/packages/no-deps-2.0.0/index.js index b375424a4e..a6bf8f5865 100644 --- a/packages/pkg-tests/pkg-tests-fixtures/packages/no-deps-2.0.0/index.js +++ b/packages/pkg-tests/pkg-tests-fixtures/packages/no-deps-2.0.0/index.js @@ -1,5 +1,10 @@ +/* @flow */ + module.exports = require(`./package.json`); -for (const key of Object.keys(module.exports.dependencies || {})) { - module.exports.dependencies[key] = require(key); +for (const key of [`dependencies`, `devDependencies`, `peerDependencies`]) { + for (const dep of Object.keys(module.exports[key] || {})) { + // $FlowFixMe The whole point of this file is to be dynamic + module.exports[key][dep] = require(dep); + } } diff --git a/packages/pkg-tests/pkg-tests-fixtures/packages/no-deps-bins-1.0.0/index.js b/packages/pkg-tests/pkg-tests-fixtures/packages/no-deps-bins-1.0.0/index.js index b375424a4e..a6bf8f5865 100644 --- a/packages/pkg-tests/pkg-tests-fixtures/packages/no-deps-bins-1.0.0/index.js +++ b/packages/pkg-tests/pkg-tests-fixtures/packages/no-deps-bins-1.0.0/index.js @@ -1,5 +1,10 @@ +/* @flow */ + module.exports = require(`./package.json`); -for (const key of Object.keys(module.exports.dependencies || {})) { - module.exports.dependencies[key] = require(key); +for (const key of [`dependencies`, `devDependencies`, `peerDependencies`]) { + for (const dep of Object.keys(module.exports[key] || {})) { + // $FlowFixMe The whole point of this file is to be dynamic + module.exports[key][dep] = require(dep); + } } diff --git a/packages/pkg-tests/pkg-tests-fixtures/packages/no-deps-bins-2.0.0/index.js b/packages/pkg-tests/pkg-tests-fixtures/packages/no-deps-bins-2.0.0/index.js index b375424a4e..a6bf8f5865 100644 --- a/packages/pkg-tests/pkg-tests-fixtures/packages/no-deps-bins-2.0.0/index.js +++ b/packages/pkg-tests/pkg-tests-fixtures/packages/no-deps-bins-2.0.0/index.js @@ -1,5 +1,10 @@ +/* @flow */ + module.exports = require(`./package.json`); -for (const key of Object.keys(module.exports.dependencies || {})) { - module.exports.dependencies[key] = require(key); +for (const key of [`dependencies`, `devDependencies`, `peerDependencies`]) { + for (const dep of Object.keys(module.exports[key] || {})) { + // $FlowFixMe The whole point of this file is to be dynamic + module.exports[key][dep] = require(dep); + } } diff --git a/packages/pkg-tests/pkg-tests-fixtures/packages/no-deps-checked-1.0.0/index.js b/packages/pkg-tests/pkg-tests-fixtures/packages/no-deps-checked-1.0.0/index.js index b375424a4e..a6bf8f5865 100644 --- a/packages/pkg-tests/pkg-tests-fixtures/packages/no-deps-checked-1.0.0/index.js +++ b/packages/pkg-tests/pkg-tests-fixtures/packages/no-deps-checked-1.0.0/index.js @@ -1,5 +1,10 @@ +/* @flow */ + module.exports = require(`./package.json`); -for (const key of Object.keys(module.exports.dependencies || {})) { - module.exports.dependencies[key] = require(key); +for (const key of [`dependencies`, `devDependencies`, `peerDependencies`]) { + for (const dep of Object.keys(module.exports[key] || {})) { + // $FlowFixMe The whole point of this file is to be dynamic + module.exports[key][dep] = require(dep); + } } diff --git a/packages/pkg-tests/pkg-tests-fixtures/packages/no-deps-failing-1.0.0/index.js b/packages/pkg-tests/pkg-tests-fixtures/packages/no-deps-failing-1.0.0/index.js index b375424a4e..a6bf8f5865 100644 --- a/packages/pkg-tests/pkg-tests-fixtures/packages/no-deps-failing-1.0.0/index.js +++ b/packages/pkg-tests/pkg-tests-fixtures/packages/no-deps-failing-1.0.0/index.js @@ -1,5 +1,10 @@ +/* @flow */ + module.exports = require(`./package.json`); -for (const key of Object.keys(module.exports.dependencies || {})) { - module.exports.dependencies[key] = require(key); +for (const key of [`dependencies`, `devDependencies`, `peerDependencies`]) { + for (const dep of Object.keys(module.exports[key] || {})) { + // $FlowFixMe The whole point of this file is to be dynamic + module.exports[key][dep] = require(dep); + } } diff --git a/packages/pkg-tests/pkg-tests-fixtures/packages/no-deps-scripted-1.0.0/index.js b/packages/pkg-tests/pkg-tests-fixtures/packages/no-deps-scripted-1.0.0/index.js index b375424a4e..a6bf8f5865 100644 --- a/packages/pkg-tests/pkg-tests-fixtures/packages/no-deps-scripted-1.0.0/index.js +++ b/packages/pkg-tests/pkg-tests-fixtures/packages/no-deps-scripted-1.0.0/index.js @@ -1,5 +1,10 @@ +/* @flow */ + module.exports = require(`./package.json`); -for (const key of Object.keys(module.exports.dependencies || {})) { - module.exports.dependencies[key] = require(key); +for (const key of [`dependencies`, `devDependencies`, `peerDependencies`]) { + for (const dep of Object.keys(module.exports[key] || {})) { + // $FlowFixMe The whole point of this file is to be dynamic + module.exports[key][dep] = require(dep); + } } diff --git a/packages/pkg-tests/pkg-tests-fixtures/packages/one-deep1-dep-bins/index.js b/packages/pkg-tests/pkg-tests-fixtures/packages/one-deep1-dep-bins/index.js index b375424a4e..a6bf8f5865 100644 --- a/packages/pkg-tests/pkg-tests-fixtures/packages/one-deep1-dep-bins/index.js +++ b/packages/pkg-tests/pkg-tests-fixtures/packages/one-deep1-dep-bins/index.js @@ -1,5 +1,10 @@ +/* @flow */ + module.exports = require(`./package.json`); -for (const key of Object.keys(module.exports.dependencies || {})) { - module.exports.dependencies[key] = require(key); +for (const key of [`dependencies`, `devDependencies`, `peerDependencies`]) { + for (const dep of Object.keys(module.exports[key] || {})) { + // $FlowFixMe The whole point of this file is to be dynamic + module.exports[key][dep] = require(dep); + } } diff --git a/packages/pkg-tests/pkg-tests-fixtures/packages/one-deep2-dep-bins-1.0.0/index.js b/packages/pkg-tests/pkg-tests-fixtures/packages/one-deep2-dep-bins-1.0.0/index.js index b375424a4e..a6bf8f5865 100644 --- a/packages/pkg-tests/pkg-tests-fixtures/packages/one-deep2-dep-bins-1.0.0/index.js +++ b/packages/pkg-tests/pkg-tests-fixtures/packages/one-deep2-dep-bins-1.0.0/index.js @@ -1,5 +1,10 @@ +/* @flow */ + module.exports = require(`./package.json`); -for (const key of Object.keys(module.exports.dependencies || {})) { - module.exports.dependencies[key] = require(key); +for (const key of [`dependencies`, `devDependencies`, `peerDependencies`]) { + for (const dep of Object.keys(module.exports[key] || {})) { + // $FlowFixMe The whole point of this file is to be dynamic + module.exports[key][dep] = require(dep); + } } diff --git a/packages/pkg-tests/pkg-tests-fixtures/packages/one-fixed-dep-1.0.0/index.js b/packages/pkg-tests/pkg-tests-fixtures/packages/one-fixed-dep-1.0.0/index.js index b375424a4e..a6bf8f5865 100644 --- a/packages/pkg-tests/pkg-tests-fixtures/packages/one-fixed-dep-1.0.0/index.js +++ b/packages/pkg-tests/pkg-tests-fixtures/packages/one-fixed-dep-1.0.0/index.js @@ -1,5 +1,10 @@ +/* @flow */ + module.exports = require(`./package.json`); -for (const key of Object.keys(module.exports.dependencies || {})) { - module.exports.dependencies[key] = require(key); +for (const key of [`dependencies`, `devDependencies`, `peerDependencies`]) { + for (const dep of Object.keys(module.exports[key] || {})) { + // $FlowFixMe The whole point of this file is to be dynamic + module.exports[key][dep] = require(dep); + } } diff --git a/packages/pkg-tests/pkg-tests-fixtures/packages/one-fixed-dep-bins-0.0.0/index.js b/packages/pkg-tests/pkg-tests-fixtures/packages/one-fixed-dep-bins-0.0.0/index.js index b375424a4e..a6bf8f5865 100644 --- a/packages/pkg-tests/pkg-tests-fixtures/packages/one-fixed-dep-bins-0.0.0/index.js +++ b/packages/pkg-tests/pkg-tests-fixtures/packages/one-fixed-dep-bins-0.0.0/index.js @@ -1,5 +1,10 @@ +/* @flow */ + module.exports = require(`./package.json`); -for (const key of Object.keys(module.exports.dependencies || {})) { - module.exports.dependencies[key] = require(key); +for (const key of [`dependencies`, `devDependencies`, `peerDependencies`]) { + for (const dep of Object.keys(module.exports[key] || {})) { + // $FlowFixMe The whole point of this file is to be dynamic + module.exports[key][dep] = require(dep); + } } diff --git a/packages/pkg-tests/pkg-tests-fixtures/packages/one-fixed-dep-bins-1.0.0/index.js b/packages/pkg-tests/pkg-tests-fixtures/packages/one-fixed-dep-bins-1.0.0/index.js index b375424a4e..a6bf8f5865 100644 --- a/packages/pkg-tests/pkg-tests-fixtures/packages/one-fixed-dep-bins-1.0.0/index.js +++ b/packages/pkg-tests/pkg-tests-fixtures/packages/one-fixed-dep-bins-1.0.0/index.js @@ -1,5 +1,10 @@ +/* @flow */ + module.exports = require(`./package.json`); -for (const key of Object.keys(module.exports.dependencies || {})) { - module.exports.dependencies[key] = require(key); +for (const key of [`dependencies`, `devDependencies`, `peerDependencies`]) { + for (const dep of Object.keys(module.exports[key] || {})) { + // $FlowFixMe The whole point of this file is to be dynamic + module.exports[key][dep] = require(dep); + } } diff --git a/packages/pkg-tests/pkg-tests-fixtures/packages/one-fixed-dep-bins-2.0.0/index.js b/packages/pkg-tests/pkg-tests-fixtures/packages/one-fixed-dep-bins-2.0.0/index.js index b375424a4e..a6bf8f5865 100644 --- a/packages/pkg-tests/pkg-tests-fixtures/packages/one-fixed-dep-bins-2.0.0/index.js +++ b/packages/pkg-tests/pkg-tests-fixtures/packages/one-fixed-dep-bins-2.0.0/index.js @@ -1,5 +1,10 @@ +/* @flow */ + module.exports = require(`./package.json`); -for (const key of Object.keys(module.exports.dependencies || {})) { - module.exports.dependencies[key] = require(key); +for (const key of [`dependencies`, `devDependencies`, `peerDependencies`]) { + for (const dep of Object.keys(module.exports[key] || {})) { + // $FlowFixMe The whole point of this file is to be dynamic + module.exports[key][dep] = require(dep); + } } diff --git a/packages/pkg-tests/pkg-tests-fixtures/packages/one-fixed-dep-checked-1.0.0/index.js b/packages/pkg-tests/pkg-tests-fixtures/packages/one-fixed-dep-checked-1.0.0/index.js index b375424a4e..a6bf8f5865 100644 --- a/packages/pkg-tests/pkg-tests-fixtures/packages/one-fixed-dep-checked-1.0.0/index.js +++ b/packages/pkg-tests/pkg-tests-fixtures/packages/one-fixed-dep-checked-1.0.0/index.js @@ -1,5 +1,10 @@ +/* @flow */ + module.exports = require(`./package.json`); -for (const key of Object.keys(module.exports.dependencies || {})) { - module.exports.dependencies[key] = require(key); +for (const key of [`dependencies`, `devDependencies`, `peerDependencies`]) { + for (const dep of Object.keys(module.exports[key] || {})) { + // $FlowFixMe The whole point of this file is to be dynamic + module.exports[key][dep] = require(dep); + } } diff --git a/packages/pkg-tests/pkg-tests-fixtures/packages/one-fixed-dep-scripted-1.0.0/index.js b/packages/pkg-tests/pkg-tests-fixtures/packages/one-fixed-dep-scripted-1.0.0/index.js index b375424a4e..a6bf8f5865 100644 --- a/packages/pkg-tests/pkg-tests-fixtures/packages/one-fixed-dep-scripted-1.0.0/index.js +++ b/packages/pkg-tests/pkg-tests-fixtures/packages/one-fixed-dep-scripted-1.0.0/index.js @@ -1,5 +1,10 @@ +/* @flow */ + module.exports = require(`./package.json`); -for (const key of Object.keys(module.exports.dependencies || {})) { - module.exports.dependencies[key] = require(key); +for (const key of [`dependencies`, `devDependencies`, `peerDependencies`]) { + for (const dep of Object.keys(module.exports[key] || {})) { + // $FlowFixMe The whole point of this file is to be dynamic + module.exports[key][dep] = require(dep); + } } diff --git a/packages/pkg-tests/pkg-tests-fixtures/packages/one-range-dep-1.0.0/index.js b/packages/pkg-tests/pkg-tests-fixtures/packages/one-range-dep-1.0.0/index.js index b375424a4e..a6bf8f5865 100644 --- a/packages/pkg-tests/pkg-tests-fixtures/packages/one-range-dep-1.0.0/index.js +++ b/packages/pkg-tests/pkg-tests-fixtures/packages/one-range-dep-1.0.0/index.js @@ -1,5 +1,10 @@ +/* @flow */ + module.exports = require(`./package.json`); -for (const key of Object.keys(module.exports.dependencies || {})) { - module.exports.dependencies[key] = require(key); +for (const key of [`dependencies`, `devDependencies`, `peerDependencies`]) { + for (const dep of Object.keys(module.exports[key] || {})) { + // $FlowFixMe The whole point of this file is to be dynamic + module.exports[key][dep] = require(dep); + } } diff --git a/packages/pkg-tests/pkg-tests-fixtures/packages/various-requires-1.0.0/index.js b/packages/pkg-tests/pkg-tests-fixtures/packages/various-requires-1.0.0/index.js index b375424a4e..a6bf8f5865 100644 --- a/packages/pkg-tests/pkg-tests-fixtures/packages/various-requires-1.0.0/index.js +++ b/packages/pkg-tests/pkg-tests-fixtures/packages/various-requires-1.0.0/index.js @@ -1,5 +1,10 @@ +/* @flow */ + module.exports = require(`./package.json`); -for (const key of Object.keys(module.exports.dependencies || {})) { - module.exports.dependencies[key] = require(key); +for (const key of [`dependencies`, `devDependencies`, `peerDependencies`]) { + for (const dep of Object.keys(module.exports[key] || {})) { + // $FlowFixMe The whole point of this file is to be dynamic + module.exports[key][dep] = require(dep); + } } From 26ebad17ba7765776ec409e73b9d16b61d1c7a12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Fri, 2 Mar 2018 19:08:00 +0000 Subject: [PATCH 015/111] Finishes to hide plugnplay behind a yarnrc option (`plugnplay-experimental`) Branch: option-plugnplay-experimental --- packages/pkg-tests/yarn.test.js | 5 +---- src/cli/commands/install.js | 14 ++++++++------ src/config.js | 2 +- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/packages/pkg-tests/yarn.test.js b/packages/pkg-tests/yarn.test.js index 7a5ba38e45..984278337a 100644 --- a/packages/pkg-tests/yarn.test.js +++ b/packages/pkg-tests/yarn.test.js @@ -17,14 +17,11 @@ const pkgDriver = generatePkgDriver({ extraArgs = [...extraArgs, `--cache-folder`, `${path}/.cache`]; } - if (plugNPlay) { - extraArgs; - } - return execFile(process.execPath, [`${process.cwd()}/../../bin/yarn.js`, command, ...extraArgs, ...args], { env: { [`NPM_CONFIG_REGISTRY`]: registryUrl, [`YARN_SILENT`]: `1`, + [`YARN_PLUGNPLAY_EXPERIMENTAL`]: plugNPlay ? `true` : `false`, [`PATH`]: `${path}/bin${delimiter}${process.env.PATH}`, }, cwd: path, diff --git a/src/cli/commands/install.js b/src/cli/commands/install.js index fbe01e3c6a..25897bd93c 100644 --- a/src/cli/commands/install.js +++ b/src/cli/commands/install.js @@ -576,12 +576,14 @@ export class Install { }), ); - steps.push((curr: number, total: number) => - callThroughHook('pnpStep', async () => { - const code = await generatePnpMap(this.config, flattenedTopLevelPatterns, {resolver: this.resolver}); - await fs.writeFile(`${this.config.lockfileFolder}/${constants.PNP_FILENAME}`, code); - }), - ); + if (this.config.plugnplayEnabled) { + steps.push((curr: number, total: number) => + callThroughHook('pnpStep', async () => { + const code = await generatePnpMap(this.config, flattenedTopLevelPatterns, {resolver: this.resolver}); + await fs.writeFile(`${this.config.lockfileFolder}/${constants.PNP_FILENAME}`, code); + }), + ); + } steps.push((curr: number, total: number) => callThroughHook('buildStep', async () => { diff --git a/src/config.js b/src/config.js index 2326f27f6c..8ab8f25cbc 100644 --- a/src/config.js +++ b/src/config.js @@ -325,7 +325,7 @@ export default class Config { } else { this._cacheRootFolder = String(cacheRootFolder); } - this.plugnplayEnabled = this.getOption('plugnplay-experimental') !== false; + this.plugnplayEnabled = Boolean(this.getOption('plugnplay-experimental')); this.workspacesEnabled = this.getOption('workspaces-experimental') !== false; this.workspacesNohoistEnabled = this.getOption('workspaces-nohoist-experimental') !== false; From a011d7ba00373108d1c7a77d21cac970b5ee8374 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Fri, 2 Mar 2018 19:14:29 +0000 Subject: [PATCH 016/111] Adds failing tests for pnp peer dependencies Branch: pnp-peer-dependencies-failing --- .../packages/peer-deps-1.0.0/index.js | 10 +++++ .../packages/peer-deps-1.0.0/package.json | 7 +++ .../pkg-tests-specs/sources/basic.js | 45 ++++++++++++++++++- 3 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 packages/pkg-tests/pkg-tests-fixtures/packages/peer-deps-1.0.0/index.js create mode 100644 packages/pkg-tests/pkg-tests-fixtures/packages/peer-deps-1.0.0/package.json diff --git a/packages/pkg-tests/pkg-tests-fixtures/packages/peer-deps-1.0.0/index.js b/packages/pkg-tests/pkg-tests-fixtures/packages/peer-deps-1.0.0/index.js new file mode 100644 index 0000000000..a6bf8f5865 --- /dev/null +++ b/packages/pkg-tests/pkg-tests-fixtures/packages/peer-deps-1.0.0/index.js @@ -0,0 +1,10 @@ +/* @flow */ + +module.exports = require(`./package.json`); + +for (const key of [`dependencies`, `devDependencies`, `peerDependencies`]) { + for (const dep of Object.keys(module.exports[key] || {})) { + // $FlowFixMe The whole point of this file is to be dynamic + module.exports[key][dep] = require(dep); + } +} diff --git a/packages/pkg-tests/pkg-tests-fixtures/packages/peer-deps-1.0.0/package.json b/packages/pkg-tests/pkg-tests-fixtures/packages/peer-deps-1.0.0/package.json new file mode 100644 index 0000000000..89fa70330a --- /dev/null +++ b/packages/pkg-tests/pkg-tests-fixtures/packages/peer-deps-1.0.0/package.json @@ -0,0 +1,7 @@ +{ + "name": "peer-deps", + "version": "1.0.0", + "peerDependencies": { + "no-deps": "*" + } +} diff --git a/packages/pkg-tests/pkg-tests-specs/sources/basic.js b/packages/pkg-tests/pkg-tests-specs/sources/basic.js index 21eda5dea8..d42b71748b 100644 --- a/packages/pkg-tests/pkg-tests-specs/sources/basic.js +++ b/packages/pkg-tests/pkg-tests-specs/sources/basic.js @@ -2,7 +2,7 @@ import type {PackageDriver} from 'pkg-tests-core'; -const {tests: {getPackageArchivePath, getPackageHttpArchivePath, getPackageDirectoryPath}} = require('pkg-tests-core'); +const {fs: {writeJson}, tests: {getPackageArchivePath, getPackageHttpArchivePath, getPackageDirectoryPath}} = require('pkg-tests-core'); module.exports = (makeTemporaryEnv: PackageDriver) => { describe(`Basic tests`, () => { @@ -224,5 +224,48 @@ module.exports = (makeTemporaryEnv: PackageDriver) => { }, ), ); + + test(`it should install in such a way that peer dependencies can be resolved (from top-level)`, makeTemporaryEnv({ + dependencies: {[`peer-deps`]: `1.0.0`, [`no-deps`]: `1.0.0`} + }, async ({path, run, source}) => { + await run(`install`); + + await expect(source(`require('peer-deps')`)).resolves.toMatchObject({ + name: `peer-deps`, + version: `1.0.0`, + peerDependencies: { + [`no-deps`]: { + name: `no-deps`, + version: `1.0.0`, + } + } + }); + })); + + test(`it should install in such a way that peer dependencies can be resolved (from within a dependency)`, makeTemporaryEnv({ + dependencies: {[`custom-dep`]: `file:./custom-dep`}, + }, async ({path, run, source}) => { + await writeJson(`${path}/custom-dep/package.json`, { + name: `custom-dep`, + version: `1.0.0`, + dependencies: { + [`peer-deps`]: `1.0.0`, + [`no-deps`]: `1.0.0`, + } + }); + + await run(`install`); + + await expect(source(`require('peer-deps')`)).resolves.toMatchObject({ + name: `peer-deps`, + version: `1.0.0`, + peerDependencies: { + [`no-deps`]: { + name: `no-deps`, + version: `1.0.0`, + } + } + }); + })); }); }; From e7d2f996ea2c73939311f1d7094226b60cbb7ea1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Mon, 5 Mar 2018 11:23:06 +0000 Subject: [PATCH 017/111] Prettifies the generated pnp files --- src/util/generate-pnp-map.js | 149 ++++++++++++++++++----------------- 1 file changed, 76 insertions(+), 73 deletions(-) diff --git a/src/util/generate-pnp-map.js b/src/util/generate-pnp-map.js index d625194697..2270982c3c 100644 --- a/src/util/generate-pnp-map.js +++ b/src/util/generate-pnp-map.js @@ -17,35 +17,36 @@ function generateMaps(packageInformationStores: PackageInformationStores): strin code += `let packageInformationStores = new Map([\n`; for (const [packageName, packageInformationStore] of packageInformationStores) { - code += ` [ ${JSON.stringify(packageName)}, new Map([\n`; + code += ` [${JSON.stringify(packageName)}, new Map([\n`; for (const [packageReference, {packageLocation, packageDependencies}] of packageInformationStore) { - code += ` [ ${JSON.stringify(packageReference)}, {\n`; - code += ` packageLocation: ${JSON.stringify(packageLocation)},\n`; - code += ` packageDependencies: new Map([\n`; + code += ` [${JSON.stringify(packageReference)}, {\n`; + code += ` packageLocation: ${JSON.stringify(packageLocation)},\n`; + code += ` packageDependencies: new Map([\n`; for (const [dependencyName, dependencyReference] of packageDependencies.entries()) { - code += ` [ ${JSON.stringify(dependencyName)}, ${JSON.stringify(dependencyReference)} ],\n`; + code += ` [${JSON.stringify(dependencyName)}, ${JSON.stringify(dependencyReference)}],\n`; } - code += ` ]),\n`; - code += ` } ],\n`; + code += ` ]),\n`; + code += ` }],\n`; } - code += ` ]) ],\n`; + code += ` ])],\n`; } code += `]);\n`; + code += `\n`; // Also bake an inverse map that will allow us to find the package information based on the path code += `let locatorsByLocations = new Map([\n`; for (const [packageName, packageInformationStore] of packageInformationStores) { for (const [packageReference, {packageLocation}] of packageInformationStore) { - code += ` [ ${JSON.stringify(packageLocation)}, ${JSON.stringify({ + code += ` [${JSON.stringify(packageLocation)}, ${JSON.stringify({ name: packageName, reference: packageReference, - })} ],\n`; + })}],\n`; } } @@ -75,18 +76,17 @@ function generateFindPackageLocator(packageInformationStores: PackageInformation // Generate a function that, given a file path, returns the associated package name code += `exports.findPackageLocator = function findPackageLocator(location) {\n`; - code += `\n`; - code += ` let match;\n`; + code += ` let match;\n`; for (const [length] of sortedLengths) { code += `\n`; - code += ` if (location.length >= ${length} && location[${length} - 1] === path.sep)\n`; - code += ` if (match = locatorsByLocations.get(location.substr(0, ${length})))\n`; - code += ` return match;\n`; + code += ` if (location.length >= ${length} && location[${length} - 1] === path.sep)\n`; + code += ` if (match = locatorsByLocations.get(location.substr(0, ${length})))\n`; + code += ` return match;\n`; } code += `\n`; - code += ` return null;\n`; + code += ` return null;\n`; code += `};\n`; return code; @@ -97,8 +97,7 @@ function generateGetPackageLocation(packageInformationStores: PackageInformation // Generate a function that, given a locator, returns the package location on the disk - code += `exports.getPackageLocation = function getPackageLocation({ name, reference }) {\n`; - code += `\n`; + code += `exports.getPackageLocation = function getPackageLocation({name, reference}) {\n`; code += ` let packageInformationStore, packageInformation;\n`; code += `\n`; code += ` if (packageInformationStore = packageInformationStores.get(name))\n`; @@ -106,7 +105,6 @@ function generateGetPackageLocation(packageInformationStores: PackageInformation code += ` return packageInformation.packageLocation;\n`; code += `\n`; code += ` return null;\n`; - code += `\n`; code += `};\n`; return code; @@ -117,15 +115,14 @@ function generateGetPackageDependencies(packageInformationStores: PackageInforma // Generate a function that, given a locator, returns the package dependencies - code += `exports.getPackageDependencies = function getPackageDependencies({ name, reference }) {\n`; - code += `\n`; - code += ` let packageInformationStore, packageInformation;\n`; + code += `exports.getPackageDependencies = function getPackageDependencies({name, reference}) {\n`; + code += ` let packageInformationStore, packageInformation;\n`; code += `\n`; - code += ` if (packageInformationStore = packageInformationStores.get(name))\n`; - code += ` if (packageInformation = packageInformationStore.get(reference))\n`; - code += ` return packageInformation.packageDependencies;\n`; + code += ` if (packageInformationStore = packageInformationStores.get(name))\n`; + code += ` if (packageInformation = packageInformationStore.get(reference))\n`; + code += ` return packageInformation.packageDependencies;\n`; code += `\n`; - code += ` return null;\n`; + code += ` return null;\n`; code += `};\n`; return code; @@ -134,65 +131,69 @@ function generateGetPackageDependencies(packageInformationStores: PackageInforma /* eslint-disable max-len */ const PROLOGUE = ` let path = require('path'); -`; +`.replace(/^\n/, ``); /* eslint-enable max-len */ /* eslint-disable max-len */ -const REQUIRE_HOOK = lockfileFolder => ` -let Module = require('module'); +const REQUIRE_HOOK = lockfileFolder => + ` +const Module = require('module'); -let originalResolver = Module._resolveFilename; -let pathRegExp = /^(?!\\.{0,2}\\/)([^\\/]+)(\\/.*|)$/; +const originalResolver = Module._resolveFilename; +const pathRegExp = /^(?!\\.{0,2}\\/)([^\\/]+)(\\/.*|)$/; Module._resolveFilename = function (request, parent, isMain, options) { - if (Module.builtinModules.includes(request)) - return request; - - let dependencyNameMatch = request.match(pathRegExp); + if (Module.builtinModules.includes(request)) { + return request; + } - if (!dependencyNameMatch) - return originalResolver.call(Module, request, parent, isMain, options); + const dependencyNameMatch = request.match(pathRegExp); - let caller = parent; + if (!dependencyNameMatch) { + return originalResolver.call(Module, request, parent, isMain, options); + } - while (caller && (caller.id === '[eval]' || caller.id === '' || !caller.filename)) - caller = caller.parent; + let caller = parent; - let packagePath = caller ? caller.filename : process.cwd() + path.sep; - let packageLocator = exports.findPackageLocator(packagePath); + while (caller && (caller.id === '[eval]' || caller.id === '' || !caller.filename)) { + caller = caller.parent; + } - if (!packageLocator) - throw new Error(\`Could not find to which package belongs the path \${packagePath}\`); + const packagePath = caller ? caller.filename : process.cwd() + path.sep; + const packageLocator = exports.findPackageLocator(packagePath); - let [ , dependencyName, subPath ] = dependencyNameMatch; + if (!packageLocator) { + throw new Error(\`Could not find to which package belongs the path \${packagePath}\`); + } - let packageDependencies = exports.getPackageDependencies(packageLocator); - let dependencyReference = packageDependencies.get(dependencyName); + const [ , dependencyName, subPath ] = dependencyNameMatch; - if (!dependencyReference) { + const packageDependencies = exports.getPackageDependencies(packageLocator); + let dependencyReference = packageDependencies.get(dependencyName); - if (packageLocator.name === null) - throw new Error(\`You cannot require a package (\${dependencyName}) that is not declared in your dependencies\`); - - let topLevelDependencies = exports.getPackageDependencies({ name: null, reference: null }); - dependencyReference = topLevelDependencies.get(dependencyName); + if (!dependencyReference) { + if (packageLocator.name === null) { + throw new Error(\`You cannot require a package (\${dependencyName}) that is not declared in your dependencies\`); + } - if (!dependencyReference) { - throw new Error(\`Package \${packageLocator.name}@\${packageLocator.reference} is trying to require package \${dependencyName}, which is not declared in its dependencies (\${Array.from(packageDependencies.keys()).join(\`, \`)})\`); - } + const topLevelDependencies = exports.getPackageDependencies({ name: null, reference: null }); + dependencyReference = topLevelDependencies.get(dependencyName); + if (!dependencyReference) { + throw new Error(\`Package \${packageLocator.name}@\${packageLocator.reference} is trying to require package \${dependencyName}, which is not declared in its dependencies (\${Array.from(packageDependencies.keys()).join(\`, \`)})\`); } + } - let dependencyLocation = exports.getPackageLocation({ name: dependencyName, reference: dependencyReference }); - - if (!dependencyLocation) - throw new Error(\`Package \${dependencyName}@\${dependencyReference} is a valid dependency, but hasn't been installed and thus cannot be required\`); + const dependencyLocation = exports.getPackageLocation({ name: dependencyName, reference: dependencyReference }); - return originalResolver.call(Module, \`\${dependencyLocation}/\${subPath}\`, parent, isMain, options); + if (!dependencyLocation) { + throw new Error(\`Package \${dependencyName}@\${dependencyReference} is a valid dependency, but hasn't been installed and thus cannot be required\`); + } + return originalResolver.call(Module, \`\${dependencyLocation}/\${subPath}\`, parent, isMain, options); }; -`; +`.replace(/^\n/, ``); /* eslint-enable */ async function getPackageInformationStores( @@ -222,6 +223,11 @@ async function getPackageInformationStores( packageDependencies.set(dep.name, dep.version); } + for (const pattern of ref.peerDependencies || []) { + const dep = resolver.getStrictResolvedPattern(pattern); + packageDependencies.set(dep.name, dep.version); + } + packageInformationStore.set(pkg.version, { packageLocation: (await fs.realpath(loc)).replace(/[\\\/]?$/, path.sep), packageDependencies, @@ -262,15 +268,12 @@ export async function generatePnpMap( ): Promise { const packageInformationStores = await getPackageInformationStores(config, seedPatterns, {resolver}); - let code = PROLOGUE; - - code += generateMaps(packageInformationStores); - - code += generateFindPackageLocator(packageInformationStores); - code += generateGetPackageLocation(packageInformationStores); - code += generateGetPackageDependencies(packageInformationStores); - - code += REQUIRE_HOOK(config.lockfileFolder); - - return code; + return [ + PROLOGUE, + generateMaps(packageInformationStores), + generateFindPackageLocator(packageInformationStores), + generateGetPackageLocation(packageInformationStores), + generateGetPackageDependencies(packageInformationStores), + REQUIRE_HOOK(config.lockfileFolder), + ].join(`\n`); } From 9db30e4239b649e8414b020e2b45836221758fcc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Mon, 5 Mar 2018 11:29:32 +0000 Subject: [PATCH 018/111] Adds the plugnplay flag to the integrity check --- src/integrity-checker.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/integrity-checker.js b/src/integrity-checker.js index 9f6102b9bb..539fc758d1 100644 --- a/src/integrity-checker.js +++ b/src/integrity-checker.js @@ -245,6 +245,10 @@ export default class InstallationIntegrityChecker { result.flags.push('production'); } + if (this.config.plugnplayEnabled) { + result.flags.push('plugnplay'); + } + const linkedModules = this.config.linkedModules; if (linkedModules.length) { From bdf60d9fab14246553d2eeea46305c709d44bc6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Mon, 5 Mar 2018 11:47:23 +0000 Subject: [PATCH 019/111] Removes the pnp file at link-time if installing with pnp disabled --- src/package-linker.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/package-linker.js b/src/package-linker.js index ff7f76d275..acccc328d9 100644 --- a/src/package-linker.js +++ b/src/package-linker.js @@ -573,5 +573,9 @@ export default class PackageLinker { ): Promise { this.resolvePeerModules(); await this.copyModules(patterns, workspaceLayout, {linkDuplicates, ignoreOptional}); + + if (!this.config.plugnplayEnabled) { + await fs.unlink(`${this.config.lockfileFolder}/${constants.PNP_FILENAME}`); + } } } From 7eb452187a304250cb0a0abdd43501e15f6e938f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Mon, 5 Mar 2018 15:24:53 +0000 Subject: [PATCH 020/111] Improves pnp maps compatibility --- src/util/generate-pnp-map.js | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/util/generate-pnp-map.js b/src/util/generate-pnp-map.js index 2270982c3c..51a7c4b80b 100644 --- a/src/util/generate-pnp-map.js +++ b/src/util/generate-pnp-map.js @@ -139,12 +139,14 @@ const REQUIRE_HOOK = lockfileFolder => ` const Module = require('module'); +const builtinModules = Module.builtinModules || Object.keys(process.binding('natives')); + const originalResolver = Module._resolveFilename; const pathRegExp = /^(?!\\.{0,2}\\/)([^\\/]+)(\\/.*|)$/; Module._resolveFilename = function (request, parent, isMain, options) { - if (Module.builtinModules.includes(request)) { + if (builtinModules.indexOf(request) !== -1) { return request; } @@ -223,11 +225,6 @@ async function getPackageInformationStores( packageDependencies.set(dep.name, dep.version); } - for (const pattern of ref.peerDependencies || []) { - const dep = resolver.getStrictResolvedPattern(pattern); - packageDependencies.set(dep.name, dep.version); - } - packageInformationStore.set(pkg.version, { packageLocation: (await fs.realpath(loc)).replace(/[\\\/]?$/, path.sep), packageDependencies, From 6d10cc0a716c721c2805c45a37d4eff282d2184a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Mon, 5 Mar 2018 15:25:21 +0000 Subject: [PATCH 021/111] Prevents "yarn check" from checking the node_modules existence when under pnp --- src/cli/commands/check.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/cli/commands/check.js b/src/cli/commands/check.js index dafdf7a60d..d01331e210 100644 --- a/src/cli/commands/check.js +++ b/src/cli/commands/check.js @@ -89,6 +89,11 @@ export async function verifyTreeCheck( continue; } locationsVisited.add(manifestLoc + `@${dep.version}`); + // When plugnplay is enabled, packages aren't copied to the node_modules folder, so this check doesn't make sense + // TODO: We ideally should check that the packages are located inside the cache instead + if (config.plugnplayEnabled) { + continue; + } if (!await fs.exists(manifestLoc)) { reportError('packageNotInstalled', `${dep.originalKey}`); continue; From 9fa12cd5bfaff0a9a44c9205d6f4c165232c1ec8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Mon, 5 Mar 2018 15:30:25 +0000 Subject: [PATCH 022/111] Adds a missing package to the request cache --- .../angular/core/-/core-2.4.10.tgz.bin | Bin 0 -> 447848 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 __tests__/fixtures/request-cache/GET/registry.yarnpkg.com/angular/core/-/core-2.4.10.tgz.bin diff --git a/__tests__/fixtures/request-cache/GET/registry.yarnpkg.com/angular/core/-/core-2.4.10.tgz.bin b/__tests__/fixtures/request-cache/GET/registry.yarnpkg.com/angular/core/-/core-2.4.10.tgz.bin new file mode 100644 index 0000000000000000000000000000000000000000..9378b1cea28ede442e4f8c41384bc1cb404d1e80 GIT binary patch literal 447848 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�g$xiT!T+{FlrgDJ@w=mfZRKF;54ggS1 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 z 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%0Db!0ajj{0v0?S5aX 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 D*ljR4 literal 0 HcmV?d00001 From 65514862d3a7179e15f8b88fe4dce2d6db7e1757 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Tue, 6 Mar 2018 20:42:49 +0000 Subject: [PATCH 023/111] Fixes tests Branch: pnp-fix-tests --- .../pkg-tests-specs/sources/basic.js | 88 ++++++++++++------- .../pkg-tests/pkg-tests-specs/sources/pnp.js | 51 +++++++++-- 2 files changed, 97 insertions(+), 42 deletions(-) diff --git a/packages/pkg-tests/pkg-tests-specs/sources/basic.js b/packages/pkg-tests/pkg-tests-specs/sources/basic.js index d42b71748b..6479ea54b8 100644 --- a/packages/pkg-tests/pkg-tests-specs/sources/basic.js +++ b/packages/pkg-tests/pkg-tests-specs/sources/basic.js @@ -2,7 +2,10 @@ import type {PackageDriver} from 'pkg-tests-core'; -const {fs: {writeJson}, tests: {getPackageArchivePath, getPackageHttpArchivePath, getPackageDirectoryPath}} = require('pkg-tests-core'); +const { + fs: {writeFile, writeJson}, + tests: {getPackageArchivePath, getPackageHttpArchivePath, getPackageDirectoryPath}, +} = require('pkg-tests-core'); module.exports = (makeTemporaryEnv: PackageDriver) => { describe(`Basic tests`, () => { @@ -225,47 +228,66 @@ module.exports = (makeTemporaryEnv: PackageDriver) => { ), ); - test(`it should install in such a way that peer dependencies can be resolved (from top-level)`, makeTemporaryEnv({ - dependencies: {[`peer-deps`]: `1.0.0`, [`no-deps`]: `1.0.0`} - }, async ({path, run, source}) => { + test( + `it should install in such a way that peer dependencies can be resolved (from top-level)`, + makeTemporaryEnv( + { + dependencies: {[`peer-deps`]: `1.0.0`, [`no-deps`]: `1.0.0`}, + }, + async ({path, run, source}) => { await run(`install`); - await expect(source(`require('peer-deps')`)).resolves.toMatchObject({ - name: `peer-deps`, - version: `1.0.0`, - peerDependencies: { - [`no-deps`]: { - name: `no-deps`, - version: `1.0.0`, - } - } + await expect(source(`require('peer-deps')`)).resolves.toMatchObject({ + name: `peer-deps`, + version: `1.0.0`, + peerDependencies: { + [`no-deps`]: { + name: `no-deps`, + version: `1.0.0`, + }, + }, }); - })); + }, + ), + ); - test(`it should install in such a way that peer dependencies can be resolved (from within a dependency)`, makeTemporaryEnv({ - dependencies: {[`custom-dep`]: `file:./custom-dep`}, - }, async ({path, run, source}) => { - await writeJson(`${path}/custom-dep/package.json`, { + test( + `it should install in such a way that peer dependencies can be resolved (from within a dependency)`, + makeTemporaryEnv( + { + dependencies: {[`custom-dep`]: `file:./custom-dep`}, + }, + async ({path, run, source}) => { + await writeJson(`${path}/custom-dep/package.json`, { name: `custom-dep`, version: `1.0.0`, dependencies: { - [`peer-deps`]: `1.0.0`, - [`no-deps`]: `1.0.0`, - } - }); + [`peer-deps`]: `1.0.0`, + [`no-deps`]: `1.0.0`, + }, + }); - await run(`install`); + await writeFile( + `${path}/custom-dep/index.js`, + ` + module.exports = require('peer-deps'); + `, + ); + + await run(`install`); - await expect(source(`require('peer-deps')`)).resolves.toMatchObject({ - name: `peer-deps`, - version: `1.0.0`, - peerDependencies: { - [`no-deps`]: { - name: `no-deps`, - version: `1.0.0`, - } - } + await expect(source(`require('custom-dep')`)).resolves.toMatchObject({ + name: `peer-deps`, + version: `1.0.0`, + peerDependencies: { + [`no-deps`]: { + name: `no-deps`, + version: `1.0.0`, + }, + }, }); - })); + }, + ), + ); }); }; diff --git a/packages/pkg-tests/pkg-tests-specs/sources/pnp.js b/packages/pkg-tests/pkg-tests-specs/sources/pnp.js index 44667b6e9e..3fb9667be4 100644 --- a/packages/pkg-tests/pkg-tests-specs/sources/pnp.js +++ b/packages/pkg-tests/pkg-tests-specs/sources/pnp.js @@ -19,6 +19,9 @@ module.exports = makeTemporaryEnv => { [`no-deps`]: `1.0.0`, }, }, + { + plugNPlay: true, + }, async ({path, run, source}) => { await run(`install`); @@ -42,6 +45,9 @@ module.exports = makeTemporaryEnv => { [`no-deps`]: `2.0.0`, }, }, + { + plugNPlay: true, + }, async ({path, run, source}) => { await run(`install`); @@ -63,22 +69,34 @@ module.exports = makeTemporaryEnv => { test( `it should correctly resolve native Node modules`, - makeTemporaryEnv({}, async ({path, run, source}) => { - await run(`install`); + makeTemporaryEnv( + {}, + { + plugNPlay: true, + }, + async ({path, run, source}) => { + await run(`install`); - await expect(source(`require('fs') ? true : false`)).resolves.toEqual(true); - }), + await expect(source(`require('fs') ? true : false`)).resolves.toEqual(true); + }, + ), ); test( `it should correctly resolve relative imports`, - makeTemporaryEnv({}, async ({path, run, source}) => { - await writeFile(`${path}/foo.js`, `module.exports = 42;\n`); + makeTemporaryEnv( + {}, + { + plugNPlay: true, + }, + async ({path, run, source}) => { + await writeFile(`${path}/foo.js`, `module.exports = 42;\n`); - await run(`install`); + await run(`install`); - await expect(source(`require('./foo.js')`)).resolves.toEqual(42); - }), + await expect(source(`require('./foo.js')`)).resolves.toEqual(42); + }, + ), ); test( @@ -87,6 +105,9 @@ module.exports = makeTemporaryEnv => { { dependencies: {[`various-requires`]: `1.0.0`}, }, + { + plugNPlay: true, + }, async ({path, run, source}) => { await run(`install`); @@ -103,6 +124,9 @@ module.exports = makeTemporaryEnv => { [`various-requires`]: `1.0.0`, }, }, + { + plugNPlay: true, + }, async ({path, run, source}) => { await run(`install`); @@ -115,6 +139,9 @@ module.exports = makeTemporaryEnv => { `it should fallback to the top-level dependencies when it cannot require a transitive dependency require`, makeTemporaryEnv( {dependencies: {[`various-requires`]: `1.0.0`, [`no-deps`]: `1.0.0`}}, + { + plugNPlay: true, + }, async ({path, run, source}) => { await run(`install`); @@ -130,6 +157,9 @@ module.exports = makeTemporaryEnv => { `it should throw an exception if a dependency tries to require something it doesn't own`, makeTemporaryEnv( {dependencies: {[`various-requires`]: `1.0.0`}}, + { + plugNPlay: true, + }, async ({path, run, source}) => { await run(`install`); @@ -145,6 +175,9 @@ module.exports = makeTemporaryEnv => { dependencies: {[`no-deps`]: `1.0.0`}, scripts: {myScript: `node -p 'require("no-deps/package.json").version'`}, }, + { + plugNPlay: true, + }, async ({path, run}) => { await run(`install`); From da25857de7436fdd6d9b3398b5261a1bfb2c0ed6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Tue, 6 Mar 2018 20:43:05 +0000 Subject: [PATCH 024/111] Reimplements the resolution to correctly account for peer dependencies Branch: better-faster-stronger --- src/util/generate-pnp-map.js | 369 ++++++++++++++++++++++++----------- 1 file changed, 253 insertions(+), 116 deletions(-) diff --git a/src/util/generate-pnp-map.js b/src/util/generate-pnp-map.js index 51a7c4b80b..ad09428b38 100644 --- a/src/util/generate-pnp-map.js +++ b/src/util/generate-pnp-map.js @@ -1,12 +1,16 @@ // @flow import type Config from '../config.js'; +import type PackageReference from '../package-reference.js'; +import type PackageRequest from '../package-request.js'; import type PackageResolver from '../package-resolver.js'; +import type {Manifest} from '../types.js'; import * as fs from './fs.js'; +const invariant = require('invariant'); const path = require('path'); -type PackageInformation = {|packageLocation: string, packageDependencies: Map|}; +type PackageInformation = {|packageLocation: string, packageDependencies: Map, packagePeers: Map>|}; type PackageInformationStore = Map; type PackageInformationStores = Map; @@ -19,16 +23,28 @@ function generateMaps(packageInformationStores: PackageInformationStores): strin for (const [packageName, packageInformationStore] of packageInformationStores) { code += ` [${JSON.stringify(packageName)}, new Map([\n`; - for (const [packageReference, {packageLocation, packageDependencies}] of packageInformationStore) { + for (const [packageReference, {packageLocation, packageDependencies, packagePeers}] of packageInformationStore) { code += ` [${JSON.stringify(packageReference)}, {\n`; code += ` packageLocation: ${JSON.stringify(packageLocation)},\n`; - code += ` packageDependencies: new Map([\n`; + code += ` packageDependencies: new Map([\n`; for (const [dependencyName, dependencyReference] of packageDependencies.entries()) { code += ` [${JSON.stringify(dependencyName)}, ${JSON.stringify(dependencyReference)}],\n`; } - code += ` ]),\n`; + + if (packagePeers.size > 0) { + code += ` packagePeers: new Map([\n`; + for (const [dependencyPath, peerEntries] of packagePeers) { + code += ` [${JSON.stringify(dependencyPath)}, new Map([\n`; + for (const [dependencyName, dependencyReference] of peerEntries.entries()) { + code += ` [${JSON.stringify(dependencyName)}, ${JSON.stringify(dependencyReference)}],\n`; + } + code += ` ])],\n`; + } + code += ` ]),\n`; + } + code += ` }],\n`; } @@ -36,168 +52,284 @@ function generateMaps(packageInformationStores: PackageInformationStores): strin } code += `]);\n`; - code += `\n`; - // Also bake an inverse map that will allow us to find the package information based on the path - code += `let locatorsByLocations = new Map([\n`; + return code; +} - for (const [packageName, packageInformationStore] of packageInformationStores) { - for (const [packageReference, {packageLocation}] of packageInformationStore) { - code += ` [${JSON.stringify(packageLocation)}, ${JSON.stringify({ - name: packageName, - reference: packageReference, - })}],\n`; - } - } +/* eslint-disable max-len */ +const PROLOGUE = ` +const path = require('path'); - code += `]);\n`; +const topLevelLocator = {name: null, reference: null}; - return code; -} +`.replace(/^\n/, ``); +/* eslint-enable max-len */ -function generateFindPackageLocator(packageInformationStores: PackageInformationStores): string { - let code = ``; +/* eslint-disable max-len */ +const REQUIRE_HOOK = lockfileFolder => + ` +const Module = require('module'); - // We get the list of each string length we'll need to check in order to find the current package context - const lengths = new Map(); +const builtinModules = Module.builtinModules || Object.keys(process.binding('natives')); - for (const packageInformationStore of packageInformationStores.values()) { - for (const {packageLocation} of packageInformationStore.values()) { - if (packageLocation !== null) { - lengths.set(packageLocation.length, (lengths.get(packageLocation.length) || 0) + 1); - } - } +const originalLoader = Module._load; +const originalResolver = Module._resolveFilename; + +const pathRegExp = /^(?!\\.{0,2}\\/)([^\\/]+)(\\/.*|)$/; + +const pnpPackageLocator = Symbol('pnpPackageLocator'); +const pnpPackagePath = Symbol('pnpPackagePath'); + +const moduleCache = new Map(); + +exports.getPackageInformation = function getPackageInformation({name, reference}) { + const packageInformationStore = packageInformationStores.get(name); + + if (!packageInformationStore) { + return null; } - // We sort the lengths by the number of time they are used, so that the more common ones are tested before the others - const sortedLengths = Array.from(lengths.entries()).sort((a, b) => { - return b[1] - a[1]; - }); + const packageInformation = packageInformationStore.get(reference); - // Generate a function that, given a file path, returns the associated package name - code += `exports.findPackageLocator = function findPackageLocator(location) {\n`; - code += ` let match;\n`; + if (!packageInformation) { + return null; + } - for (const [length] of sortedLengths) { - code += `\n`; - code += ` if (location.length >= ${length} && location[${length} - 1] === path.sep)\n`; - code += ` if (match = locatorsByLocations.get(location.substr(0, ${length})))\n`; - code += ` return match;\n`; + return packageInformation; +}; + +exports.resolveRequest = function resolveFilename(request, packageLocator, parentPath) { + if (builtinModules.indexOf(request) !== -1) { + return null; } - code += `\n`; - code += ` return null;\n`; - code += `};\n`; + const dependencyNameMatch = request.match(pathRegExp); - return code; -} + if (!dependencyNameMatch) { + return null; + } -function generateGetPackageLocation(packageInformationStores: PackageInformationStores): string { - let code = ``; + const [ , dependencyName, subPath ] = dependencyNameMatch; - // Generate a function that, given a locator, returns the package location on the disk + const packageInformation = exports.getPackageInformation(packageLocator); - code += `exports.getPackageLocation = function getPackageLocation({name, reference}) {\n`; - code += ` let packageInformationStore, packageInformation;\n`; - code += `\n`; - code += ` if (packageInformationStore = packageInformationStores.get(name))\n`; - code += ` if (packageInformation = packageInformationStore.get(reference))\n`; - code += ` return packageInformation.packageLocation;\n`; - code += `\n`; - code += ` return null;\n`; - code += `};\n`; + if (!packageInformation) { + throw new Error(\`Couldn't find a matching entry in the dependency tree for the specified parent (this is probably an internal error)\`); + } - return code; -} + // We obtain the dependency reference in regard to the package that request it + // We also need to keep track of whether the dependency had to be loaded through a peerDependency entry + // This is because in this case, the cache key must reflect it -function generateGetPackageDependencies(packageInformationStores: PackageInformationStores): string { - let code = ``; + let dependencyReference = packageInformation.packageDependencies.get(dependencyName); + let isPeerDependency = false; - // Generate a function that, given a locator, returns the package dependencies + // If there's no strict dependency that match the request, we look into peer dependencies - code += `exports.getPackageDependencies = function getPackageDependencies({name, reference}) {\n`; - code += ` let packageInformationStore, packageInformation;\n`; - code += `\n`; - code += ` if (packageInformationStore = packageInformationStores.get(name))\n`; - code += ` if (packageInformation = packageInformationStore.get(reference))\n`; - code += ` return packageInformation.packageDependencies;\n`; - code += `\n`; - code += ` return null;\n`; - code += `};\n`; + if (!dependencyReference && packageInformation.packagePeers) { + const peerResolutions = packageInformation.packagePeers.get(parentPath); - return code; -} + if (!peerResolutions) { + throw new Error(\`Couldn't find the peer candidates for path "\${parentPath}" (this is probably an internal error)\`); + } -/* eslint-disable max-len */ -const PROLOGUE = ` -let path = require('path'); -`.replace(/^\n/, ``); -/* eslint-enable max-len */ + const peerReference = peerResolutions.get(dependencyName); -/* eslint-disable max-len */ -const REQUIRE_HOOK = lockfileFolder => - ` -const Module = require('module'); + if (peerReference === null) { + throw new Error(\`Package "\${packageLocator.name}" tries to access a missing peer dependency ("\${dependencyName}")\`); + } -const builtinModules = Module.builtinModules || Object.keys(process.binding('natives')); + dependencyReference = peerReference; + isPeerDependency = true; + } -const originalResolver = Module._resolveFilename; -const pathRegExp = /^(?!\\.{0,2}\\/)([^\\/]+)(\\/.*|)$/; + // If we STILL can't find it, we fallback to the top-level dependencies + // This fallback isn't ideal, but makes working with plugins much easier -Module._resolveFilename = function (request, parent, isMain, options) { + if (!dependencyReference) { + const topLevelInformation = exports.getPackageInformation(topLevelLocator); - if (builtinModules.indexOf(request) !== -1) { - return request; + dependencyReference = topLevelInformation.packageDependencies.get(dependencyName); } - const dependencyNameMatch = request.match(pathRegExp); + // And if we still haven't been able to resolve it, we give up + // If the package making the request is the top-level, we can be a bit nicer in the error message - if (!dependencyNameMatch) { - return originalResolver.call(Module, request, parent, isMain, options); + if (!dependencyReference) { + if (packageLocator !== topLevelLocator) { + throw new Error(\`Package \${packageLocator.name}@\${packageLocator.reference} is trying to require package \${dependencyName}, which is not declared in its dependencies (\${Array.from(packageInformation.packageDependencies.keys()).join(\`, \`)})\`); + } else { + throw new Error(\`You cannot require a package (\${dependencyName}) that is not declared in your dependencies\`); + } } - let caller = parent; + // We need to check that the package exists on the filesystem, because it might not have been installed - while (caller && (caller.id === '[eval]' || caller.id === '' || !caller.filename)) { - caller = caller.parent; + const dependencyLocator = {name: dependencyName, reference: dependencyReference}; + const dependencyInformation = exports.getPackageInformation(dependencyLocator); + + const dependencyLocation = dependencyInformation.packageLocation; + + if (!dependencyLocation) { + throw new Error(\`Package \${dependencyName}@\${dependencyReference} is a valid dependency, but hasn't been installed and thus cannot be required\`); } - const packagePath = caller ? caller.filename : process.cwd() + path.sep; - const packageLocator = exports.findPackageLocator(packagePath); + const path = \`\${dependencyLocation}/\${subPath}\`; + const cacheKey = isPeerDependency ? \`\${parentPath}@\${path}\` : path; - if (!packageLocator) { - throw new Error(\`Could not find to which package belongs the path \${packagePath}\`); + return {locator: dependencyLocator, path, cacheKey}; +} + +Module._load = function (request, parent, isMain) { + if (builtinModules.indexOf(request) !== -1) { + return originalLoader.call(this, request, parent, isMain); } - const [ , dependencyName, subPath ] = dependencyNameMatch; + const parentLocator = parent && parent[pnpPackageLocator] ? parent[pnpPackageLocator] : topLevelLocator; + const parentPath = parent && parent[pnpPackagePath] ? parent[pnpPackagePath] : ''; - const packageDependencies = exports.getPackageDependencies(packageLocator); - let dependencyReference = packageDependencies.get(dependencyName); + const resolution = exports.resolveRequest(request, parentLocator, parentPath); + const qualifiedPath = originalResolver.call(this, resolution ? resolution.path : request, parent, isMain); - if (!dependencyReference) { - if (packageLocator.name === null) { - throw new Error(\`You cannot require a package (\${dependencyName}) that is not declared in your dependencies\`); - } + const cacheKey = resolution ? resolution.cacheKey : qualifiedPath; + const cacheEntry = moduleCache.get(cacheKey); + + if (cacheEntry) { + return cacheEntry.exports; + } - const topLevelDependencies = exports.getPackageDependencies({ name: null, reference: null }); - dependencyReference = topLevelDependencies.get(dependencyName); + const module = new Module(qualifiedPath, parent); + moduleCache.set(cacheKey, module); - if (!dependencyReference) { - throw new Error(\`Package \${packageLocator.name}@\${packageLocator.reference} is trying to require package \${dependencyName}, which is not declared in its dependencies (\${Array.from(packageDependencies.keys()).join(\`, \`)})\`); + if (isMain) { + process.mainModule = module; + module.id = '.'; + } + + if (resolution) { + module[pnpPackageLocator] = resolution.locator; + module[pnpPackagePath] = parentPath ? \`\${parentPath}/\${resolution.locator.name}\` : resolution.locator.name; + } else { + module[pnpPackagePath] = parentPath; + } + + let hasThrown = true; + + try { + module.load(qualifiedPath); + hasThrown = false; + } finally { + if (hasThrown) { + moduleCache.delete(cacheKey); } } - const dependencyLocation = exports.getPackageLocation({ name: dependencyName, reference: dependencyReference }); + return module.exports; +}; - if (!dependencyLocation) { - throw new Error(\`Package \${dependencyName}@\${dependencyReference} is a valid dependency, but hasn't been installed and thus cannot be required\`); +Module._resolveFilename = function (request, parent, isMain, options) { + if (builtinModules.indexOf(request) !== -1) { + return request; } - return originalResolver.call(Module, \`\${dependencyLocation}/\${subPath}\`, parent, isMain, options); + const parentLocator = parent && parent[pnpPackageLocator] ? parent[pnpPackageLocator] : topLevelLocator; + const parentPath = parent && parent[pnpPackagePath] ? parent[pnpPackagePath] : ''; + + const resolution = exports.resolveRequest(request, parentLocator, parentPath); + const qualifiedPath = originalResolver.call(this, resolution ? resolution.path : request, parent, isMain); + + return qualifiedPath; }; `.replace(/^\n/, ``); /* eslint-enable */ +function getPackagesDistance(fromReq: PackageRequest, toReq: PackageRequest) { + // toReq cannot be a valid peer dependency if it's deeper in the tree + if (toReq.parentNames.length > fromReq.parentNames.length) { + return null; + } + + // To be a valid peer dependency, toReq must have the same parents + for (let t = 0; t < toReq.parentNames.length; ++t) { + if (toReq.parentNames[t] !== fromReq.parentNames[t]) { + return null; + } + } + + // The depth is simply the number of parents between the two packages + return fromReq.parentNames.length - toReq.parentNames.length; +} + +function getPackagePeers(pkg: Manifest, {resolver, exclude}: {resolver: PackageResolver, exclude: Array}): Map> { + const ref = pkg._reference; + invariant(ref, `Ref must exists`); + + // Early exit if the package has no peer dependency + + const peerDependencies = pkg.peerDependencies || {}; + const peerNames = new Set(Object.keys(peerDependencies)); + + for (const excludeName of exclude) { + peerNames.delete(excludeName); + } + + if (peerNames.size === 0) { + return new Map(); + } + + // Cache the candidates for each peer dependency + + const peerCandidateMap = new Map(); + + for (const peerDependency of peerNames) { + peerCandidateMap.set(peerDependency, resolver.getAllInfoForPackageName(peerDependency)); + } + + // Find the best candidates for each peer dependency for each branch that uses `pkg` + + const packagePeers = new Map(); + + for (const req of ref.requests) { + const peerPath = [... req.parentNames, ref.name].join('/'); + const peerEntries = new Map(); + + for (const peerDependency of peerNames) { + const peerCandidates = peerCandidateMap.get(peerDependency); + invariant(peerCandidates, `We must have peer candidates`); + + let bestCandidate = null; + let bestDepth = Infinity; + + for (const peerCandidate of peerCandidates) { + const candidateRef = peerCandidate._reference; + + if (!candidateRef) { + continue; + } + + for (const candidateReq of candidateRef.requests) { + const candidateDepth = getPackagesDistance(req, candidateReq); + + if (candidateDepth !== null && bestDepth > candidateDepth) { + bestCandidate = peerCandidate; + bestDepth = candidateDepth; + } + } + } + + if (bestCandidate) { + peerEntries.set(peerDependency, bestCandidate.version); + } else { + peerEntries.set(peerDependency, null); + } + } + + packagePeers.set(peerPath, peerEntries); + } + + return packagePeers; +} + async function getPackageInformationStores( config: Config, seedPatterns: Array, @@ -218,6 +350,8 @@ async function getPackageInformationStores( packageInformationStores.set(pkg.name, (packageInformationStore = new Map())); } + // Resolve all the dependencies for our package + const packageDependencies = new Map(); for (const pattern of ref.dependencies) { @@ -225,9 +359,14 @@ async function getPackageInformationStores( packageDependencies.set(dep.name, dep.version); } + // Compute the peer dependencies for each possible require path + + const packagePeers = getPackagePeers(pkg, {resolver, exclude: Array.from(packageDependencies.keys())}); + packageInformationStore.set(pkg.version, { packageLocation: (await fs.realpath(loc)).replace(/[\\\/]?$/, path.sep), packageDependencies, + packagePeers, }); } } @@ -249,6 +388,7 @@ async function getPackageInformationStores( { packageLocation: (await fs.realpath(config.lockfileFolder)).replace(/[\\\/]?$/, path.sep), packageDependencies: topLevelDependencies, + packagePeers: new Map(), }, ], ]), @@ -268,9 +408,6 @@ export async function generatePnpMap( return [ PROLOGUE, generateMaps(packageInformationStores), - generateFindPackageLocator(packageInformationStores), - generateGetPackageLocation(packageInformationStores), - generateGetPackageDependencies(packageInformationStores), REQUIRE_HOOK(config.lockfileFolder), ].join(`\n`); } From 8fea70b0ed6ef560b5770e83afef1b8be456f740 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Wed, 7 Mar 2018 14:00:04 +0000 Subject: [PATCH 025/111] Externalizes the creation of proxy scripts Branch: portable-proxy-scripts --- src/util/execute-lifecycle-script.js | 50 ++++++++++++---------------- src/util/portable-script.js | 26 +++++++++++++++ 2 files changed, 47 insertions(+), 29 deletions(-) create mode 100644 src/util/portable-script.js diff --git a/src/util/execute-lifecycle-script.js b/src/util/execute-lifecycle-script.js index 4e3bb05714..96e0725bbf 100644 --- a/src/util/execute-lifecycle-script.js +++ b/src/util/execute-lifecycle-script.js @@ -6,6 +6,7 @@ import {MessageError, ProcessTermError} from '../errors.js'; import * as constants from '../constants.js'; import * as child from './child.js'; import * as fs from './fs.js'; +import {makePortableProxyScript} from './portable-script.js'; import {registries} from '../resolvers/index.js'; import {fixCmdWinSlashes} from './fix-cmd-win-slashes.js'; import {run as globalRun, getBinFolder as getGlobalBinFolder} from '../cli/commands/global.js'; @@ -26,27 +27,13 @@ const IGNORE_MANIFEST_KEYS = ['readme']; // See https://github.com/yarnpkg/yarn/issues/2286. const IGNORE_CONFIG_KEYS = ['lastUpdateCheck']; -const NODE_SIMPLE_SH_WRAPPER = (config: Config) => `#!/bin/sh -"${JSON.stringify(process.execPath)}" "$@" -`; - -const NODE_PNP_SH_WRAPPER = (config: Config) => `#!/bin/sh -"${JSON.stringify(process.execPath)}" -r "${config.lockfileFolder}/${constants.PNP_FILENAME}" "$@" -`; - -const NODE_SH_WRAPPER = async (config: Config) => { +async function getPnpParameters(config: Config) { if (await fs.exists(`${config.lockfileFolder}/${constants.PNP_FILENAME}`)) { - return NODE_PNP_SH_WRAPPER(config); + return ['-r', `${config.lockfileFolder}/${constants.PNP_FILENAME}`]; } else { - return NODE_SIMPLE_SH_WRAPPER(config); + return []; } -}; - -const YARN_SH_WRAPPER = (config: Config) => `#!/bin/sh -"${JSON.stringify(process.execPath)}" "${process.argv[1]}" "$@" -`; - -const LIFECYCLE_WRAPPERS = [[`yarn`, YARN_SH_WRAPPER], [`node`, NODE_SH_WRAPPER]]; +} let wrappersFolder = null; @@ -57,12 +44,15 @@ export async function getWrappersFolder(config: Config): Promise { wrappersFolder = await fs.makeTempDir(); - for (const [fileName, content] of LIFECYCLE_WRAPPERS) { - const wrapperPath = `${wrappersFolder}/${fileName}`; + await makePortableProxyScript(process.execPath, wrappersFolder, { + proxyBasename: 'node', + prependArguments: [... await getPnpParameters(config)], + }); - await fs.writeFile(wrapperPath, await content(config)); - await fs.chmod(wrapperPath, 0o755); - } + await makePortableProxyScript(process.execPath, wrappersFolder, { + proxyBasename: 'yarn', + prependArguments: [process.argv[1]], + }); return wrappersFolder; } @@ -191,13 +181,15 @@ export async function makeEnv( } // add .bin folders to PATH - for (const registry of Object.keys(registries)) { - const binFolder = path.join(config.registries[registry].folder, '.bin'); - if (config.workspacesEnabled && config.workspaceRootFolder) { - pathParts.unshift(path.join(config.workspaceRootFolder, binFolder)); + if (!config.plugnplayEnabled) { + for (const registry of Object.keys(registries)) { + const binFolder = path.join(config.registries[registry].folder, '.bin'); + if (config.workspacesEnabled && config.workspaceRootFolder) { + pathParts.unshift(path.join(config.workspaceRootFolder, binFolder)); + } + pathParts.unshift(path.join(config.linkFolder, binFolder)); + pathParts.unshift(path.join(cwd, binFolder)); } - pathParts.unshift(path.join(config.linkFolder, binFolder)); - pathParts.unshift(path.join(cwd, binFolder)); } pathParts.unshift(await getWrappersFolder(config)); diff --git a/src/util/portable-script.js b/src/util/portable-script.js new file mode 100644 index 0000000000..e9ef8b4380 --- /dev/null +++ b/src/util/portable-script.js @@ -0,0 +1,26 @@ +import * as fs from './fs.js'; + +const path = require('path'); + +export type PortableProxyOptions = {| + proxyBasename?: string, + extraEnvironment?: Map, + prependArguments?: Array, + appendArguments?: Array, +|}; + +async function makePortableProxyScriptUnix(source: string, destination: string, options: PortableProxyOptions): Promise { + const environment = options.extraEnvironment ? Array.from(options.extraEnvironment.entries()).map(([key, value]) => `${key}="${value}"`).join(' ') : ''; + + const prependedArguments = options.prependArguments ? options.prependArguments.map(arg => `"${arg}"`).join(' ') : ''; + const appendedArguments = options.appendArguments ? options.appendArguments.map(arg => `"${arg}"`).join(' ') : ''; + + const filePath = `${destination}/${options.proxyBasename || path.basename(source)}`; + + await fs.writeFile(filePath, `#!/bin/sh\n${environment} "${source}" ${prependedArguments} "$@" ${appendedArguments}\n`); + await fs.chmod(filePath, 0o755); +} + +export function makePortableProxyScript(source: string, destination: string, options: PortableProxyOptions = {}): Promise { + return makePortableProxyScriptUnix(source, destination, options); +} From 8e77876d69269b27963be3fa9437cf92f6a35b31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Fri, 9 Mar 2018 01:18:19 +0000 Subject: [PATCH 026/111] Implements support for `yarn run` within pnp-enabled installations Branch: pnp-yarn-run --- .../packages/has-bin-entries-1.0.0/bin.js | 5 + .../packages/has-bin-entries-1.0.0/index.js | 10 ++ .../has-bin-entries-1.0.0/package.json | 7 ++ .../pkg-tests/pkg-tests-specs/sources/pnp.js | 9 +- .../pkg-tests-specs/sources/script.js | 53 ++++++++ packages/pkg-tests/yarn.test.js | 4 +- src/cli/commands/run.js | 91 +++++++++----- src/constants.js | 2 +- src/fetchers/base-fetcher.js | 10 ++ src/util/dynamic-require.js | 4 + src/util/execute-lifecycle-script.js | 38 ++++-- src/util/generate-pnp-map.js | 116 ++++++++++-------- src/util/portable-script.js | 24 +++- 13 files changed, 271 insertions(+), 102 deletions(-) create mode 100755 packages/pkg-tests/pkg-tests-fixtures/packages/has-bin-entries-1.0.0/bin.js create mode 100644 packages/pkg-tests/pkg-tests-fixtures/packages/has-bin-entries-1.0.0/index.js create mode 100644 packages/pkg-tests/pkg-tests-fixtures/packages/has-bin-entries-1.0.0/package.json create mode 100644 src/util/dynamic-require.js diff --git a/packages/pkg-tests/pkg-tests-fixtures/packages/has-bin-entries-1.0.0/bin.js b/packages/pkg-tests/pkg-tests-fixtures/packages/has-bin-entries-1.0.0/bin.js new file mode 100755 index 0000000000..7e9cf01609 --- /dev/null +++ b/packages/pkg-tests/pkg-tests-fixtures/packages/has-bin-entries-1.0.0/bin.js @@ -0,0 +1,5 @@ +#!/usr/bin/env node + +for (let t = 2; t < process.argv.length; ++t) { + console.log(process.argv[t]); +} diff --git a/packages/pkg-tests/pkg-tests-fixtures/packages/has-bin-entries-1.0.0/index.js b/packages/pkg-tests/pkg-tests-fixtures/packages/has-bin-entries-1.0.0/index.js new file mode 100644 index 0000000000..a6bf8f5865 --- /dev/null +++ b/packages/pkg-tests/pkg-tests-fixtures/packages/has-bin-entries-1.0.0/index.js @@ -0,0 +1,10 @@ +/* @flow */ + +module.exports = require(`./package.json`); + +for (const key of [`dependencies`, `devDependencies`, `peerDependencies`]) { + for (const dep of Object.keys(module.exports[key] || {})) { + // $FlowFixMe The whole point of this file is to be dynamic + module.exports[key][dep] = require(dep); + } +} diff --git a/packages/pkg-tests/pkg-tests-fixtures/packages/has-bin-entries-1.0.0/package.json b/packages/pkg-tests/pkg-tests-fixtures/packages/has-bin-entries-1.0.0/package.json new file mode 100644 index 0000000000..0ed2fe2a6f --- /dev/null +++ b/packages/pkg-tests/pkg-tests-fixtures/packages/has-bin-entries-1.0.0/package.json @@ -0,0 +1,7 @@ +{ + "name": "has-bin-entries", + "version": "1.0.0", + "bin": { + "has-bin-entries": "./bin.js" + } +} diff --git a/packages/pkg-tests/pkg-tests-specs/sources/pnp.js b/packages/pkg-tests/pkg-tests-specs/sources/pnp.js index 3fb9667be4..1a7cde5a47 100644 --- a/packages/pkg-tests/pkg-tests-specs/sources/pnp.js +++ b/packages/pkg-tests/pkg-tests-specs/sources/pnp.js @@ -1,7 +1,8 @@ const {fs: {writeFile}, tests: {getPackageDirectoryPath}} = require('pkg-tests-core'); -const {basic: basicSpecs} = require('pkg-tests-specs'); module.exports = makeTemporaryEnv => { + const {basic: basicSpecs, script: scriptSpecs} = require('pkg-tests-specs'); + describe(`Plug'n'Play`, () => { basicSpecs( makeTemporaryEnv.withConfig({ @@ -9,6 +10,12 @@ module.exports = makeTemporaryEnv => { }), ); + scriptSpecs( + makeTemporaryEnv.withConfig({ + plugNPlay: true, + }), + ); + test( `it should resolve two identical packages with the same object (easy)`, makeTemporaryEnv( diff --git a/packages/pkg-tests/pkg-tests-specs/sources/script.js b/packages/pkg-tests/pkg-tests-specs/sources/script.js index 8f6f659cfd..b8a78278ab 100644 --- a/packages/pkg-tests/pkg-tests-specs/sources/script.js +++ b/packages/pkg-tests/pkg-tests-specs/sources/script.js @@ -16,6 +16,7 @@ module.exports = (makeTemporaryEnv: PackageDriver) => { }); }), ); + test( `it should run scripts using the same package manager than the one running the scripts`, makeTemporaryEnv({scripts: {myScript: `yarn --version`}}, async ({path, run, source}) => { @@ -26,5 +27,57 @@ module.exports = (makeTemporaryEnv: PackageDriver) => { }); }), ); + + test( + `it should run declared scripts`, + makeTemporaryEnv( + { + scripts: { + [`foobar`]: `echo test successful`, + }, + }, + async ({path, run, source}) => { + await expect(run(`run`, `foobar`)).resolves.toMatchObject({ + stdout: `test successful\n`, + }); + }, + ), + ); + + test( + `it should expose its dependencies within the $PATH`, + makeTemporaryEnv( + { + dependencies: { + [`has-bin-entries`]: `1.0.0`, + }, + }, + async ({path, run, source}) => { + await run(`install`); + + await expect(run(`run`, `has-bin-entries`, `success`)).resolves.toMatchObject({ + stdout: `success\n`, + }); + }, + ), + ); + + test( + `it shouldn't require the "--" flag to stop interpreting options after "run" commands`, + makeTemporaryEnv( + { + dependencies: { + [`has-bin-entries`]: `1.0.0`, + }, + }, + async ({path, run, source}) => { + await run(`install`); + + await expect(run(`run`, `has-bin-entries`, `--hello`)).resolves.toMatchObject({ + stdout: `--hello\n`, + }); + }, + ), + ); }); }; diff --git a/packages/pkg-tests/yarn.test.js b/packages/pkg-tests/yarn.test.js index 984278337a..4567910966 100644 --- a/packages/pkg-tests/yarn.test.js +++ b/packages/pkg-tests/yarn.test.js @@ -35,6 +35,6 @@ beforeEach(async () => { }); basicSpecs(pkgDriver); -dragonSpecs(pkgDriver); -pnpSpecs(pkgDriver); scriptSpecs(pkgDriver); +pnpSpecs(pkgDriver); +dragonSpecs(pkgDriver); diff --git a/src/cli/commands/run.js b/src/cli/commands/run.js index 300acf89f2..39fcbfb3e0 100644 --- a/src/cli/commands/run.js +++ b/src/cli/commands/run.js @@ -3,15 +3,27 @@ import type {Reporter} from '../../reporters/index.js'; import type Config from '../../config.js'; import {execCommand, makeEnv} from '../../util/execute-lifecycle-script.js'; +import {dynamicRequire} from '../../util/dynamic-require.js'; import {MessageError} from '../../errors.js'; import {registries} from '../../resolvers/index.js'; import * as fs from '../../util/fs.js'; -import map from '../../util/map.js'; +import * as constants from '../../constants.js'; +const invariant = require('invariant'); const leven = require('leven'); const path = require('path'); const {quoteForShell, sh, unquoted} = require('puka'); +function toObject(input: Map): Object { + const output = Object.create(null); + + for (const [key, val] of input.entries()) { + output[key] = val; + } + + return output; +} + export function setFlags(commander: Object) { commander.description('Runs a defined package script.'); } @@ -21,36 +33,51 @@ export function hasWrapper(commander: Object, args: Array): boolean { } export async function run(config: Config, reporter: Reporter, flags: Object, args: Array): Promise { - // build up a list of possible scripts const pkg = await config.readManifest(config.cwd); - const scripts = map(); - const binCommands = []; - const visitedBinFolders = new Set(); - let pkgCommands = []; + + const binFolders = new Set(); + + // Setup the node_modules/.bin folders for analysis for (const registry of Object.keys(registries)) { - const binFolder = path.join(config.cwd, config.registries[registry].folder, '.bin'); - if (!visitedBinFolders.has(binFolder)) { - if (await fs.exists(binFolder)) { - for (const name of await fs.readdir(binFolder)) { - binCommands.push(name); - scripts[name] = quoteForShell(path.join(binFolder, name)); - } + binFolders.add(path.join(config.cwd, config.registries[registry].folder, '.bin')); + } + + // Same thing, but for the pnp dependencies, located inside the cache + if (await fs.exists(`${config.lockfileFolder}/${constants.PNP_FILENAME}`)) { + const pnpApi = dynamicRequire(`${config.lockfileFolder}/${constants.PNP_FILENAME}`); + const topLevelInformation = pnpApi.getPackageInformation({name: null, reference: null}); + + for (const [name, reference] of topLevelInformation.packageDependencies.entries()) { + const dependencyInformation = pnpApi.getPackageInformation({name, reference}); + + if (dependencyInformation.packageLocation) { + binFolders.add(`${dependencyInformation.packageLocation}/.bin`); } - visitedBinFolders.add(binFolder); } } - const pkgScripts = pkg.scripts; - const cmdHints = {}; - if (pkgScripts) { - // inherit `scripts` from manifest - pkgCommands = Object.keys(pkgScripts).sort(); - // add command hints (what the actual yarn command will do) - for (const cmd of pkgCommands) { - cmdHints[cmd] = pkgScripts[cmd] || ''; + const binCommands = new Set(); + const pkgCommands = new Set(); + + const scripts: Map = new Map(); + + // Build up a list of possible scripts by exploring the folders marked for analysis + for (const binFolder of binFolders) { + if (await fs.exists(binFolder)) { + for (const name of await fs.readdir(binFolder)) { + scripts.set(name, quoteForShell(path.join(binFolder, name))); + binCommands.add(name); + } } + } + + const pkgScripts = pkg.scripts; - Object.assign(scripts, pkgScripts); + if (pkgScripts) { + for (const name of Object.keys(pkgScripts).sort()) { + scripts.set(name, pkgScripts[name] || ''); + pkgCommands.add(name); + } } async function runCommand(args): Promise { @@ -65,14 +92,18 @@ export async function run(config: Config, reporter: Reporter, flags: Object, arg cmds.push([preAction, pkgScripts[preAction]]); } - cmds.push([action, scripts[action]]); + const script = scripts.get(action); + invariant(script, 'Script must exist'); + cmds.push([action, script]); const postAction = `post${action}`; if (postAction in pkgScripts) { cmds.push([postAction, pkgScripts[postAction]]); } - } else if (scripts[action]) { - cmds.push([action, scripts[action]]); + } else if (scripts.has(action)) { + const script = scripts.get(action); + invariant(script, 'Script must exist'); + cmds.push([action, script]); } if (cmds.length) { @@ -112,15 +143,15 @@ export async function run(config: Config, reporter: Reporter, flags: Object, arg if (args.length === 0) { reporter.error(reporter.lang('commandNotSpecified')); - if (binCommands.length) { - reporter.info(`${reporter.lang('binCommands') + binCommands.join(', ')}`); + if (binCommands.size > 0) { + reporter.info(`${reporter.lang('binCommands') + Array.from(binCommands).join(', ')}`); } else { reporter.error(reporter.lang('noBinAvailable')); } - if (pkgCommands.length) { + if (pkgCommands.size > 0) { reporter.info(`${reporter.lang('possibleCommands')}`); - reporter.list('possibleCommands', pkgCommands, cmdHints); + reporter.list('possibleCommands', Array.from(scripts.keys()), toObject(scripts)); await reporter .question(reporter.lang('commandQuestion')) .then(answer => runCommand(answer.split(' ')), () => reporter.error(reporter.lang('commandNotSpecified'))); diff --git a/src/constants.js b/src/constants.js index a4ba0cd50b..c56cd727de 100644 --- a/src/constants.js +++ b/src/constants.js @@ -27,7 +27,7 @@ export const SELF_UPDATE_TARBALL_URL = 'https://yarnpkg.com/latest.tar.gz'; export const SELF_UPDATE_DOWNLOAD_FOLDER = 'updates'; // cache version, bump whenever we make backwards incompatible changes -export const CACHE_VERSION = 1; +export const CACHE_VERSION = 2; // lockfile version, bump whenever we make backwards incompatible changes export const LOCKFILE_VERSION = 1; diff --git a/src/fetchers/base-fetcher.js b/src/fetchers/base-fetcher.js index 7ddbfcd492..0df85a88f0 100644 --- a/src/fetchers/base-fetcher.js +++ b/src/fetchers/base-fetcher.js @@ -6,6 +6,7 @@ import type {PackageRemote, FetchedMetadata, FetchedOverride} from '../types.js' import type {RegistryNames} from '../registries/index.js'; import type Config from '../config.js'; import normalizeManifest from '../util/normalize-manifest/index.js'; +import {linkBin} from '../package-linker.js'; import * as constants from '../constants.js'; import * as fs from '../util/fs.js'; @@ -62,6 +63,15 @@ export default class BaseFetcher { } })(); + if (pkg.bin) { + for (const binName of Object.keys(pkg.bin)) { + const dest = `${this.dest}/.bin/${binName}`; + const src = `${this.dest}/${pkg.bin[binName]}`; + + await linkBin(src, dest); + } + } + await fs.writeFile( path.join(this.dest, constants.METADATA_FILENAME), JSON.stringify( diff --git a/src/util/dynamic-require.js b/src/util/dynamic-require.js new file mode 100644 index 0000000000..0fef3c653d --- /dev/null +++ b/src/util/dynamic-require.js @@ -0,0 +1,4 @@ +/* @flow */ + +// $FlowFixMe We want this require to be dynamic +exports.dynamicRequire = typeof __webpack_require__ !== 'undefined' ? __non_webpack_require__ : require; // eslint-disable-line diff --git a/src/util/execute-lifecycle-script.js b/src/util/execute-lifecycle-script.js index 96e0725bbf..4de302f3e7 100644 --- a/src/util/execute-lifecycle-script.js +++ b/src/util/execute-lifecycle-script.js @@ -6,6 +6,7 @@ import {MessageError, ProcessTermError} from '../errors.js'; import * as constants from '../constants.js'; import * as child from './child.js'; import * as fs from './fs.js'; +import {dynamicRequire} from './dynamic-require.js'; import {makePortableProxyScript} from './portable-script.js'; import {registries} from '../resolvers/index.js'; import {fixCmdWinSlashes} from './fix-cmd-win-slashes.js'; @@ -27,7 +28,7 @@ const IGNORE_MANIFEST_KEYS = ['readme']; // See https://github.com/yarnpkg/yarn/issues/2286. const IGNORE_CONFIG_KEYS = ['lastUpdateCheck']; -async function getPnpParameters(config: Config) { +async function getPnpParameters(config: Config): Promise> { if (await fs.exists(`${config.lockfileFolder}/${constants.PNP_FILENAME}`)) { return ['-r', `${config.lockfileFolder}/${constants.PNP_FILENAME}`]; } else { @@ -46,7 +47,7 @@ export async function getWrappersFolder(config: Config): Promise { await makePortableProxyScript(process.execPath, wrappersFolder, { proxyBasename: 'node', - prependArguments: [... await getPnpParameters(config)], + prependArguments: [...(await getPnpParameters(config))], }); await makePortableProxyScript(process.execPath, wrappersFolder, { @@ -180,15 +181,32 @@ export async function makeEnv( pathParts.unshift(globalBin); } - // add .bin folders to PATH - if (!config.plugnplayEnabled) { - for (const registry of Object.keys(registries)) { - const binFolder = path.join(config.registries[registry].folder, '.bin'); - if (config.workspacesEnabled && config.workspaceRootFolder) { - pathParts.unshift(path.join(config.workspaceRootFolder, binFolder)); + // Add node_modules .bin folders to the PATH + for (const registry of Object.keys(registries)) { + const binFolder = path.join(config.registries[registry].folder, '.bin'); + if (config.workspacesEnabled && config.workspaceRootFolder) { + pathParts.unshift(path.join(config.workspaceRootFolder, binFolder)); + } + pathParts.unshift(path.join(config.linkFolder, binFolder)); + pathParts.unshift(path.join(cwd, binFolder)); + } + + // Otherwise, only add the top-level dependencies to the PATH + // Note that this isn't enough when executing scripts from subdependencies, but since dependencies with postinstall + // scripts have other issues that require us to make them fallback to regular node_modules installation (like sharing + // artifacts), we can sit on this one until we fix everything at once. + if (await fs.exists(`${config.lockfileFolder}/${constants.PNP_FILENAME}`)) { + const pnpApi = dynamicRequire(`${config.lockfileFolder}/${constants.PNP_FILENAME}`); + const topLevelInformation = pnpApi.getPackageInformation({name: null, reference: null}); + + for (const [name, reference] of topLevelInformation.packageDependencies.entries()) { + const dependencyInformation = pnpApi.getPackageInformation({name, reference}); + + if (!dependencyInformation || !dependencyInformation.packageLocation) { + continue; } - pathParts.unshift(path.join(config.linkFolder, binFolder)); - pathParts.unshift(path.join(cwd, binFolder)); + + pathParts.unshift(`${dependencyInformation.packageLocation}/.bin`); } } diff --git a/src/util/generate-pnp-map.js b/src/util/generate-pnp-map.js index ad09428b38..252ea89772 100644 --- a/src/util/generate-pnp-map.js +++ b/src/util/generate-pnp-map.js @@ -1,7 +1,6 @@ // @flow import type Config from '../config.js'; -import type PackageReference from '../package-reference.js'; import type PackageRequest from '../package-request.js'; import type PackageResolver from '../package-resolver.js'; import type {Manifest} from '../types.js'; @@ -10,7 +9,11 @@ import * as fs from './fs.js'; const invariant = require('invariant'); const path = require('path'); -type PackageInformation = {|packageLocation: string, packageDependencies: Map, packagePeers: Map>|}; +type PackageInformation = {| + packageLocation: string, + packageDependencies: Map, + packagePeers: Map>, +|}; type PackageInformationStore = Map; type PackageInformationStores = Map; @@ -180,70 +183,76 @@ exports.resolveRequest = function resolveFilename(request, packageLocator, paren return {locator: dependencyLocator, path, cacheKey}; } -Module._load = function (request, parent, isMain) { - if (builtinModules.indexOf(request) !== -1) { - return originalLoader.call(this, request, parent, isMain); - } +exports.setup = function setup () { + Module._load = function (request, parent, isMain) { + if (builtinModules.indexOf(request) !== -1) { + return originalLoader.call(this, request, parent, isMain); + } - const parentLocator = parent && parent[pnpPackageLocator] ? parent[pnpPackageLocator] : topLevelLocator; - const parentPath = parent && parent[pnpPackagePath] ? parent[pnpPackagePath] : ''; + const parentLocator = parent && parent[pnpPackageLocator] ? parent[pnpPackageLocator] : topLevelLocator; + const parentPath = parent && parent[pnpPackagePath] ? parent[pnpPackagePath] : ''; - const resolution = exports.resolveRequest(request, parentLocator, parentPath); - const qualifiedPath = originalResolver.call(this, resolution ? resolution.path : request, parent, isMain); + const resolution = exports.resolveRequest(request, parentLocator, parentPath); + const qualifiedPath = originalResolver.call(this, resolution ? resolution.path : request, parent, isMain); - const cacheKey = resolution ? resolution.cacheKey : qualifiedPath; - const cacheEntry = moduleCache.get(cacheKey); + const cacheKey = resolution ? resolution.cacheKey : qualifiedPath; + const cacheEntry = moduleCache.get(cacheKey); - if (cacheEntry) { - return cacheEntry.exports; - } + if (cacheEntry) { + return cacheEntry.exports; + } - const module = new Module(qualifiedPath, parent); - moduleCache.set(cacheKey, module); + const module = new Module(qualifiedPath, parent); + moduleCache.set(cacheKey, module); - if (isMain) { - process.mainModule = module; - module.id = '.'; - } + if (isMain) { + process.mainModule = module; + module.id = '.'; + } - if (resolution) { - module[pnpPackageLocator] = resolution.locator; - module[pnpPackagePath] = parentPath ? \`\${parentPath}/\${resolution.locator.name}\` : resolution.locator.name; - } else { - module[pnpPackagePath] = parentPath; - } + if (resolution) { + module[pnpPackageLocator] = resolution.locator; + module[pnpPackagePath] = parentPath ? \`\${parentPath}/\${resolution.locator.name}\` : resolution.locator.name; + } else { + module[pnpPackagePath] = parentPath; + } - let hasThrown = true; + let hasThrown = true; - try { - module.load(qualifiedPath); - hasThrown = false; - } finally { - if (hasThrown) { - moduleCache.delete(cacheKey); + try { + module.load(qualifiedPath); + hasThrown = false; + } finally { + if (hasThrown) { + moduleCache.delete(cacheKey); + } } - } - return module.exports; -}; + return module.exports; + }; -Module._resolveFilename = function (request, parent, isMain, options) { - if (builtinModules.indexOf(request) !== -1) { - return request; - } + Module._resolveFilename = function (request, parent, isMain, options) { + if (builtinModules.indexOf(request) !== -1) { + return request; + } - const parentLocator = parent && parent[pnpPackageLocator] ? parent[pnpPackageLocator] : topLevelLocator; - const parentPath = parent && parent[pnpPackagePath] ? parent[pnpPackagePath] : ''; + const parentLocator = parent && parent[pnpPackageLocator] ? parent[pnpPackageLocator] : topLevelLocator; + const parentPath = parent && parent[pnpPackagePath] ? parent[pnpPackagePath] : ''; - const resolution = exports.resolveRequest(request, parentLocator, parentPath); - const qualifiedPath = originalResolver.call(this, resolution ? resolution.path : request, parent, isMain); + const resolution = exports.resolveRequest(request, parentLocator, parentPath); + const qualifiedPath = originalResolver.call(this, resolution ? resolution.path : request, parent, isMain); - return qualifiedPath; + return qualifiedPath; + }; }; + +if (module.parent && module.parent.id === 'internal/preload') { + exports.setup(); +} `.replace(/^\n/, ``); /* eslint-enable */ -function getPackagesDistance(fromReq: PackageRequest, toReq: PackageRequest) { +function getPackagesDistance(fromReq: PackageRequest, toReq: PackageRequest): number | null { // toReq cannot be a valid peer dependency if it's deeper in the tree if (toReq.parentNames.length > fromReq.parentNames.length) { return null; @@ -260,7 +269,10 @@ function getPackagesDistance(fromReq: PackageRequest, toReq: PackageRequest) { return fromReq.parentNames.length - toReq.parentNames.length; } -function getPackagePeers(pkg: Manifest, {resolver, exclude}: {resolver: PackageResolver, exclude: Array}): Map> { +function getPackagePeers( + pkg: Manifest, + {resolver, exclude}: {resolver: PackageResolver, exclude: Array}, +): Map> { const ref = pkg._reference; invariant(ref, `Ref must exists`); @@ -290,7 +302,7 @@ function getPackagePeers(pkg: Manifest, {resolver, exclude}: {resolver: PackageR const packagePeers = new Map(); for (const req of ref.requests) { - const peerPath = [... req.parentNames, ref.name].join('/'); + const peerPath = [...req.parentNames, ref.name].join('/'); const peerEntries = new Map(); for (const peerDependency of peerNames) { @@ -405,9 +417,5 @@ export async function generatePnpMap( ): Promise { const packageInformationStores = await getPackageInformationStores(config, seedPatterns, {resolver}); - return [ - PROLOGUE, - generateMaps(packageInformationStores), - REQUIRE_HOOK(config.lockfileFolder), - ].join(`\n`); + return [PROLOGUE, generateMaps(packageInformationStores), REQUIRE_HOOK(config.lockfileFolder)].join(`\n`); } diff --git a/src/util/portable-script.js b/src/util/portable-script.js index e9ef8b4380..4a38fd72cf 100644 --- a/src/util/portable-script.js +++ b/src/util/portable-script.js @@ -1,3 +1,5 @@ +/* @flow */ + import * as fs from './fs.js'; const path = require('path'); @@ -9,18 +11,32 @@ export type PortableProxyOptions = {| appendArguments?: Array, |}; -async function makePortableProxyScriptUnix(source: string, destination: string, options: PortableProxyOptions): Promise { - const environment = options.extraEnvironment ? Array.from(options.extraEnvironment.entries()).map(([key, value]) => `${key}="${value}"`).join(' ') : ''; +async function makePortableProxyScriptUnix( + source: string, + destination: string, + options: PortableProxyOptions, +): Promise { + const environment = options.extraEnvironment + ? Array.from(options.extraEnvironment.entries()).map(([key, value]) => `${key}="${value}"`).join(' ') + : ''; const prependedArguments = options.prependArguments ? options.prependArguments.map(arg => `"${arg}"`).join(' ') : ''; const appendedArguments = options.appendArguments ? options.appendArguments.map(arg => `"${arg}"`).join(' ') : ''; const filePath = `${destination}/${options.proxyBasename || path.basename(source)}`; - await fs.writeFile(filePath, `#!/bin/sh\n${environment} "${source}" ${prependedArguments} "$@" ${appendedArguments}\n`); + await fs.writeFile( + filePath, + `#!/bin/sh\n${environment} "${source}" ${prependedArguments} "$@" ${appendedArguments}\n`, + ); await fs.chmod(filePath, 0o755); } -export function makePortableProxyScript(source: string, destination: string, options: PortableProxyOptions = {}): Promise { +export function makePortableProxyScript( + source: string, + destination: string, + // $FlowFixMe Flow doesn't support exact types with empty default values + options: PortableProxyOptions = {}, +): Promise { return makePortableProxyScriptUnix(source, destination, options); } From 6daa57cf462a7b8404dc07df6c1b8eec81f72462 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Fri, 9 Mar 2018 12:30:56 +0000 Subject: [PATCH 027/111] Makes it possible for dependency binaries to require their own dependencies Branch: pnp-yarn-run-dependencies --- .../has-bin-entries-1.0.0/bin-with-require.js | 6 +++ .../has-bin-entries-1.0.0/package.json | 6 ++- .../pkg-tests-specs/sources/script.js | 18 +++++++++ src/fetchers/base-fetcher.js | 9 +++-- src/util/generate-pnp-map.js | 37 +++++++++++++++++-- src/util/portable-script.js | 19 ++++++++-- 6 files changed, 83 insertions(+), 12 deletions(-) create mode 100755 packages/pkg-tests/pkg-tests-fixtures/packages/has-bin-entries-1.0.0/bin-with-require.js diff --git a/packages/pkg-tests/pkg-tests-fixtures/packages/has-bin-entries-1.0.0/bin-with-require.js b/packages/pkg-tests/pkg-tests-fixtures/packages/has-bin-entries-1.0.0/bin-with-require.js new file mode 100755 index 0000000000..0bee57337a --- /dev/null +++ b/packages/pkg-tests/pkg-tests-fixtures/packages/has-bin-entries-1.0.0/bin-with-require.js @@ -0,0 +1,6 @@ +#!/usr/bin/env node + +const noDeps = require('no-deps'); + +console.log(noDeps.name); +console.log(noDeps.version); diff --git a/packages/pkg-tests/pkg-tests-fixtures/packages/has-bin-entries-1.0.0/package.json b/packages/pkg-tests/pkg-tests-fixtures/packages/has-bin-entries-1.0.0/package.json index 0ed2fe2a6f..b45b064d28 100644 --- a/packages/pkg-tests/pkg-tests-fixtures/packages/has-bin-entries-1.0.0/package.json +++ b/packages/pkg-tests/pkg-tests-fixtures/packages/has-bin-entries-1.0.0/package.json @@ -2,6 +2,10 @@ "name": "has-bin-entries", "version": "1.0.0", "bin": { - "has-bin-entries": "./bin.js" + "has-bin-entries": "./bin.js", + "has-bin-entries-with-require": "./bin-with-require.js" + }, + "dependencies": { + "no-deps": "1.0.0" } } diff --git a/packages/pkg-tests/pkg-tests-specs/sources/script.js b/packages/pkg-tests/pkg-tests-specs/sources/script.js index b8a78278ab..3c726b47f6 100644 --- a/packages/pkg-tests/pkg-tests-specs/sources/script.js +++ b/packages/pkg-tests/pkg-tests-specs/sources/script.js @@ -79,5 +79,23 @@ module.exports = (makeTemporaryEnv: PackageDriver) => { }, ), ); + + test( + `it should allow dependencies binaries to require their own dependencies`, + makeTemporaryEnv( + { + dependencies: { + [`has-bin-entries`]: `1.0.0`, + }, + }, + async ({path, run, source}) => { + await run(`install`); + + await expect(run(`run`, `has-bin-entries-with-require`)).resolves.toMatchObject({ + stdout: `no-deps\n1.0.0\n`, + }); + }, + ), + ); }); }; diff --git a/src/fetchers/base-fetcher.js b/src/fetchers/base-fetcher.js index 0df85a88f0..fe08ea5a20 100644 --- a/src/fetchers/base-fetcher.js +++ b/src/fetchers/base-fetcher.js @@ -6,7 +6,7 @@ import type {PackageRemote, FetchedMetadata, FetchedOverride} from '../types.js' import type {RegistryNames} from '../registries/index.js'; import type Config from '../config.js'; import normalizeManifest from '../util/normalize-manifest/index.js'; -import {linkBin} from '../package-linker.js'; +import {makePortableProxyScript} from '../util/portable-script.js'; import * as constants from '../constants.js'; import * as fs from '../util/fs.js'; @@ -65,10 +65,13 @@ export default class BaseFetcher { if (pkg.bin) { for (const binName of Object.keys(pkg.bin)) { - const dest = `${this.dest}/.bin/${binName}`; + const dest = `${this.dest}/.bin`; const src = `${this.dest}/${pkg.bin[binName]}`; - await linkBin(src, dest); + await makePortableProxyScript(src, dest, { + proxyBasename: binName, + pnpPackageName: pkg.name, + }); } } diff --git a/src/util/generate-pnp-map.js b/src/util/generate-pnp-map.js index 252ea89772..e358c1e3c4 100644 --- a/src/util/generate-pnp-map.js +++ b/src/util/generate-pnp-map.js @@ -183,14 +183,42 @@ exports.resolveRequest = function resolveFilename(request, packageLocator, paren return {locator: dependencyLocator, path, cacheKey}; } -exports.setup = function setup () { +exports.setup = function setup (initialParentPath) { + let initialParentLocator = topLevelLocator; + + for (let t = 0; t < initialParentPath.length; ++t) { + const dependencies = exports.getPackageInformation(initialParentLocator); + const currentPath = initialParentPath.slice(0, t).join('/'); + + const dependencyName = initialParentPath[t]; + let dependencyReference = dependencies.packageDependencies.get(dependencyName); + + if (!dependencyReference && dependencies.packagePeers) { + const peerResolutions = dependencies.packagePeers.get(currentPath); + + if (peerResolutions) { + dependencyReference = peerResolutions.get(dependencyName); + } + } + + if (!dependencyReference) { + if (initialParentLocator === topLevelLocator) { + throw new Error(\`Could not find package "\${dependencyName} in the dependencies of your project (this is probably an internal error)\`); + } else { + throw new Error(\`Could not find package "\${dependencyName} in the dependencies of "\${currentPath}" (this is probably an internal error)\`); + } + } + + initialParentLocator = {name: dependencyName, reference: dependencyReference}; + } + Module._load = function (request, parent, isMain) { if (builtinModules.indexOf(request) !== -1) { return originalLoader.call(this, request, parent, isMain); } - const parentLocator = parent && parent[pnpPackageLocator] ? parent[pnpPackageLocator] : topLevelLocator; - const parentPath = parent && parent[pnpPackagePath] ? parent[pnpPackagePath] : ''; + const parentLocator = parent && parent[pnpPackageLocator] ? parent[pnpPackageLocator] : initialParentLocator; + const parentPath = parent && parent[pnpPackagePath] ? parent[pnpPackagePath] : initialParentPath; const resolution = exports.resolveRequest(request, parentLocator, parentPath); const qualifiedPath = originalResolver.call(this, resolution ? resolution.path : request, parent, isMain); @@ -214,6 +242,7 @@ exports.setup = function setup () { module[pnpPackageLocator] = resolution.locator; module[pnpPackagePath] = parentPath ? \`\${parentPath}/\${resolution.locator.name}\` : resolution.locator.name; } else { + module[pnpPackageLocator] = parentLocator; module[pnpPackagePath] = parentPath; } @@ -247,7 +276,7 @@ exports.setup = function setup () { }; if (module.parent && module.parent.id === 'internal/preload') { - exports.setup(); + exports.setup(process.env.YARN_PNP_PATH ? process.env.YARN_PNP_PATH.split(/\\//g) : []); } `.replace(/^\n/, ``); /* eslint-enable */ diff --git a/src/util/portable-script.js b/src/util/portable-script.js index 4a38fd72cf..3562489f56 100644 --- a/src/util/portable-script.js +++ b/src/util/portable-script.js @@ -9,6 +9,7 @@ export type PortableProxyOptions = {| extraEnvironment?: Map, prependArguments?: Array, appendArguments?: Array, + pnpPackageName?: string, |}; async function makePortableProxyScriptUnix( @@ -17,17 +18,27 @@ async function makePortableProxyScriptUnix( options: PortableProxyOptions, ): Promise { const environment = options.extraEnvironment - ? Array.from(options.extraEnvironment.entries()).map(([key, value]) => `${key}="${value}"`).join(' ') + ? Array.from(options.extraEnvironment.entries()).map(([key, value]) => `${key}="${value}"`).join(' ') + ' ' : ''; - const prependedArguments = options.prependArguments ? options.prependArguments.map(arg => `"${arg}"`).join(' ') : ''; - const appendedArguments = options.appendArguments ? options.appendArguments.map(arg => `"${arg}"`).join(' ') : ''; + const prependedArguments = options.prependArguments + ? ' ' + options.prependArguments.map(arg => `"${arg}"`).join(' ') + : ''; + const appendedArguments = options.appendArguments + ? ' ' + options.appendArguments.map(arg => `"${arg}"`).join(' ') + : ''; + + const pnpPathBuilder = options.pnpPackageName + ? // eslint-disable-next-line max-len + `if [[ -z $YARN_PNP_PATH ]]; then\n export YARN_PNP_PATH="${options.pnpPackageName}"\nelse\n export YARN_PNP_PATH="$YARN_PNP_PATH/${options.pnpPackageName}"\nfi\n\n` + : ''; const filePath = `${destination}/${options.proxyBasename || path.basename(source)}`; + await fs.mkdirp(destination); await fs.writeFile( filePath, - `#!/bin/sh\n${environment} "${source}" ${prependedArguments} "$@" ${appendedArguments}\n`, + `#!/bin/sh\n\n${pnpPathBuilder}${environment}"${source}"${prependedArguments} "$@"${appendedArguments}\n`, ); await fs.chmod(filePath, 0o755); } From fddf91c0e8cb8d4ba2301ba2310723e04f31788f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Fri, 9 Mar 2018 15:37:00 +0000 Subject: [PATCH 028/111] Moves the pnp embed api into its own file --- .babelrc | 1 + package.json | 1 + src/util/generate-pnp-map-api.tpl.js | 228 +++++++++++++++++++++++++++ src/util/generate-pnp-map.js | 225 +------------------------- yarn.lock | 22 +++ 5 files changed, 254 insertions(+), 223 deletions(-) create mode 100644 src/util/generate-pnp-map-api.tpl.js diff --git a/.babelrc b/.babelrc index 847d8cb88e..a71d9c170d 100644 --- a/.babelrc +++ b/.babelrc @@ -51,6 +51,7 @@ "stage-0" ], "plugins": [ + ["babel-plugin-inline-import", { "extensions": [ ".tpl.js" ] }], ["transform-inline-imports-commonjs"], ["transform-runtime", { "polyfill": false, "regenerator": true }] ] diff --git a/package.json b/package.json index d201d3f4d0..d728f25260 100644 --- a/package.json +++ b/package.json @@ -53,6 +53,7 @@ "babel-eslint": "^7.2.3", "babel-loader": "^6.2.5", "babel-plugin-array-includes": "^2.0.3", + "babel-plugin-inline-import": "^2.0.6", "babel-plugin-transform-inline-imports-commonjs": "^1.0.0", "babel-plugin-transform-runtime": "^6.4.3", "babel-preset-env": "^1.6.0", diff --git a/src/util/generate-pnp-map-api.tpl.js b/src/util/generate-pnp-map-api.tpl.js new file mode 100644 index 0000000000..b27549011f --- /dev/null +++ b/src/util/generate-pnp-map-api.tpl.js @@ -0,0 +1,228 @@ +/* eslint-disable max-len, flowtype/require-valid-file-annotation, flowtype/require-return-type */ +/* global packageInformationStores */ + +const Module = require('module'); + +const builtinModules = Module.builtinModules || Object.keys(process.binding('natives')); + +const originalLoader = Module._load; +const originalResolver = Module._resolveFilename; + +const pathRegExp = /^(?!\.{0,2}\/)([^\/]+)(\/.*|)$/; + +const topLevelLocator = {name: null, reference: null}; + +const pnpPackageLocator = Symbol('pnpPackageLocator'); +const pnpPackagePath = Symbol('pnpPackagePath'); + +const moduleCache = new Map(); + +exports.getPackageInformation = function getPackageInformation({name, reference}) { + const packageInformationStore = packageInformationStores.get(name); + + if (!packageInformationStore) { + return null; + } + + const packageInformation = packageInformationStore.get(reference); + + if (!packageInformation) { + return null; + } + + return packageInformation; +}; + +exports.resolveRequest = function resolveFilename(request, packageLocator, parentPath) { + if (builtinModules.indexOf(request) !== -1) { + return null; + } + + const dependencyNameMatch = request.match(pathRegExp); + + if (!dependencyNameMatch) { + return null; + } + + const [, dependencyName, subPath] = dependencyNameMatch; + + const packageInformation = exports.getPackageInformation(packageLocator); + + if (!packageInformation) { + throw new Error( + `Couldn't find a matching entry in the dependency tree for the specified parent (this is probably an internal error)`, + ); + } + + // We obtain the dependency reference in regard to the package that request it + // We also need to keep track of whether the dependency had to be loaded through a peerDependency entry + // This is because in this case, the cache key must reflect it + + let dependencyReference = packageInformation.packageDependencies.get(dependencyName); + let isPeerDependency = false; + + // If there's no strict dependency that match the request, we look into peer dependencies + + if (!dependencyReference && packageInformation.packagePeers) { + const peerResolutions = packageInformation.packagePeers.get(parentPath); + + if (!peerResolutions) { + throw new Error( + `Couldn't find the peer candidates for path "${parentPath}" (this is probably an internal error)`, + ); + } + + const peerReference = peerResolutions.get(dependencyName); + + if (peerReference === null) { + throw new Error( + `Package "${packageLocator.name}" tries to access a missing peer dependency ("${dependencyName}")`, + ); + } + + dependencyReference = peerReference; + isPeerDependency = true; + } + + // If we STILL can't find it, we fallback to the top-level dependencies + // This fallback isn't ideal, but makes working with plugins much easier + + if (!dependencyReference) { + const topLevelInformation = exports.getPackageInformation(topLevelLocator); + + dependencyReference = topLevelInformation.packageDependencies.get(dependencyName); + } + + // And if we still haven't been able to resolve it, we give up + // If the package making the request is the top-level, we can be a bit nicer in the error message + + if (!dependencyReference) { + if (packageLocator !== topLevelLocator) { + throw new Error( + `Package ${packageLocator.name}@${packageLocator.reference} is trying to require package ${dependencyName}, which is not declared in its dependencies (${Array.from( + packageInformation.packageDependencies.keys(), + ).join(`, `)})`, + ); + } else { + throw new Error(`You cannot require a package (${dependencyName}) that is not declared in your dependencies`); + } + } + + // We need to check that the package exists on the filesystem, because it might not have been installed + + const dependencyLocator = {name: dependencyName, reference: dependencyReference}; + const dependencyInformation = exports.getPackageInformation(dependencyLocator); + + const dependencyLocation = dependencyInformation.packageLocation; + + if (!dependencyLocation) { + throw new Error( + `Package ${dependencyName}@${dependencyReference} is a valid dependency, but hasn't been installed and thus cannot be required`, + ); + } + + const path = `${dependencyLocation}/${subPath}`; + const cacheKey = isPeerDependency ? `${parentPath}@${path}` : path; + + return {locator: dependencyLocator, path, cacheKey}; +}; + +exports.setup = function setup(initialParentPath) { + let initialParentLocator = topLevelLocator; + + for (let t = 0; t < initialParentPath.length; ++t) { + const dependencies = exports.getPackageInformation(initialParentLocator); + const currentPath = initialParentPath.slice(0, t).join('/'); + + const dependencyName = initialParentPath[t]; + let dependencyReference = dependencies.packageDependencies.get(dependencyName); + + if (!dependencyReference && dependencies.packagePeers) { + const peerResolutions = dependencies.packagePeers.get(currentPath); + + if (peerResolutions) { + dependencyReference = peerResolutions.get(dependencyName); + } + } + + if (!dependencyReference) { + if (initialParentLocator === topLevelLocator) { + throw new Error( + `Could not find package "${dependencyName} in the dependencies of your project (this is probably an internal error)`, + ); + } else { + throw new Error( + `Could not find package "${dependencyName} in the dependencies of "${currentPath}" (this is probably an internal error)`, + ); + } + } + + initialParentLocator = {name: dependencyName, reference: dependencyReference}; + } + + Module._load = function(request, parent, isMain) { + if (builtinModules.indexOf(request) !== -1) { + return originalLoader.call(this, request, parent, isMain); + } + + const parentLocator = parent && parent[pnpPackageLocator] ? parent[pnpPackageLocator] : initialParentLocator; + const parentPath = parent && parent[pnpPackagePath] ? parent[pnpPackagePath] : initialParentPath; + + const resolution = exports.resolveRequest(request, parentLocator, parentPath); + const qualifiedPath = originalResolver.call(this, resolution ? resolution.path : request, parent, isMain); + + const cacheKey = resolution ? resolution.cacheKey : qualifiedPath; + const cacheEntry = moduleCache.get(cacheKey); + + if (cacheEntry) { + return cacheEntry.exports; + } + + const module = new Module(qualifiedPath, parent); + moduleCache.set(cacheKey, module); + + if (isMain) { + process.mainModule = module; + module.id = '.'; + } + + if (resolution) { + module[pnpPackageLocator] = resolution.locator; + module[pnpPackagePath] = parentPath ? `${parentPath}/${resolution.locator.name}` : resolution.locator.name; + } else { + module[pnpPackageLocator] = parentLocator; + module[pnpPackagePath] = parentPath; + } + + let hasThrown = true; + + try { + module.load(qualifiedPath); + hasThrown = false; + } finally { + if (hasThrown) { + moduleCache.delete(cacheKey); + } + } + + return module.exports; + }; + + Module._resolveFilename = function(request, parent, isMain, options) { + if (builtinModules.indexOf(request) !== -1) { + return request; + } + + const parentLocator = parent && parent[pnpPackageLocator] ? parent[pnpPackageLocator] : topLevelLocator; + const parentPath = parent && parent[pnpPackagePath] ? parent[pnpPackagePath] : ''; + + const resolution = exports.resolveRequest(request, parentLocator, parentPath); + const qualifiedPath = originalResolver.call(this, resolution ? resolution.path : request, parent, isMain); + + return qualifiedPath; + }; +}; + +if (module.parent && module.parent.id === 'internal/preload') { + exports.setup(process.env.YARN_PNP_PATH ? process.env.YARN_PNP_PATH.split(/\//g) : []); +} diff --git a/src/util/generate-pnp-map.js b/src/util/generate-pnp-map.js index e358c1e3c4..af69ae5190 100644 --- a/src/util/generate-pnp-map.js +++ b/src/util/generate-pnp-map.js @@ -3,6 +3,7 @@ import type Config from '../config.js'; import type PackageRequest from '../package-request.js'; import type PackageResolver from '../package-resolver.js'; +import pnpApi from './generate-pnp-map-api.tpl.js'; import type {Manifest} from '../types.js'; import * as fs from './fs.js'; @@ -59,228 +60,6 @@ function generateMaps(packageInformationStores: PackageInformationStores): strin return code; } -/* eslint-disable max-len */ -const PROLOGUE = ` -const path = require('path'); - -const topLevelLocator = {name: null, reference: null}; - -`.replace(/^\n/, ``); -/* eslint-enable max-len */ - -/* eslint-disable max-len */ -const REQUIRE_HOOK = lockfileFolder => - ` -const Module = require('module'); - -const builtinModules = Module.builtinModules || Object.keys(process.binding('natives')); - -const originalLoader = Module._load; -const originalResolver = Module._resolveFilename; - -const pathRegExp = /^(?!\\.{0,2}\\/)([^\\/]+)(\\/.*|)$/; - -const pnpPackageLocator = Symbol('pnpPackageLocator'); -const pnpPackagePath = Symbol('pnpPackagePath'); - -const moduleCache = new Map(); - -exports.getPackageInformation = function getPackageInformation({name, reference}) { - const packageInformationStore = packageInformationStores.get(name); - - if (!packageInformationStore) { - return null; - } - - const packageInformation = packageInformationStore.get(reference); - - if (!packageInformation) { - return null; - } - - return packageInformation; -}; - -exports.resolveRequest = function resolveFilename(request, packageLocator, parentPath) { - if (builtinModules.indexOf(request) !== -1) { - return null; - } - - const dependencyNameMatch = request.match(pathRegExp); - - if (!dependencyNameMatch) { - return null; - } - - const [ , dependencyName, subPath ] = dependencyNameMatch; - - const packageInformation = exports.getPackageInformation(packageLocator); - - if (!packageInformation) { - throw new Error(\`Couldn't find a matching entry in the dependency tree for the specified parent (this is probably an internal error)\`); - } - - // We obtain the dependency reference in regard to the package that request it - // We also need to keep track of whether the dependency had to be loaded through a peerDependency entry - // This is because in this case, the cache key must reflect it - - let dependencyReference = packageInformation.packageDependencies.get(dependencyName); - let isPeerDependency = false; - - // If there's no strict dependency that match the request, we look into peer dependencies - - if (!dependencyReference && packageInformation.packagePeers) { - const peerResolutions = packageInformation.packagePeers.get(parentPath); - - if (!peerResolutions) { - throw new Error(\`Couldn't find the peer candidates for path "\${parentPath}" (this is probably an internal error)\`); - } - - const peerReference = peerResolutions.get(dependencyName); - - if (peerReference === null) { - throw new Error(\`Package "\${packageLocator.name}" tries to access a missing peer dependency ("\${dependencyName}")\`); - } - - dependencyReference = peerReference; - isPeerDependency = true; - } - - // If we STILL can't find it, we fallback to the top-level dependencies - // This fallback isn't ideal, but makes working with plugins much easier - - if (!dependencyReference) { - const topLevelInformation = exports.getPackageInformation(topLevelLocator); - - dependencyReference = topLevelInformation.packageDependencies.get(dependencyName); - } - - // And if we still haven't been able to resolve it, we give up - // If the package making the request is the top-level, we can be a bit nicer in the error message - - if (!dependencyReference) { - if (packageLocator !== topLevelLocator) { - throw new Error(\`Package \${packageLocator.name}@\${packageLocator.reference} is trying to require package \${dependencyName}, which is not declared in its dependencies (\${Array.from(packageInformation.packageDependencies.keys()).join(\`, \`)})\`); - } else { - throw new Error(\`You cannot require a package (\${dependencyName}) that is not declared in your dependencies\`); - } - } - - // We need to check that the package exists on the filesystem, because it might not have been installed - - const dependencyLocator = {name: dependencyName, reference: dependencyReference}; - const dependencyInformation = exports.getPackageInformation(dependencyLocator); - - const dependencyLocation = dependencyInformation.packageLocation; - - if (!dependencyLocation) { - throw new Error(\`Package \${dependencyName}@\${dependencyReference} is a valid dependency, but hasn't been installed and thus cannot be required\`); - } - - const path = \`\${dependencyLocation}/\${subPath}\`; - const cacheKey = isPeerDependency ? \`\${parentPath}@\${path}\` : path; - - return {locator: dependencyLocator, path, cacheKey}; -} - -exports.setup = function setup (initialParentPath) { - let initialParentLocator = topLevelLocator; - - for (let t = 0; t < initialParentPath.length; ++t) { - const dependencies = exports.getPackageInformation(initialParentLocator); - const currentPath = initialParentPath.slice(0, t).join('/'); - - const dependencyName = initialParentPath[t]; - let dependencyReference = dependencies.packageDependencies.get(dependencyName); - - if (!dependencyReference && dependencies.packagePeers) { - const peerResolutions = dependencies.packagePeers.get(currentPath); - - if (peerResolutions) { - dependencyReference = peerResolutions.get(dependencyName); - } - } - - if (!dependencyReference) { - if (initialParentLocator === topLevelLocator) { - throw new Error(\`Could not find package "\${dependencyName} in the dependencies of your project (this is probably an internal error)\`); - } else { - throw new Error(\`Could not find package "\${dependencyName} in the dependencies of "\${currentPath}" (this is probably an internal error)\`); - } - } - - initialParentLocator = {name: dependencyName, reference: dependencyReference}; - } - - Module._load = function (request, parent, isMain) { - if (builtinModules.indexOf(request) !== -1) { - return originalLoader.call(this, request, parent, isMain); - } - - const parentLocator = parent && parent[pnpPackageLocator] ? parent[pnpPackageLocator] : initialParentLocator; - const parentPath = parent && parent[pnpPackagePath] ? parent[pnpPackagePath] : initialParentPath; - - const resolution = exports.resolveRequest(request, parentLocator, parentPath); - const qualifiedPath = originalResolver.call(this, resolution ? resolution.path : request, parent, isMain); - - const cacheKey = resolution ? resolution.cacheKey : qualifiedPath; - const cacheEntry = moduleCache.get(cacheKey); - - if (cacheEntry) { - return cacheEntry.exports; - } - - const module = new Module(qualifiedPath, parent); - moduleCache.set(cacheKey, module); - - if (isMain) { - process.mainModule = module; - module.id = '.'; - } - - if (resolution) { - module[pnpPackageLocator] = resolution.locator; - module[pnpPackagePath] = parentPath ? \`\${parentPath}/\${resolution.locator.name}\` : resolution.locator.name; - } else { - module[pnpPackageLocator] = parentLocator; - module[pnpPackagePath] = parentPath; - } - - let hasThrown = true; - - try { - module.load(qualifiedPath); - hasThrown = false; - } finally { - if (hasThrown) { - moduleCache.delete(cacheKey); - } - } - - return module.exports; - }; - - Module._resolveFilename = function (request, parent, isMain, options) { - if (builtinModules.indexOf(request) !== -1) { - return request; - } - - const parentLocator = parent && parent[pnpPackageLocator] ? parent[pnpPackageLocator] : topLevelLocator; - const parentPath = parent && parent[pnpPackagePath] ? parent[pnpPackagePath] : ''; - - const resolution = exports.resolveRequest(request, parentLocator, parentPath); - const qualifiedPath = originalResolver.call(this, resolution ? resolution.path : request, parent, isMain); - - return qualifiedPath; - }; -}; - -if (module.parent && module.parent.id === 'internal/preload') { - exports.setup(process.env.YARN_PNP_PATH ? process.env.YARN_PNP_PATH.split(/\\//g) : []); -} -`.replace(/^\n/, ``); -/* eslint-enable */ - function getPackagesDistance(fromReq: PackageRequest, toReq: PackageRequest): number | null { // toReq cannot be a valid peer dependency if it's deeper in the tree if (toReq.parentNames.length > fromReq.parentNames.length) { @@ -446,5 +225,5 @@ export async function generatePnpMap( ): Promise { const packageInformationStores = await getPackageInformationStores(config, seedPatterns, {resolver}); - return [PROLOGUE, generateMaps(packageInformationStores), REQUIRE_HOOK(config.lockfileFolder)].join(`\n`); + return generateMaps(packageInformationStores) + pnpApi; } diff --git a/yarn.lock b/yarn.lock index 73ae9fddc2..ecc64f7f39 100644 --- a/yarn.lock +++ b/yarn.lock @@ -549,6 +549,12 @@ babel-plugin-check-es2015-constants@^6.22.0: dependencies: babel-runtime "^6.22.0" +babel-plugin-inline-import@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/babel-plugin-inline-import/-/babel-plugin-inline-import-2.0.6.tgz#8a3c179561b503bf4af319f3cad435e6b7b2863c" + dependencies: + require-resolve "0.0.2" + babel-plugin-istanbul@^4.0.0: version "4.1.5" resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-4.1.5.tgz#6760cdd977f411d3e175bb064f2bc327d99b2b6e" @@ -4812,6 +4818,10 @@ path-exists@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" +path-extra@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/path-extra/-/path-extra-1.0.3.tgz#7c112189a6e50d595790e7ad2037e44e410c1166" + path-is-absolute@^1.0.0, path-is-absolute@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" @@ -5273,6 +5283,12 @@ require-main-filename@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" +require-resolve@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/require-resolve/-/require-resolve-0.0.2.tgz#bab410ab1aee2f3f55b79317451dd3428764e6f3" + dependencies: + x-path "^0.0.2" + require-uncached@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" @@ -6340,6 +6356,12 @@ write@^0.2.1: dependencies: mkdirp "^0.5.1" +x-path@^0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/x-path/-/x-path-0.0.2.tgz#294d076bb97a7706cc070bbb2a6fd8c54df67b12" + dependencies: + path-extra "^1.0.2" + xml-name-validator@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-2.0.1.tgz#4d8b8f1eccd3419aa362061becef515e1e559635" From 2ef5f05d6731deced4779c29d8be9adc76903006 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Sun, 11 Mar 2018 01:28:50 +0000 Subject: [PATCH 029/111] Adds the test folder to Jest error messages Branch: jest-better-message --- .../pkg-tests-core/sources/utils/tests.js | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/packages/pkg-tests/pkg-tests-core/sources/utils/tests.js b/packages/pkg-tests/pkg-tests-core/sources/utils/tests.js index eaaa25b071..a1662eabe5 100644 --- a/packages/pkg-tests/pkg-tests-core/sources/utils/tests.js +++ b/packages/pkg-tests/pkg-tests-core/sources/utils/tests.js @@ -319,11 +319,16 @@ exports.generatePkgDriver = function generatePkgDriver({runDriver}: {|runDriver: return JSON.parse((await run('node', '-p', `JSON.stringify(${script})`)).stdout.toString()); }; - await fn({ - path, - run, - source, - }); + try { + await fn({ + path, + run, + source, + }); + } catch (error) { + error.message = `Temporary fixture folder: ${path}\n\n` + error.message; + throw error; + } }; }; From e8a27c7e02b428929e1ac790dffa89df1a3a72af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Sun, 11 Mar 2018 01:29:41 +0000 Subject: [PATCH 030/111] Improves peer dependency tests Branch: peer-deps-tests --- .../provides-peer-deps-1-0-0-1.0.0/index.js | 10 +++ .../package.json | 8 +++ .../provides-peer-deps-2-0-0-1.0.0/index.js | 10 +++ .../package.json | 8 +++ .../pkg-tests-specs/sources/basic.js | 34 +++++------ .../pkg-tests/pkg-tests-specs/sources/pnp.js | 61 +++++++++++++++++++ 6 files changed, 111 insertions(+), 20 deletions(-) create mode 100644 packages/pkg-tests/pkg-tests-fixtures/packages/provides-peer-deps-1-0-0-1.0.0/index.js create mode 100644 packages/pkg-tests/pkg-tests-fixtures/packages/provides-peer-deps-1-0-0-1.0.0/package.json create mode 100644 packages/pkg-tests/pkg-tests-fixtures/packages/provides-peer-deps-2-0-0-1.0.0/index.js create mode 100644 packages/pkg-tests/pkg-tests-fixtures/packages/provides-peer-deps-2-0-0-1.0.0/package.json diff --git a/packages/pkg-tests/pkg-tests-fixtures/packages/provides-peer-deps-1-0-0-1.0.0/index.js b/packages/pkg-tests/pkg-tests-fixtures/packages/provides-peer-deps-1-0-0-1.0.0/index.js new file mode 100644 index 0000000000..a6bf8f5865 --- /dev/null +++ b/packages/pkg-tests/pkg-tests-fixtures/packages/provides-peer-deps-1-0-0-1.0.0/index.js @@ -0,0 +1,10 @@ +/* @flow */ + +module.exports = require(`./package.json`); + +for (const key of [`dependencies`, `devDependencies`, `peerDependencies`]) { + for (const dep of Object.keys(module.exports[key] || {})) { + // $FlowFixMe The whole point of this file is to be dynamic + module.exports[key][dep] = require(dep); + } +} diff --git a/packages/pkg-tests/pkg-tests-fixtures/packages/provides-peer-deps-1-0-0-1.0.0/package.json b/packages/pkg-tests/pkg-tests-fixtures/packages/provides-peer-deps-1-0-0-1.0.0/package.json new file mode 100644 index 0000000000..dad66deee3 --- /dev/null +++ b/packages/pkg-tests/pkg-tests-fixtures/packages/provides-peer-deps-1-0-0-1.0.0/package.json @@ -0,0 +1,8 @@ +{ + "name": "provides-peer-deps-1-0-0", + "version": "1.0.0", + "dependencies": { + "peer-deps": "1.0.0", + "no-deps": "1.0.0" + } +} diff --git a/packages/pkg-tests/pkg-tests-fixtures/packages/provides-peer-deps-2-0-0-1.0.0/index.js b/packages/pkg-tests/pkg-tests-fixtures/packages/provides-peer-deps-2-0-0-1.0.0/index.js new file mode 100644 index 0000000000..a6bf8f5865 --- /dev/null +++ b/packages/pkg-tests/pkg-tests-fixtures/packages/provides-peer-deps-2-0-0-1.0.0/index.js @@ -0,0 +1,10 @@ +/* @flow */ + +module.exports = require(`./package.json`); + +for (const key of [`dependencies`, `devDependencies`, `peerDependencies`]) { + for (const dep of Object.keys(module.exports[key] || {})) { + // $FlowFixMe The whole point of this file is to be dynamic + module.exports[key][dep] = require(dep); + } +} diff --git a/packages/pkg-tests/pkg-tests-fixtures/packages/provides-peer-deps-2-0-0-1.0.0/package.json b/packages/pkg-tests/pkg-tests-fixtures/packages/provides-peer-deps-2-0-0-1.0.0/package.json new file mode 100644 index 0000000000..194a121d1a --- /dev/null +++ b/packages/pkg-tests/pkg-tests-fixtures/packages/provides-peer-deps-2-0-0-1.0.0/package.json @@ -0,0 +1,8 @@ +{ + "name": "provides-peer-deps-2-0-0", + "version": "1.0.0", + "dependencies": { + "peer-deps": "1.0.0", + "no-deps": "2.0.0" + } +} diff --git a/packages/pkg-tests/pkg-tests-specs/sources/basic.js b/packages/pkg-tests/pkg-tests-specs/sources/basic.js index 6479ea54b8..d8b8da3d6f 100644 --- a/packages/pkg-tests/pkg-tests-specs/sources/basic.js +++ b/packages/pkg-tests/pkg-tests-specs/sources/basic.js @@ -255,31 +255,25 @@ module.exports = (makeTemporaryEnv: PackageDriver) => { `it should install in such a way that peer dependencies can be resolved (from within a dependency)`, makeTemporaryEnv( { - dependencies: {[`custom-dep`]: `file:./custom-dep`}, + dependencies: {[`provides-peer-deps-1-0-0`]: `1.0.0`}, }, async ({path, run, source}) => { - await writeJson(`${path}/custom-dep/package.json`, { - name: `custom-dep`, - version: `1.0.0`, - dependencies: { - [`peer-deps`]: `1.0.0`, - [`no-deps`]: `1.0.0`, - }, - }); - - await writeFile( - `${path}/custom-dep/index.js`, - ` - module.exports = require('peer-deps'); - `, - ); - await run(`install`); - await expect(source(`require('custom-dep')`)).resolves.toMatchObject({ - name: `peer-deps`, + await expect(source(`require('provides-peer-deps-1-0-0')`)).resolves.toMatchObject({ + name: `provides-peer-deps-1-0-0`, version: `1.0.0`, - peerDependencies: { + dependencies: { + [`peer-deps`]: { + name: `peer-deps`, + version: `1.0.0`, + peerDependencies: { + [`no-deps`]: { + name: `no-deps`, + version: `1.0.0`, + }, + }, + }, [`no-deps`]: { name: `no-deps`, version: `1.0.0`, diff --git a/packages/pkg-tests/pkg-tests-specs/sources/pnp.js b/packages/pkg-tests/pkg-tests-specs/sources/pnp.js index 1a7cde5a47..5ebc652bd8 100644 --- a/packages/pkg-tests/pkg-tests-specs/sources/pnp.js +++ b/packages/pkg-tests/pkg-tests-specs/sources/pnp.js @@ -194,5 +194,66 @@ module.exports = makeTemporaryEnv => { }, ), ); + + test( + `it should install in such a way that two identical packages with different peer dependencies are different instances`, + makeTemporaryEnv( + { + dependencies: {[`provides-peer-deps-1-0-0`]: `1.0.0`, [`provides-peer-deps-2-0-0`]: `1.0.0`}, + }, + { + plugNPlay: true, + }, + async ({path, run, source}) => { + await run(`install`); + + await expect( + source(`require('provides-peer-deps-1-0-0') !== require('provides-peer-deps-2-0-0')`), + ).resolves.toEqual(true); + + await expect(source(`require('provides-peer-deps-1-0-0')`)).resolves.toMatchObject({ + name: `provides-peer-deps-1-0-0`, + version: `1.0.0`, + dependencies: { + [`peer-deps`]: { + name: `peer-deps`, + version: `1.0.0`, + peerDependencies: { + [`no-deps`]: { + name: `no-deps`, + version: `1.0.0`, + }, + }, + }, + [`no-deps`]: { + name: `no-deps`, + version: `1.0.0`, + }, + }, + }); + + await expect(source(`require('provides-peer-deps-2-0-0')`)).resolves.toMatchObject({ + name: `provides-peer-deps-2-0-0`, + version: `1.0.0`, + dependencies: { + [`peer-deps`]: { + name: `peer-deps`, + version: `1.0.0`, + peerDependencies: { + [`no-deps`]: { + name: `no-deps`, + version: `2.0.0`, + }, + }, + }, + [`no-deps`]: { + name: `no-deps`, + version: `2.0.0`, + }, + }, + }); + }, + ), + ); }); }; From 062e9f89306638923bd3c70dd376e92c968d91b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Mon, 12 Mar 2018 11:04:47 +0000 Subject: [PATCH 031/111] Adds tests for require.resolve Branch: require-resolve-tests --- .../pkg-tests/pkg-tests-specs/sources/pnp.js | 75 ++++++++++++++++++- 1 file changed, 74 insertions(+), 1 deletion(-) diff --git a/packages/pkg-tests/pkg-tests-specs/sources/pnp.js b/packages/pkg-tests/pkg-tests-specs/sources/pnp.js index 5ebc652bd8..a213bb9fb2 100644 --- a/packages/pkg-tests/pkg-tests-specs/sources/pnp.js +++ b/packages/pkg-tests/pkg-tests-specs/sources/pnp.js @@ -1,4 +1,4 @@ -const {fs: {writeFile}, tests: {getPackageDirectoryPath}} = require('pkg-tests-core'); +const {fs: {writeFile, writeJson}, tests: {getPackageDirectoryPath}} = require('pkg-tests-core'); module.exports = makeTemporaryEnv => { const {basic: basicSpecs, script: scriptSpecs} = require('pkg-tests-specs'); @@ -255,5 +255,78 @@ module.exports = makeTemporaryEnv => { }, ), ); + + test( + `it should support the use case of using the result of require.resolve(...) to load a package`, + makeTemporaryEnv( + { + dependencies: {[`custom-dep-a`]: `file:./custom-dep-a`}, + }, + { + plugNPlay: true, + }, + async ({path, run, source}) => { + await writeFile( + `${path}/custom-dep-a/index.js`, + `module.exports = require('custom-dep-b')(require.resolve('no-deps'))`, + ); + await writeJson(`${path}/custom-dep-a/package.json`, { + name: `custom-dep-a`, + version: `1.0.0`, + dependencies: {[`custom-dep-b`]: `file:../custom-dep-b`, [`no-deps`]: `1.0.0`}, + }); + + await writeFile(`${path}/custom-dep-b/index.js`, `module.exports = path => require(path)`); + await writeJson(`${path}/custom-dep-b/package.json`, {name: `custom-dep-b`, version: `1.0.0`}); + + await run(`install`); + + await expect(source(`require('custom-dep-a')`)).resolves.toMatchObject({ + name: `no-deps`, + version: `1.0.0`, + }); + }, + ), + ); + + test( + `it should not break the tree path when loading through the result of require.resolve(...)`, + makeTemporaryEnv( + { + dependencies: {[`custom-dep-a`]: `file:./custom-dep-a`}, + }, + { + plugNPlay: true, + }, + async ({path, run, source}) => { + await writeFile( + `${path}/custom-dep-a/index.js`, + `module.exports = require('custom-dep-b')(require.resolve('custom-dep-c'))`, + ); + await writeJson(`${path}/custom-dep-a/package.json`, { + name: `custom-dep-a`, + version: `1.0.0`, + dependencies: {[`custom-dep-b`]: `file:../custom-dep-b`, [`custom-dep-c`]: `file:../custom-dep-c`}, + }); + + await writeFile(`${path}/custom-dep-b/index.js`, `module.exports = path => require(path)`); + await writeJson(`${path}/custom-dep-b/package.json`, {name: `custom-dep-b`, version: `1.0.0`}); + + await writeFile(`${path}/custom-dep-c/index.js`, `module.exports = require('no-deps')`); + await writeJson(`${path}/custom-dep-c/package.json`, { + name: `custom-dep-c`, + version: `1.0.0`, + dependencies: {[`no-deps`]: `1.0.0`}, + }); + + await run(`install`); + + await expect(source(`require('custom-dep-a')`)).resolves.toMatchObject({ + name: `no-deps`, + version: `1.0.0`, + }); + }, + ), + ); }); }; From 0728eba1872b2ab8638c47a5c9e39ec49680614d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Mon, 12 Mar 2018 11:06:00 +0000 Subject: [PATCH 032/111] Refactors the pnp file Branch: pnp-file-refactoring --- src/constants.js | 2 + src/util/generate-pnp-map-api.tpl.js | 547 +++++++++++++++++++++------ src/util/generate-pnp-map.js | 33 +- 3 files changed, 468 insertions(+), 114 deletions(-) diff --git a/src/constants.js b/src/constants.js index c56cd727de..e0c36c8c76 100644 --- a/src/constants.js +++ b/src/constants.js @@ -11,6 +11,8 @@ type Env = { }; export const DEPENDENCY_TYPES = ['devDependencies', 'dependencies', 'optionalDependencies', 'peerDependencies']; +export const OWNED_DEPENDENCY_TYPES = ['devDependencies', 'dependencies', 'optionalDependencies']; + export const RESOLUTIONS = 'resolutions'; export const MANIFEST_FIELDS = [RESOLUTIONS, ...DEPENDENCY_TYPES]; diff --git a/src/util/generate-pnp-map-api.tpl.js b/src/util/generate-pnp-map-api.tpl.js index b27549011f..91857c41d9 100644 --- a/src/util/generate-pnp-map-api.tpl.js +++ b/src/util/generate-pnp-map-api.tpl.js @@ -1,207 +1,466 @@ /* eslint-disable max-len, flowtype/require-valid-file-annotation, flowtype/require-return-type */ /* global packageInformationStores */ +const fs = require('fs'); const Module = require('module'); +const path = require('path'); const builtinModules = Module.builtinModules || Object.keys(process.binding('natives')); const originalLoader = Module._load; const originalResolver = Module._resolveFilename; +const originalReadFile = fs.readFile; -const pathRegExp = /^(?!\.{0,2}\/)([^\/]+)(\/.*|)$/; +const pathRegExp = /^(?!\.{0,2}(?:\/|$))((?:@[^\/]+\/)?[^\/]+)\/?(.*|)$/; const topLevelLocator = {name: null, reference: null}; +const topLevelResolution = {locator: topLevelLocator, treePath: ``, filesystemDirectory: "/Users/mael/yarn-pnp"}; -const pnpPackageLocator = Symbol('pnpPackageLocator'); -const pnpPackagePath = Symbol('pnpPackagePath'); +const pnpResolutionSymbol = Symbol('pnpResolution'); +const moduleShims = new Map(); const moduleCache = new Map(); -exports.getPackageInformation = function getPackageInformation({name, reference}) { - const packageInformationStore = packageInformationStores.get(name); +const pnpPathMagic = `/.//.//.//`; - if (!packageInformationStore) { - return null; - } +/** + * Returns information about a package in a safe way (will throw if they cannot be retrieved) + */ - const packageInformation = packageInformationStore.get(reference); +function getPackageInformationSafe(packageLocator) { + const packageInformation = exports.getPackageInformation(packageLocator); if (!packageInformation) { - return null; + throw new Error( + `Couldn't find a matching entry in the dependency tree for the specified parent (this is probably an internal error)`, + ); } return packageInformation; -}; +} -exports.resolveRequest = function resolveFilename(request, packageLocator, parentPath) { - if (builtinModules.indexOf(request) !== -1) { - return null; +/** + * Returns the peer dependency resolutions about a package in a given location in the dependency tree in a safe way + * (will throw if they cannot be retrieved). + */ + +function getPeerReferencesSafe(packageInformation, parentTreePath) { + const peerReferences = packageInformation.packagePeers.get(parentTreePath); + + if (!peerReferences) { + throw new Error( + `Couldn't find the peer candidates for package located at "${parentTreePath}" in the dependency tree (this is probably an internal error)`, + ); } - const dependencyNameMatch = request.match(pathRegExp); + return peerReferences; +} - if (!dependencyNameMatch) { - return null; +/** + * Given a tree path (pkg-a/sub-pkg-b/foobar), returns the associated locator (foobar@1.0.0) + */ + +function getLocatorFromTreePath(treePath) { + const parts = treePath ? treePath.split(/\//g) : []; + let currentLocator = topLevelLocator; + + for (let t = 0; t < parts.length; ++t) { + const dependencies = exports.getPackageInformation(currentLocator); + const currentTreePath = parts.slice(0, t).join('/'); + + const dependencyName = parts[t]; + let dependencyReference = dependencies.packageDependencies.get(dependencyName); + + if (!dependencyReference && dependencies.packagePeers) { + const peerReferences = dependencies.packagePeers.get(currentTreePath); + + if (peerReferences) { + dependencyReference = peerReferences.get(dependencyName); + } + } + + if (!dependencyReference) { + return null; + } + + currentLocator = {name: dependencyName, reference: dependencyReference}; } - const [, dependencyName, subPath] = dependencyNameMatch; + return currentLocator; +} + +/** + * Transforms the result of exports.resolveRequest into a single string. + */ - const packageInformation = exports.getPackageInformation(packageLocator); +function serializeResolution(resolution) { + let output = pnpPathMagic; - if (!packageInformation) { - throw new Error( - `Couldn't find a matching entry in the dependency tree for the specified parent (this is probably an internal error)`, - ); + writeShort(resolution.treePath.length); + + for (let t = 0; t < resolution.treePath.length; ++t) { + writeByte(resolution.treePath.charCodeAt(t)); } - // We obtain the dependency reference in regard to the package that request it - // We also need to keep track of whether the dependency had to be loaded through a peerDependency entry - // This is because in this case, the cache key must reflect it + return output + resolution.filesystemPath; - let dependencyReference = packageInformation.packageDependencies.get(dependencyName); - let isPeerDependency = false; + function writeShort(n) { + writeByte((n >>> 0) & 0xFF); + writeByte((n >>> 8) & 0xFF); + } - // If there's no strict dependency that match the request, we look into peer dependencies + function writeByte(n) { + output += n.toString(2).padStart(8, '0').replace(/0/g, `./`).replace(/1/g, `//`); + } +} - if (!dependencyReference && packageInformation.packagePeers) { - const peerResolutions = packageInformation.packagePeers.get(parentPath); +/** +*/ - if (!peerResolutions) { - throw new Error( - `Couldn't find the peer candidates for path "${parentPath}" (this is probably an internal error)`, - ); +function deserializeResolution(serializedResolution) { + let offset = pnpPathMagic.length; + + const size = readShort(); + const charCodes = []; + + for (let t = 0; t < size; ++t) { + charCodes.push(readByte()); + } + + const filesystemPath = serializedResolution.slice(offset); + const filesystemDirectory = path.dirname(filesystemPath); + const treePath = String.fromCharCode(... charCodes); + + const locator = getLocatorFromTreePath(treePath); + const cacheKey = getCacheKey(filesystemPath, locator, treePath); + + return {locator, treePath, filesystemPath, filesystemDirectory, cacheKey}; + + function readShort() { + return readByte() | (readByte() << 8); + } + + function readByte() { + const encodedByte = serializedResolution.slice(offset, offset += 2 * 8); + let decodedByte = 0; + + for (let t = 0; t < 2 * 8; t += 2) { + decodedByte *= 2; + decodedByte += encodedByte.slice(t, t + 2).includes(`.`) ? 0 : 1; } - const peerReference = peerResolutions.get(dependencyName); + return decodedByte; + } +} + +/** + * Computes the cache key for the given file of the given package. + * + * The cache key is the file path for most entries, but if their owning package has peer dependency then we need to + * bake the peer dependencies resolved references into the cache key (because we'll need to instanciate multiple + * versions of the same file, one for each set of dependencies). + */ - if (peerReference === null) { - throw new Error( - `Package "${packageLocator.name}" tries to access a missing peer dependency ("${dependencyName}")`, - ); +function getCacheKey(filesystemPath, packageLocator, treePath) { + let cacheKey = filesystemPath; + + const packageInformation = getPackageInformationSafe(packageLocator); + + if (packageInformation.packagePeers) { + const peerReferences = getPeerReferencesSafe(packageInformation, treePath); + + for (const [dependencyName, dependencyReference] of peerReferences.entries()) { + cacheKey += `@${dependencyName}@${dependencyReference}`; } + } + + return cacheKey; +} + +/** + */ + +function applyNodeExtensionResolution(filesystemPath) { + // If the file exists and is a file, we can stop right there + + let stat; - dependencyReference = peerReference; - isPeerDependency = true; + try { + stat = fs.statSync(filesystemPath); + } catch (error) {} + + if (stat && !stat.isDirectory()) { + return filesystemPath; } - // If we STILL can't find it, we fallback to the top-level dependencies - // This fallback isn't ideal, but makes working with plugins much easier + // Otherwise we check if we find a file that match one of the supported extensions + + const extensions = Object.keys(Module._extensions); - if (!dependencyReference) { - const topLevelInformation = exports.getPackageInformation(topLevelLocator); + const qualifiedFile = extensions.map(extension => { + return `${filesystemPath}${extension}`; + }).find(candidateFile => { + return fs.existsSync(candidateFile); + }); - dependencyReference = topLevelInformation.packageDependencies.get(dependencyName); + if (qualifiedFile) { + return qualifiedFile; } - // And if we still haven't been able to resolve it, we give up - // If the package making the request is the top-level, we can be a bit nicer in the error message + // Otherwise, we check if the path is a folder - in such a case, we try to use its index - if (!dependencyReference) { - if (packageLocator !== topLevelLocator) { - throw new Error( - `Package ${packageLocator.name}@${packageLocator.reference} is trying to require package ${dependencyName}, which is not declared in its dependencies (${Array.from( - packageInformation.packageDependencies.keys(), - ).join(`, `)})`, - ); - } else { - throw new Error(`You cannot require a package (${dependencyName}) that is not declared in your dependencies`); + if (stat && stat.isDirectory()) { + const indexFile = extensions.map(extension => { + return `${filesystemPath}/index${extension}`; + }).find(candidateFile => { + return fs.existsSync(candidateFile); + }); + + if (indexFile) { + return indexFile; } } - // We need to check that the package exists on the filesystem, because it might not have been installed + // Otherwise there's nothing else we can do :( - const dependencyLocator = {name: dependencyName, reference: dependencyReference}; - const dependencyInformation = exports.getPackageInformation(dependencyLocator); + return null; +} - const dependencyLocation = dependencyInformation.packageLocation; +/** + * Gets the package information for a given locator. Returns null if they cannot be retrieved. + */ - if (!dependencyLocation) { - throw new Error( - `Package ${dependencyName}@${dependencyReference} is a valid dependency, but hasn't been installed and thus cannot be required`, - ); +exports.getPackageInformation = function getPackageInformation({name, reference}) { + const packageInformationStore = packageInformationStores.get(name); + + if (!packageInformationStore) { + return null; } - const path = `${dependencyLocation}/${subPath}`; - const cacheKey = isPeerDependency ? `${parentPath}@${path}` : path; + const packageInformation = packageInformationStore.get(reference); + + if (!packageInformation) { + return null; + } - return {locator: dependencyLocator, path, cacheKey}; + return packageInformation; }; -exports.setup = function setup(initialParentPath) { - let initialParentLocator = topLevelLocator; +/** + * Transforms a request (what's typically passed as argument to the require function) into a location on the + * filesystem, amongst other data. + * + * It also returns the following information: + * + * - The owning package locator + * - The owning package path in the dependency tree + * - The file cache key + */ - for (let t = 0; t < initialParentPath.length; ++t) { - const dependencies = exports.getPackageInformation(initialParentLocator); - const currentPath = initialParentPath.slice(0, t).join('/'); +exports.resolveRequest = function resolveRequest(request, parentResolution) { + // console.error('requesting', request, 'from', parentResolution); - const dependencyName = initialParentPath[t]; - let dependencyReference = dependencies.packageDependencies.get(dependencyName); + // Bailout if the request is a native module - if (!dependencyReference && dependencies.packagePeers) { - const peerResolutions = dependencies.packagePeers.get(currentPath); + if (builtinModules.indexOf(request) !== -1) { + return null; + } + + // If the request is a serialized resolution, we just have to deserialize it + + if (request.startsWith(pnpPathMagic)) { + return deserializeResolution(request); + } + + let dependencyLocator; + + let treePath; + let filesystemPath; + + // If the request is a relative or absolute path, we just have to reuse the parent resolution, and resolve the + // request path relative to the parent resolution own path + + const dependencyNameMatch = request.match(pathRegExp); + + if (!dependencyNameMatch) { + dependencyLocator = parentResolution.locator; + + treePath = parentResolution.treePath; + filesystemPath = path.resolve(parentResolution.filesystemDirectory, request); + } - if (peerResolutions) { - dependencyReference = peerResolutions.get(dependencyName); + // Things are more hairy if it's a package require - we then need to figure out which package is needed, and in + // particular the exact version for the given location on the dependency tree + + if (dependencyNameMatch) { + const [, dependencyName, subPath] = dependencyNameMatch; + + const packageInformation = getPackageInformationSafe(parentResolution.locator); + + // We obtain the dependency reference in regard to the package that request it + + let dependencyReference = packageInformation.packageDependencies.get(dependencyName); + + // If there's no strict dependency that match the request, we look into peer dependencies + + if (!dependencyReference && packageInformation.packagePeers) { + const peerReferences = getPeerReferencesSafe(packageInformation, parentResolution.treePath); + const peerReference = peerReferences.get(dependencyName); + + if (peerReference === null) { + throw new Error( + `Package "${parentResolution.locator.name}" tries to access a missing peer dependency ("${dependencyName}")`, + ); } + + dependencyReference = peerReference; } + // If we STILL can't find it, we fallback to the top-level dependencies + // This fallback isn't ideal, but makes working with plugins much easier + if (!dependencyReference) { - if (initialParentLocator === topLevelLocator) { + const topLevelInformation = exports.getPackageInformation(topLevelLocator); + + dependencyReference = topLevelInformation.packageDependencies.get(dependencyName); + + if (dependencyReference) { + parentResolution = topLevelResolution; + } + } + + // And if we still haven't been able to resolve it, we give up + // If the package making the request is the top-level, we can offer a nicer error message + + if (dependencyReference) { + treePath = parentResolution.treePath ? `${parentResolution.treePath}/${dependencyName}` : dependencyName; + dependencyLocator = {name: dependencyName, reference: dependencyReference}; + } else { + if (parentResolution.locator !== topLevelLocator) { throw new Error( - `Could not find package "${dependencyName} in the dependencies of your project (this is probably an internal error)`, + `Package ${parentResolution.locator.name}@${parentResolution.locator.reference} is trying to require package ${dependencyName} through "${request}", which is not declared in its dependencies (${Array.from( + packageInformation.packageDependencies.keys(), + ).join(`, `)})`, ); } else { - throw new Error( - `Could not find package "${dependencyName} in the dependencies of "${currentPath}" (this is probably an internal error)`, - ); + throw new Error(`You cannot require a package (${dependencyName}) that is not declared in your dependencies`); } } - initialParentLocator = {name: dependencyName, reference: dependencyReference}; + // We need to check that the package exists on the filesystem, because it might not have been installed + + const dependencyInformation = exports.getPackageInformation(dependencyLocator); + const dependencyLocation = dependencyInformation.packageLocation; + + if (!dependencyLocation) { + throw new Error( + `Package ${dependencyLocator.name}@${dependencyLocator.reference} is a valid dependency, but hasn't been installed and thus cannot be required`, + ); + } + + // Now that we know which package we should resolve to, we only have to find out the file location + + if (subPath) { + filesystemPath = path.resolve(dependencyLocation, subPath); // slice(1) to strip the leading '/' + } else if (dependencyInformation.packageMainEntry) { + filesystemPath = path.resolve(dependencyLocation, dependencyInformation.packageMainEntry); + } else { + filesystemPath = dependencyLocation; + } + } + + // Try to resolve the filesystem according to the Node rules (directory -> index, optional .js extensions, etc) + + const qualifiedFilesystemPath = applyNodeExtensionResolution(filesystemPath); + + if (qualifiedFilesystemPath) { + filesystemPath = qualifiedFilesystemPath; + } else { + throw new Error(`Couldn't find a suitable resolution for path "${filesystemPath}" (initial request was "${request}")`); } + // Compute the remaining fields + + const locator = dependencyLocator; + const filesystemDirectory = path.dirname(filesystemPath); + const cacheKey = getCacheKey(filesystemPath, locator, treePath); + + const resolution = {locator, treePath, filesystemPath, filesystemDirectory, cacheKey}; + + // console.error('resolved to', resolution); + + return resolution; +}; + +/** + * Setups the hook into the Node environment + */ + +exports.setup = function setup(initialParentTreePath) { + const initialParentLocator = getLocatorFromTreePath(initialParentTreePath); + + if (!initialParentLocator) { + throw new Error( + `Could not find resolve the given entry point, "${initialParentTreePath}" (this is probably an internal error)`, + ); + } + + const initialResolution = { + locator: initialParentLocator, + treePath: initialParentTreePath, + filesystemDirectory: process.cwd(), + }; + Module._load = function(request, parent, isMain) { + // Builtins are managed by the regular Node loader + if (builtinModules.indexOf(request) !== -1) { return originalLoader.call(this, request, parent, isMain); } - const parentLocator = parent && parent[pnpPackageLocator] ? parent[pnpPackageLocator] : initialParentLocator; - const parentPath = parent && parent[pnpPackagePath] ? parent[pnpPackagePath] : initialParentPath; + // We allow to shim modules, which is useful for packages such as `resolve` - const resolution = exports.resolveRequest(request, parentLocator, parentPath); - const qualifiedPath = originalResolver.call(this, resolution ? resolution.path : request, parent, isMain); + const shim = moduleShims.get(request); - const cacheKey = resolution ? resolution.cacheKey : qualifiedPath; - const cacheEntry = moduleCache.get(cacheKey); + if (shim) { + return shim; + } + + const parentResolution = parent && parent[pnpResolutionSymbol] ? parent[pnpResolutionSymbol] : initialResolution; + const requestResolution = exports.resolveRequest(request, parentResolution); + + // Check if the module has already been created + + const cacheEntry = moduleCache.get(requestResolution.cacheKey); if (cacheEntry) { return cacheEntry.exports; } - const module = new Module(qualifiedPath, parent); - moduleCache.set(cacheKey, module); + // Create a new module and store it into the cache + + const module = new Module(requestResolution.filesystemPath, parent); + module[pnpResolutionSymbol] = requestResolution; + + moduleCache.set(requestResolution.cacheKey, module); + + // Main modules are exposed on the global instances if (isMain) { process.mainModule = module; module.id = '.'; } - if (resolution) { - module[pnpPackageLocator] = resolution.locator; - module[pnpPackagePath] = parentPath ? `${parentPath}/${resolution.locator.name}` : resolution.locator.name; - } else { - module[pnpPackageLocator] = parentLocator; - module[pnpPackagePath] = parentPath; - } + // Try to load the module, and remove it from the cache if it fails let hasThrown = true; try { - module.load(qualifiedPath); + module.load(requestResolution.filesystemPath); hasThrown = false; } finally { if (hasThrown) { - moduleCache.delete(cacheKey); + moduleCache.delete(requestResolution.cacheKey); } } @@ -213,16 +472,86 @@ exports.setup = function setup(initialParentPath) { return request; } - const parentLocator = parent && parent[pnpPackageLocator] ? parent[pnpPackageLocator] : topLevelLocator; - const parentPath = parent && parent[pnpPackagePath] ? parent[pnpPackagePath] : ''; + const parentResolution = parent && parent[pnpResolutionSymbol] ? parent[pnpResolutionSymbol] : initialResolution; + const resolution = exports.resolveRequest(request, parentResolution); + + return serializeResolution(resolution); + }; + + fs.readFile = (target, ... args) => { + return originalReadFile.call(fs, path.normalize(target), ... args); + }; +}; + +exports.setupCompatibilityLayer = () => { + // see https://github.com/browserify/resolve/blob/master/lib/caller.js + const getCaller = () => { + const origPrepareStackTrace = Error.prepareStackTrace; + + Error.prepareStackTrace = (_, stack) => stack; + const stack = new Error().stack; + Error.prepareStackTrace = origPrepareStackTrace; + + return stack[2].getFileName(); + }; + + const resolveSyncShim = (request, options = {}) => { + const basedir = options.basedir || path.dirname(getCaller()); + let parentResolution; + + if (basedir === LOCKFILE_FOLDER || basedir.startsWith(LOCKFILE_FOLDER + `/`)) { + parentResolution = topLevelResolution; + } else if (basedir.startsWith(pnpPathMagic)) { + parentResolution = deserializeResolution(basedir); + + // HACK: since basedir is traditionally a folder, the filesystemDirectory actually is filesystemPath! + // If we don't make this change, parentResolution.filesystemDirectory will be dirname(dirname(X)): the first one + // because the user did it themselves, and the second one because deserializeResolution thought that the string + // would contain something it returned in the past (which always is a file), so it would compute the directory by + // using dirname() on this path. + parentResolution.filesystemDirectory = parentResolution.filesystemPath; + } else { + throw new Error( + `This usage of the "resolve" module is not supported on Plug'n'Play environments (got "${options.basedir}" as basedir)`, + ); + } + + const resolution = exports.resolveRequest(request, parentResolution); + + if (resolution) { + return serializeResolution(resolution); + } else { + throw new Error(`Resolution failed for path "${request}"`); + } + }; + + const resolveShim = (request, options, callback) => { + if (typeof options === 'function') { + callback = options; + options = {}; + } + + // We need to compute it here because otherwise resolveSyncShim will read the wrong stacktrace entry + const basedir = options.basedir || path.dirname(getCaller()); - const resolution = exports.resolveRequest(request, parentLocator, parentPath); - const qualifiedPath = originalResolver.call(this, resolution ? resolution.path : request, parent, isMain); + setImmediate(() => { + let error; + let result; - return qualifiedPath; + try { + result = resolveShim.sync(request, Object.assign(options, {basedir})); + } catch (thrown) { + error = thrown; + } + + callback(error, result); + }); }; + + moduleShims.set('resolve', Object.assign(resolveShim, {sync: resolveSyncShim})); }; if (module.parent && module.parent.id === 'internal/preload') { - exports.setup(process.env.YARN_PNP_PATH ? process.env.YARN_PNP_PATH.split(/\//g) : []); + exports.setup(process.env.YARN_PNP_PATH || ''); + exports.setupCompatibilityLayer(); } diff --git a/src/util/generate-pnp-map.js b/src/util/generate-pnp-map.js index af69ae5190..d0e286ac42 100644 --- a/src/util/generate-pnp-map.js +++ b/src/util/generate-pnp-map.js @@ -4,6 +4,7 @@ import type Config from '../config.js'; import type PackageRequest from '../package-request.js'; import type PackageResolver from '../package-resolver.js'; import pnpApi from './generate-pnp-map-api.tpl.js'; +import * as constants from '../constants.js'; import type {Manifest} from '../types.js'; import * as fs from './fs.js'; @@ -27,10 +28,14 @@ function generateMaps(packageInformationStores: PackageInformationStores): strin for (const [packageName, packageInformationStore] of packageInformationStores) { code += ` [${JSON.stringify(packageName)}, new Map([\n`; - for (const [packageReference, {packageLocation, packageDependencies, packagePeers}] of packageInformationStore) { + for (const [packageReference, {packageMainEntry, packageLocation, packageDependencies, packagePeers}] of packageInformationStore) { code += ` [${JSON.stringify(packageReference)}, {\n`; code += ` packageLocation: ${JSON.stringify(packageLocation)},\n`; + if (packageMainEntry) { + code += ` packageMainEntry: ${JSON.stringify(packageMainEntry)},\n`; + } + code += ` packageDependencies: new Map([\n`; for (const [dependencyName, dependencyReference] of packageDependencies.entries()) { code += ` [${JSON.stringify(dependencyName)}, ${JSON.stringify(dependencyReference)}],\n`; @@ -79,7 +84,7 @@ function getPackagesDistance(fromReq: PackageRequest, toReq: PackageRequest): nu function getPackagePeers( pkg: Manifest, - {resolver, exclude}: {resolver: PackageResolver, exclude: Array}, + {resolver, exclude}: {resolver: PackageResolver, exclude: Set}, ): Map> { const ref = pkg._reference; invariant(ref, `Ref must exists`); @@ -170,20 +175,36 @@ async function getPackageInformationStores( packageInformationStores.set(pkg.name, (packageInformationStore = new Map())); } + // Get the dependency we directly own (vs those provided through peerDependencies) + + const ownedDependencies = new Set(); + + for (const dependencyType of constants.OWNED_DEPENDENCY_TYPES) { + if (pkg[dependencyType]) { + for (const dependencyName of Object.keys(pkg[dependencyType])) { + ownedDependencies.add(dependencyName); + } + } + } + // Resolve all the dependencies for our package const packageDependencies = new Map(); for (const pattern of ref.dependencies) { const dep = resolver.getStrictResolvedPattern(pattern); - packageDependencies.set(dep.name, dep.version); + if (ownedDependencies.has(dep.name)) { + packageDependencies.set(dep.name, dep.version); + } } // Compute the peer dependencies for each possible require path + // In case of conflict, we use the one from dependencies / devDependencies / optionalDependencies - const packagePeers = getPackagePeers(pkg, {resolver, exclude: Array.from(packageDependencies.keys())}); + const packagePeers = getPackagePeers(pkg, {resolver, exclude: ownedDependencies}); packageInformationStore.set(pkg.version, { + packageMainEntry: pkg.main, packageLocation: (await fs.realpath(loc)).replace(/[\\\/]?$/, path.sep), packageDependencies, packagePeers, @@ -225,5 +246,7 @@ export async function generatePnpMap( ): Promise { const packageInformationStores = await getPackageInformationStores(config, seedPatterns, {resolver}); - return generateMaps(packageInformationStores) + pnpApi; + return ( + generateMaps(packageInformationStores) + pnpApi.replace(/LOCKFILE_FOLDER/g, JSON.stringify(config.lockfileFolder)) + ); } From a5c3e03d997d6cd501e9bc4af3d0660d6ecfe34b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Mon, 12 Mar 2018 11:06:17 +0000 Subject: [PATCH 033/111] Updates the build-webpack script to include a custom resolver Branch: webpack-resolver --- scripts/build-webpack.js | 57 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 53 insertions(+), 4 deletions(-) diff --git a/scripts/build-webpack.js b/scripts/build-webpack.js index 8acad2ef4a..3377d5a018 100755 --- a/scripts/build-webpack.js +++ b/scripts/build-webpack.js @@ -3,6 +3,7 @@ const webpack = require('webpack'); const path = require('path'); +const resolve = require('resolve'); const util = require('util'); const fs = require('fs'); @@ -10,6 +11,52 @@ const version = require('../package.json').version; const basedir = path.join(__dirname, '../'); const babelRc = JSON.parse(fs.readFileSync(path.join(basedir, '.babelrc'), 'utf8')); +var PnpResolver = { + apply: function(resolver) { + resolver.plugin('resolve', function(request, callback) { + if (request.context.issuer === undefined) { + return callback(); + } + + let basedir; + let resolved; + + if (!request.context.issuer) { + basedir = request.path; + } else if (request.context.issuer.startsWith('/')) { + basedir = path.dirname(request.context.issuer); + } else { + throw 42; + } + + try { + resolved = resolve.sync(request.request, {basedir}); + } catch (error) { + // TODO This is not good! But the `debug` package tries to require `supports-color` without declaring it in its + // package.json, and Webpack accepts this because it's in a try/catch, so we need to do it as well. + resolved = false; + } + + this.doResolve(['resolved'], Object.assign({}, request, { + path: resolved, + }), '', callback); + }); + } +}; + +const pnpOptions = fs.existsSync(`${__dirname}/../.pnp.js`) ? { + resolve: { + plugins: [ + PnpResolver, + ] + }, + resolveLoader: { + plugins: [ + PnpResolver, + ] + } +} : {}; + // Use the real node __dirname and __filename in order to get Yarn's source // files on the user's system. See constants.js const nodeOptions = { @@ -31,8 +78,8 @@ const compiler = webpack({ loaders: [ { test: /\.js$/, - exclude: /node_modules/, - loader: 'babel-loader', + exclude: /node_modules|Caches/, + loader: require.resolve('babel-loader'), }, ], }, @@ -49,6 +96,7 @@ const compiler = webpack({ }, target: 'node', node: nodeOptions, + ... pnpOptions, }); compiler.run((err, stats) => { @@ -68,8 +116,8 @@ const compilerLegacy = webpack({ loaders: [ { test: /\.js$/, - exclude: /node_modules/, - loader: 'babel-loader', + exclude: /node_modules|Caches/, + loader: require.resolve('babel-loader'), query: babelRc.env['pre-node5'], }, ], @@ -87,6 +135,7 @@ const compilerLegacy = webpack({ }, target: 'node', node: nodeOptions, + ... pnpOptions, }); compilerLegacy.run((err, stats) => { From 41f000300914be83fcbee59dac8bf58eb305efaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Mon, 12 Mar 2018 12:08:29 +0000 Subject: [PATCH 034/111] Fixes tests Branch: fix-tests --- __tests__/commands/install/integration.js | 4 +- src/cli/commands/run.js | 10 +++- src/util/generate-pnp-map-api.tpl.js | 58 +++++++++++++---------- src/util/generate-pnp-map.js | 9 +++- src/util/portable-script.js | 2 +- 5 files changed, 51 insertions(+), 32 deletions(-) diff --git a/__tests__/commands/install/integration.js b/__tests__/commands/install/integration.js index e004f8cf1f..8f5092ee83 100644 --- a/__tests__/commands/install/integration.js +++ b/__tests__/commands/install/integration.js @@ -240,7 +240,7 @@ test('changes the cache path when bumping the cache version', async () => { const reporter = new reporters.JSONReporter({stdout: inOut}); await cache(config, reporter, {}, ['dir']); - expect((JSON.parse(String(inOut.read())): any).data).toMatch(/[\\\/]v1[\\\/]?$/); + expect((JSON.parse(String(inOut.read())): any).data).toMatch(/[\\\/]v[0-9][\\\/]?$/); await mockConstants(config, {CACHE_VERSION: 42}, async (config): Promise => { await cache(config, reporter, {}, ['dir']); @@ -684,7 +684,7 @@ test.concurrent('install should update checksums in yarn.lock (--update-checksum const lockFileLines = explodeLockfile(lockFileContent); const packageHashInLockfile = lockFileLines[2].replace(/(^.*#)|("$)/g, ''); const installedPackageJson = path.resolve(config.cwd, 'node_modules', 'abab', 'package.json'); - const cachePackageJson = path.resolve(config.cwd, '.yarn-cache/v1/', packageCacheName, 'package.json'); + const cachePackageJson = path.resolve(config.cwd, '.yarn-cache/v2/', packageCacheName, 'package.json'); expect(packageHashInLockfile).toEqual(packageRealHash); expect(await fs.exists(installedPackageJson)).toBe(true); expect(await fs.exists(cachePackageJson)).toBe(true); diff --git a/src/cli/commands/run.js b/src/cli/commands/run.js index 39fcbfb3e0..0ae1e87e21 100644 --- a/src/cli/commands/run.js +++ b/src/cli/commands/run.js @@ -149,9 +149,17 @@ export async function run(config: Config, reporter: Reporter, flags: Object, arg reporter.error(reporter.lang('noBinAvailable')); } + const printedCommands: Map = new Map(); + + for (const pkgCommand of pkgCommands) { + const action = scripts.get(pkgCommand); + invariant(action, 'Action must exists'); + printedCommands.set(pkgCommand, action); + } + if (pkgCommands.size > 0) { reporter.info(`${reporter.lang('possibleCommands')}`); - reporter.list('possibleCommands', Array.from(scripts.keys()), toObject(scripts)); + reporter.list('possibleCommands', Array.from(pkgCommands), toObject(printedCommands)); await reporter .question(reporter.lang('commandQuestion')) .then(answer => runCommand(answer.split(' ')), () => reporter.error(reporter.lang('commandNotSpecified'))); diff --git a/src/util/generate-pnp-map-api.tpl.js b/src/util/generate-pnp-map-api.tpl.js index 91857c41d9..e7bc34f187 100644 --- a/src/util/generate-pnp-map-api.tpl.js +++ b/src/util/generate-pnp-map-api.tpl.js @@ -1,5 +1,5 @@ /* eslint-disable max-len, flowtype/require-valid-file-annotation, flowtype/require-return-type */ -/* global packageInformationStores */ +/* global packageInformationStores, $$LOCKFILE_FOLDER */ const fs = require('fs'); const Module = require('module'); @@ -8,13 +8,12 @@ const path = require('path'); const builtinModules = Module.builtinModules || Object.keys(process.binding('natives')); const originalLoader = Module._load; -const originalResolver = Module._resolveFilename; const originalReadFile = fs.readFile; const pathRegExp = /^(?!\.{0,2}(?:\/|$))((?:@[^\/]+\/)?[^\/]+)\/?(.*|)$/; const topLevelLocator = {name: null, reference: null}; -const topLevelResolution = {locator: topLevelLocator, treePath: ``, filesystemDirectory: "/Users/mael/yarn-pnp"}; +const topLevelResolution = {locator: topLevelLocator, treePath: ``, filesystemDirectory: $$LOCKFILE_FOLDER}; const pnpResolutionSymbol = Symbol('pnpResolution'); @@ -93,6 +92,7 @@ function getLocatorFromTreePath(treePath) { * Transforms the result of exports.resolveRequest into a single string. */ +/* eslint-disable no-bitwise */ function serializeResolution(resolution) { let output = pnpPathMagic; @@ -105,18 +105,20 @@ function serializeResolution(resolution) { return output + resolution.filesystemPath; function writeShort(n) { - writeByte((n >>> 0) & 0xFF); - writeByte((n >>> 8) & 0xFF); + writeByte((n >>> 0) & 0xff); + writeByte((n >>> 8) & 0xff); } function writeByte(n) { output += n.toString(2).padStart(8, '0').replace(/0/g, `./`).replace(/1/g, `//`); } } +/* eslint-enable no-bitwise */ /** */ +/* eslint-disable no-bitwise */ function deserializeResolution(serializedResolution) { let offset = pnpPathMagic.length; @@ -129,7 +131,7 @@ function deserializeResolution(serializedResolution) { const filesystemPath = serializedResolution.slice(offset); const filesystemDirectory = path.dirname(filesystemPath); - const treePath = String.fromCharCode(... charCodes); + const treePath = String.fromCharCode(...charCodes); const locator = getLocatorFromTreePath(treePath); const cacheKey = getCacheKey(filesystemPath, locator, treePath); @@ -141,7 +143,7 @@ function deserializeResolution(serializedResolution) { } function readByte() { - const encodedByte = serializedResolution.slice(offset, offset += 2 * 8); + const encodedByte = serializedResolution.slice(offset, (offset += 2 * 8)); let decodedByte = 0; for (let t = 0; t < 2 * 8; t += 2) { @@ -152,6 +154,7 @@ function deserializeResolution(serializedResolution) { return decodedByte; } } +/* eslint-enable no-bitwise */ /** * Computes the cache key for the given file of the given package. @@ -197,11 +200,13 @@ function applyNodeExtensionResolution(filesystemPath) { const extensions = Object.keys(Module._extensions); - const qualifiedFile = extensions.map(extension => { - return `${filesystemPath}${extension}`; - }).find(candidateFile => { - return fs.existsSync(candidateFile); - }); + const qualifiedFile = extensions + .map(extension => { + return `${filesystemPath}${extension}`; + }) + .find(candidateFile => { + return fs.existsSync(candidateFile); + }); if (qualifiedFile) { return qualifiedFile; @@ -210,11 +215,13 @@ function applyNodeExtensionResolution(filesystemPath) { // Otherwise, we check if the path is a folder - in such a case, we try to use its index if (stat && stat.isDirectory()) { - const indexFile = extensions.map(extension => { - return `${filesystemPath}/index${extension}`; - }).find(candidateFile => { - return fs.existsSync(candidateFile); - }); + const indexFile = extensions + .map(extension => { + return `${filesystemPath}/index${extension}`; + }) + .find(candidateFile => { + return fs.existsSync(candidateFile); + }); if (indexFile) { return indexFile; @@ -258,8 +265,6 @@ exports.getPackageInformation = function getPackageInformation({name, reference} */ exports.resolveRequest = function resolveRequest(request, parentResolution) { - // console.error('requesting', request, 'from', parentResolution); - // Bailout if the request is a native module if (builtinModules.indexOf(request) !== -1) { @@ -338,7 +343,8 @@ exports.resolveRequest = function resolveRequest(request, parentResolution) { } else { if (parentResolution.locator !== topLevelLocator) { throw new Error( - `Package ${parentResolution.locator.name}@${parentResolution.locator.reference} is trying to require package ${dependencyName} through "${request}", which is not declared in its dependencies (${Array.from( + `Package ${parentResolution.locator.name}@${parentResolution.locator + .reference} is trying to require package ${dependencyName} through "${request}", which is not declared in its dependencies (${Array.from( packageInformation.packageDependencies.keys(), ).join(`, `)})`, ); @@ -376,7 +382,9 @@ exports.resolveRequest = function resolveRequest(request, parentResolution) { if (qualifiedFilesystemPath) { filesystemPath = qualifiedFilesystemPath; } else { - throw new Error(`Couldn't find a suitable resolution for path "${filesystemPath}" (initial request was "${request}")`); + throw new Error( + `Couldn't find a suitable resolution for path "${filesystemPath}" (initial request was "${request}")`, + ); } // Compute the remaining fields @@ -387,8 +395,6 @@ exports.resolveRequest = function resolveRequest(request, parentResolution) { const resolution = {locator, treePath, filesystemPath, filesystemDirectory, cacheKey}; - // console.error('resolved to', resolution); - return resolution; }; @@ -478,8 +484,8 @@ exports.setup = function setup(initialParentTreePath) { return serializeResolution(resolution); }; - fs.readFile = (target, ... args) => { - return originalReadFile.call(fs, path.normalize(target), ... args); + fs.readFile = (target, ...args) => { + return originalReadFile.call(fs, path.normalize(target), ...args); }; }; @@ -499,7 +505,7 @@ exports.setupCompatibilityLayer = () => { const basedir = options.basedir || path.dirname(getCaller()); let parentResolution; - if (basedir === LOCKFILE_FOLDER || basedir.startsWith(LOCKFILE_FOLDER + `/`)) { + if (basedir === $$LOCKFILE_FOLDER || basedir.startsWith($$LOCKFILE_FOLDER + `/`)) { parentResolution = topLevelResolution; } else if (basedir.startsWith(pnpPathMagic)) { parentResolution = deserializeResolution(basedir); diff --git a/src/util/generate-pnp-map.js b/src/util/generate-pnp-map.js index d0e286ac42..1270cf35bb 100644 --- a/src/util/generate-pnp-map.js +++ b/src/util/generate-pnp-map.js @@ -13,6 +13,7 @@ const path = require('path'); type PackageInformation = {| packageLocation: string, + packageMainEntry: ?string, packageDependencies: Map, packagePeers: Map>, |}; @@ -28,7 +29,10 @@ function generateMaps(packageInformationStores: PackageInformationStores): strin for (const [packageName, packageInformationStore] of packageInformationStores) { code += ` [${JSON.stringify(packageName)}, new Map([\n`; - for (const [packageReference, {packageMainEntry, packageLocation, packageDependencies, packagePeers}] of packageInformationStore) { + for (const [ + packageReference, + {packageMainEntry, packageLocation, packageDependencies, packagePeers}, + ] of packageInformationStore) { code += ` [${JSON.stringify(packageReference)}, {\n`; code += ` packageLocation: ${JSON.stringify(packageLocation)},\n`; @@ -227,6 +231,7 @@ async function getPackageInformationStores( [ null, { + packageMainEntry: null, packageLocation: (await fs.realpath(config.lockfileFolder)).replace(/[\\\/]?$/, path.sep), packageDependencies: topLevelDependencies, packagePeers: new Map(), @@ -247,6 +252,6 @@ export async function generatePnpMap( const packageInformationStores = await getPackageInformationStores(config, seedPatterns, {resolver}); return ( - generateMaps(packageInformationStores) + pnpApi.replace(/LOCKFILE_FOLDER/g, JSON.stringify(config.lockfileFolder)) + generateMaps(packageInformationStores) + pnpApi.replace(/\$\$LOCKFILE_FOLDER/g, JSON.stringify(config.lockfileFolder)) ); } diff --git a/src/util/portable-script.js b/src/util/portable-script.js index 3562489f56..05e1cd523c 100644 --- a/src/util/portable-script.js +++ b/src/util/portable-script.js @@ -30,7 +30,7 @@ async function makePortableProxyScriptUnix( const pnpPathBuilder = options.pnpPackageName ? // eslint-disable-next-line max-len - `if [[ -z $YARN_PNP_PATH ]]; then\n export YARN_PNP_PATH="${options.pnpPackageName}"\nelse\n export YARN_PNP_PATH="$YARN_PNP_PATH/${options.pnpPackageName}"\nfi\n\n` + `if [ -z "$YARN_PNP_PATH" ]; then\n export YARN_PNP_PATH="${options.pnpPackageName}"\nelse\n export YARN_PNP_PATH="$YARN_PNP_PATH/${options.pnpPackageName}"\nfi\n\n` : ''; const filePath = `${destination}/${options.proxyBasename || path.basename(source)}`; From ff25ef9efd8b2ff384ad358011341ebe82834831 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Thu, 15 Mar 2018 17:30:50 +0000 Subject: [PATCH 035/111] Generates virtual when using peer dependencies Branch: virtual-packages --- src/util/generate-pnp-map.js | 261 +++++++++++++++-------------------- 1 file changed, 110 insertions(+), 151 deletions(-) diff --git a/src/util/generate-pnp-map.js b/src/util/generate-pnp-map.js index 1270cf35bb..9a19c54e57 100644 --- a/src/util/generate-pnp-map.js +++ b/src/util/generate-pnp-map.js @@ -1,13 +1,11 @@ // @flow import type Config from '../config.js'; -import type PackageRequest from '../package-request.js'; import type PackageResolver from '../package-resolver.js'; import pnpApi from './generate-pnp-map-api.tpl.js'; -import * as constants from '../constants.js'; -import type {Manifest} from '../types.js'; import * as fs from './fs.js'; +const crypto = require('crypto'); const invariant = require('invariant'); const path = require('path'); @@ -15,7 +13,6 @@ type PackageInformation = {| packageLocation: string, packageMainEntry: ?string, packageDependencies: Map, - packagePeers: Map>, |}; type PackageInformationStore = Map; type PackageInformationStores = Map; @@ -31,7 +28,7 @@ function generateMaps(packageInformationStores: PackageInformationStores): strin for (const [ packageReference, - {packageMainEntry, packageLocation, packageDependencies, packagePeers}, + {packageMainEntry, packageLocation, packageDependencies}, ] of packageInformationStore) { code += ` [${JSON.stringify(packageReference)}, {\n`; code += ` packageLocation: ${JSON.stringify(packageLocation)},\n`; @@ -46,18 +43,6 @@ function generateMaps(packageInformationStores: PackageInformationStores): strin } code += ` ]),\n`; - if (packagePeers.size > 0) { - code += ` packagePeers: new Map([\n`; - for (const [dependencyPath, peerEntries] of packagePeers) { - code += ` [${JSON.stringify(dependencyPath)}, new Map([\n`; - for (const [dependencyName, dependencyReference] of peerEntries.entries()) { - code += ` [${JSON.stringify(dependencyName)}, ${JSON.stringify(dependencyReference)}],\n`; - } - code += ` ])],\n`; - } - code += ` ]),\n`; - } - code += ` }],\n`; } @@ -69,177 +54,150 @@ function generateMaps(packageInformationStores: PackageInformationStores): strin return code; } -function getPackagesDistance(fromReq: PackageRequest, toReq: PackageRequest): number | null { - // toReq cannot be a valid peer dependency if it's deeper in the tree - if (toReq.parentNames.length > fromReq.parentNames.length) { - return null; - } - - // To be a valid peer dependency, toReq must have the same parents - for (let t = 0; t < toReq.parentNames.length; ++t) { - if (toReq.parentNames[t] !== fromReq.parentNames[t]) { - return null; - } - } - - // The depth is simply the number of parents between the two packages - return fromReq.parentNames.length - toReq.parentNames.length; -} - -function getPackagePeers( - pkg: Manifest, - {resolver, exclude}: {resolver: PackageResolver, exclude: Set}, -): Map> { - const ref = pkg._reference; - invariant(ref, `Ref must exists`); - - // Early exit if the package has no peer dependency +async function getPackageInformationStores( + config: Config, + seedPatterns: Array, + {resolver}: {resolver: PackageResolver}, +): Promise { + const packageInformationStores: PackageInformationStores = new Map(); - const peerDependencies = pkg.peerDependencies || {}; - const peerNames = new Set(Object.keys(peerDependencies)); + const getHashFrom = (data: Array) => { + const hashGenerator = crypto.createHash('sha1'); - for (const excludeName of exclude) { - peerNames.delete(excludeName); - } + for (const datum of data) { + hashGenerator.update(datum); + } - if (peerNames.size === 0) { - return new Map(); - } + return hashGenerator.digest('hex'); + }; - // Cache the candidates for each peer dependency + const getResolverEntry = pattern => { + const pkg = resolver.getStrictResolvedPattern(pattern); + const ref = pkg._reference; - const peerCandidateMap = new Map(); + if (!ref) { + return null; + } - for (const peerDependency of peerNames) { - peerCandidateMap.set(peerDependency, resolver.getAllInfoForPackageName(peerDependency)); - } + const loc = ref.location; - // Find the best candidates for each peer dependency for each branch that uses `pkg` + if (!loc) { + return null; + } - const packagePeers = new Map(); + return {pkg, ref, loc}; + }; - for (const req of ref.requests) { - const peerPath = [...req.parentNames, ref.name].join('/'); - const peerEntries = new Map(); + const visit = async ( + seedPatterns: Array, + parentData: Array = [], + availablePackages: Map = new Map(), + ) => { + const resolutions = new Map(); - for (const peerDependency of peerNames) { - const peerCandidates = peerCandidateMap.get(peerDependency); - invariant(peerCandidates, `We must have peer candidates`); + // This first pass will compute the package reference of each of the given patterns + // They will usually be the package version, but not always. We need to do this in a pre-process pass, because the + // dependencies might depend on one another, so if we need to replace one of them, we need to compute it first + for (const pattern of seedPatterns) { + const entry = getResolverEntry(pattern); - let bestCandidate = null; - let bestDepth = Infinity; + if (!entry) { + continue; + } - for (const peerCandidate of peerCandidates) { - const candidateRef = peerCandidate._reference; + const {pkg} = entry; - if (!candidateRef) { - continue; - } + const packageName = pkg.name; + let packageReference = pkg.version; - for (const candidateReq of candidateRef.requests) { - const candidateDepth = getPackagesDistance(req, candidateReq); + // If we have peer dependencies, then we generate a new virtual reference based on the parent one + // We cannot generate this reference based on what those peer references resolve to, because they might not have + // been computed yet (for example, consider the case where A has a peer dependency on B, and B a peer dependency + // on A; it's valid, but it prevents us from computing A and B - and it's even worse with 3+ packages involved) + const peerDependencies = new Set(Array.from(Object.keys(pkg.peerDependencies || {}))); - if (candidateDepth !== null && bestDepth > candidateDepth) { - bestCandidate = peerCandidate; - bestDepth = candidateDepth; - } - } + if (peerDependencies.size > 0) { + packageReference = `pnp:${getHashFrom([...parentData, packageName])}`; } - if (bestCandidate) { - peerEntries.set(peerDependency, bestCandidate.version); - } else { - peerEntries.set(peerDependency, null); - } + // Now that we have the final reference, we need to store it + resolutions.set(packageName, packageReference); } - packagePeers.set(peerPath, peerEntries); - } + // Now that we have the final references, we can start the main loop, which will insert the packages into the store + // if they aren't already there, and recurse over their own children + for (const pattern of seedPatterns) { + const entry = getResolverEntry(pattern); - return packagePeers; -} + if (!entry) { + continue; + } -async function getPackageInformationStores( - config: Config, - seedPatterns: Array, - {resolver}: {resolver: PackageResolver}, -): Promise { - const packageInformationStores = new Map(); + const {pkg, ref, loc} = entry; - const pkgs = resolver.getTopologicalManifests(seedPatterns); + const packageName = pkg.name; + const packageReference = resolutions.get(packageName); - for (const pkg of pkgs) { - if (pkg._reference && pkg._reference.location && pkg._reference.isPlugnplay) { - const ref = pkg._reference; - const loc = pkg._reference.location; + invariant(packageReference, `Package reference should have been computed during the pre-pass`); - let packageInformationStore = packageInformationStores.get(pkg.name); + // We can early exit if the package is already registered with the exact same name and reference, since even if + // we might get slightly different dependencies (depending on how things were optimized), both sets are valid + let packageInformationStore = packageInformationStores.get(packageName); if (!packageInformationStore) { - packageInformationStores.set(pkg.name, (packageInformationStore = new Map())); - } - - // Get the dependency we directly own (vs those provided through peerDependencies) - - const ownedDependencies = new Set(); - - for (const dependencyType of constants.OWNED_DEPENDENCY_TYPES) { - if (pkg[dependencyType]) { - for (const dependencyName of Object.keys(pkg[dependencyType])) { - ownedDependencies.add(dependencyName); - } - } + packageInformationStore = new Map(); + packageInformationStores.set(packageName, packageInformationStore); } - // Resolve all the dependencies for our package + let packageInformation = packageInformationStore.get(packageReference); - const packageDependencies = new Map(); - - for (const pattern of ref.dependencies) { - const dep = resolver.getStrictResolvedPattern(pattern); - if (ownedDependencies.has(dep.name)) { - packageDependencies.set(dep.name, dep.version); - } + if (packageInformation) { + continue; } - // Compute the peer dependencies for each possible require path - // In case of conflict, we use the one from dependencies / devDependencies / optionalDependencies - - const packagePeers = getPackagePeers(pkg, {resolver, exclude: ownedDependencies}); - - packageInformationStore.set(pkg.version, { + packageInformation = { packageMainEntry: pkg.main, packageLocation: (await fs.realpath(loc)).replace(/[\\\/]?$/, path.sep), - packageDependencies, - packagePeers, + packageDependencies: new Map(), + }; + + // Split the dependencies between direct/peer - we will only recurse on the former + const peerDependencies = new Set(Array.from(Object.keys(pkg.peerDependencies || {}))); + const directDependencies = ref.dependencies.filter(pattern => { + const pkg = resolver.getStrictResolvedPattern(pattern); + return !pkg || !peerDependencies.has(pkg.name); }); - } - } - // Top-level package - if (true) { - const topLevelDependencies = new Map(); + // We do this in two steps to prevent cyclic dependencies from looping indefinitely + packageInformationStore.set(packageReference, packageInformation); + packageInformation.packageDependencies = await visit(directDependencies, [packageName, packageReference]); - for (const pattern of seedPatterns) { - const dep = resolver.getStrictResolvedPattern(pattern); - topLevelDependencies.set(dep.name, dep.version); + // We now have to inject the peer dependencies + for (const dependencyName of peerDependencies) { + const dependencyReference = resolutions.get(dependencyName); + + if (dependencyReference) { + packageInformation.packageDependencies.set(dependencyName, dependencyReference); + } + } } - packageInformationStores.set( - null, - new Map([ - [ - null, - { - packageMainEntry: null, - packageLocation: (await fs.realpath(config.lockfileFolder)).replace(/[\\\/]?$/, path.sep), - packageDependencies: topLevelDependencies, - packagePeers: new Map(), - }, - ], - ]), - ); - } + return resolutions; + }; + + packageInformationStores.set( + null, + new Map([ + [ + null, + { + packageMainEntry: null, + packageLocation: (await fs.realpath(config.lockfileFolder)).replace(/[\\\/]?$/, path.sep), + packageDependencies: await visit(seedPatterns), + }, + ], + ]), + ); return packageInformationStores; } @@ -252,6 +210,7 @@ export async function generatePnpMap( const packageInformationStores = await getPackageInformationStores(config, seedPatterns, {resolver}); return ( - generateMaps(packageInformationStores) + pnpApi.replace(/\$\$LOCKFILE_FOLDER/g, JSON.stringify(config.lockfileFolder)) + generateMaps(packageInformationStores) + + pnpApi.replace(/\$\$LOCKFILE_FOLDER/g, JSON.stringify(config.lockfileFolder)) ); } From 11ebf79e552a9811a2c8a9eb8b7742e7ddf7325d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Fri, 16 Mar 2018 13:52:16 +0000 Subject: [PATCH 036/111] Refactors the generated pnp files to use the newly generated maps Branch: pnp-refactor-find --- src/cli/commands/run.js | 1 - src/fetchers/base-fetcher.js | 5 +- src/util/generate-pnp-map-api.tpl.js | 346 ++++++--------------------- src/util/generate-pnp-map.js | 81 +++++-- src/util/portable-script.js | 12 +- 5 files changed, 155 insertions(+), 290 deletions(-) diff --git a/src/cli/commands/run.js b/src/cli/commands/run.js index 0ae1e87e21..fcb472e2ef 100644 --- a/src/cli/commands/run.js +++ b/src/cli/commands/run.js @@ -36,7 +36,6 @@ export async function run(config: Config, reporter: Reporter, flags: Object, arg const pkg = await config.readManifest(config.cwd); const binFolders = new Set(); - // Setup the node_modules/.bin folders for analysis for (const registry of Object.keys(registries)) { binFolders.add(path.join(config.cwd, config.registries[registry].folder, '.bin')); diff --git a/src/fetchers/base-fetcher.js b/src/fetchers/base-fetcher.js index fe08ea5a20..a4ad776ba6 100644 --- a/src/fetchers/base-fetcher.js +++ b/src/fetchers/base-fetcher.js @@ -66,7 +66,10 @@ export default class BaseFetcher { if (pkg.bin) { for (const binName of Object.keys(pkg.bin)) { const dest = `${this.dest}/.bin`; - const src = `${this.dest}/${pkg.bin[binName]}`; + + // Using any sort of absolute path here would prevent makePortableProxyScript from preserving symlinks when + // calling the binary + const src = pkg.bin[binName]; await makePortableProxyScript(src, dest, { proxyBasename: binName, diff --git a/src/util/generate-pnp-map-api.tpl.js b/src/util/generate-pnp-map-api.tpl.js index e7bc34f187..cb942bf772 100644 --- a/src/util/generate-pnp-map-api.tpl.js +++ b/src/util/generate-pnp-map-api.tpl.js @@ -1,5 +1,5 @@ /* eslint-disable max-len, flowtype/require-valid-file-annotation, flowtype/require-return-type */ -/* global packageInformationStores, $$LOCKFILE_FOLDER */ +/* global packageInformationStores */ const fs = require('fs'); const Module = require('module'); @@ -8,20 +8,15 @@ const path = require('path'); const builtinModules = Module.builtinModules || Object.keys(process.binding('natives')); const originalLoader = Module._load; -const originalReadFile = fs.readFile; const pathRegExp = /^(?!\.{0,2}(?:\/|$))((?:@[^\/]+\/)?[^\/]+)\/?(.*|)$/; +const isDirRegExp = /[\\\/]$/; const topLevelLocator = {name: null, reference: null}; -const topLevelResolution = {locator: topLevelLocator, treePath: ``, filesystemDirectory: $$LOCKFILE_FOLDER}; - -const pnpResolutionSymbol = Symbol('pnpResolution'); const moduleShims = new Map(); const moduleCache = new Map(); -const pnpPathMagic = `/.//.//.//`; - /** * Returns information about a package in a safe way (will throw if they cannot be retrieved) */ @@ -43,141 +38,14 @@ function getPackageInformationSafe(packageLocator) { * (will throw if they cannot be retrieved). */ -function getPeerReferencesSafe(packageInformation, parentTreePath) { - const peerReferences = packageInformation.packagePeers.get(parentTreePath); - - if (!peerReferences) { - throw new Error( - `Couldn't find the peer candidates for package located at "${parentTreePath}" in the dependency tree (this is probably an internal error)`, - ); - } - - return peerReferences; -} - -/** - * Given a tree path (pkg-a/sub-pkg-b/foobar), returns the associated locator (foobar@1.0.0) - */ - -function getLocatorFromTreePath(treePath) { - const parts = treePath ? treePath.split(/\//g) : []; - let currentLocator = topLevelLocator; - - for (let t = 0; t < parts.length; ++t) { - const dependencies = exports.getPackageInformation(currentLocator); - const currentTreePath = parts.slice(0, t).join('/'); - - const dependencyName = parts[t]; - let dependencyReference = dependencies.packageDependencies.get(dependencyName); - - if (!dependencyReference && dependencies.packagePeers) { - const peerReferences = dependencies.packagePeers.get(currentTreePath); - - if (peerReferences) { - dependencyReference = peerReferences.get(dependencyName); - } - } - - if (!dependencyReference) { - return null; - } - - currentLocator = {name: dependencyName, reference: dependencyReference}; - } - - return currentLocator; -} - -/** - * Transforms the result of exports.resolveRequest into a single string. - */ - -/* eslint-disable no-bitwise */ -function serializeResolution(resolution) { - let output = pnpPathMagic; - - writeShort(resolution.treePath.length); - - for (let t = 0; t < resolution.treePath.length; ++t) { - writeByte(resolution.treePath.charCodeAt(t)); - } - - return output + resolution.filesystemPath; - - function writeShort(n) { - writeByte((n >>> 0) & 0xff); - writeByte((n >>> 8) & 0xff); - } - - function writeByte(n) { - output += n.toString(2).padStart(8, '0').replace(/0/g, `./`).replace(/1/g, `//`); - } -} -/* eslint-enable no-bitwise */ - -/** -*/ - -/* eslint-disable no-bitwise */ -function deserializeResolution(serializedResolution) { - let offset = pnpPathMagic.length; - - const size = readShort(); - const charCodes = []; - - for (let t = 0; t < size; ++t) { - charCodes.push(readByte()); - } - - const filesystemPath = serializedResolution.slice(offset); - const filesystemDirectory = path.dirname(filesystemPath); - const treePath = String.fromCharCode(...charCodes); - - const locator = getLocatorFromTreePath(treePath); - const cacheKey = getCacheKey(filesystemPath, locator, treePath); - - return {locator, treePath, filesystemPath, filesystemDirectory, cacheKey}; - - function readShort() { - return readByte() | (readByte() << 8); - } - - function readByte() { - const encodedByte = serializedResolution.slice(offset, (offset += 2 * 8)); - let decodedByte = 0; - - for (let t = 0; t < 2 * 8; t += 2) { - decodedByte *= 2; - decodedByte += encodedByte.slice(t, t + 2).includes(`.`) ? 0 : 1; - } - - return decodedByte; - } -} -/* eslint-enable no-bitwise */ - -/** - * Computes the cache key for the given file of the given package. - * - * The cache key is the file path for most entries, but if their owning package has peer dependency then we need to - * bake the peer dependencies resolved references into the cache key (because we'll need to instanciate multiple - * versions of the same file, one for each set of dependencies). - */ - -function getCacheKey(filesystemPath, packageLocator, treePath) { - let cacheKey = filesystemPath; +function findPackageLocatorSafe(filesystemPath) { + const packageLocator = exports.findPackageLocator(filesystemPath); - const packageInformation = getPackageInformationSafe(packageLocator); - - if (packageInformation.packagePeers) { - const peerReferences = getPeerReferencesSafe(packageInformation, treePath); - - for (const [dependencyName, dependencyReference] of peerReferences.entries()) { - cacheKey += `@${dependencyName}@${dependencyReference}`; - } + if (!packageLocator) { + throw new Error(`Couldn't find an owner for path "${filesystemPath}"`); } - return cacheKey; + return packageLocator; } /** @@ -264,34 +132,25 @@ exports.getPackageInformation = function getPackageInformation({name, reference} * - The file cache key */ -exports.resolveRequest = function resolveRequest(request, parentResolution) { +exports.resolveRequest = function resolveRequest(request, issuer) { // Bailout if the request is a native module if (builtinModules.indexOf(request) !== -1) { - return null; - } - - // If the request is a serialized resolution, we just have to deserialize it - - if (request.startsWith(pnpPathMagic)) { - return deserializeResolution(request); + return request; } - let dependencyLocator; - - let treePath; let filesystemPath; - // If the request is a relative or absolute path, we just have to reuse the parent resolution, and resolve the - // request path relative to the parent resolution own path + // If the request is a relative or absolute path, we just return it normalized const dependencyNameMatch = request.match(pathRegExp); if (!dependencyNameMatch) { - dependencyLocator = parentResolution.locator; - - treePath = parentResolution.treePath; - filesystemPath = path.resolve(parentResolution.filesystemDirectory, request); + if (issuer.match(isDirRegExp)) { + filesystemPath = path.normalize(path.resolve(issuer, request)); + } else { + filesystemPath = path.normalize(path.resolve(path.dirname(issuer), request)); + } } // Things are more hairy if it's a package require - we then need to figure out which package is needed, and in @@ -300,67 +159,59 @@ exports.resolveRequest = function resolveRequest(request, parentResolution) { if (dependencyNameMatch) { const [, dependencyName, subPath] = dependencyNameMatch; - const packageInformation = getPackageInformationSafe(parentResolution.locator); + const issuerLocator = findPackageLocatorSafe(issuer); + const issuerInformation = getPackageInformationSafe(issuerLocator); // We obtain the dependency reference in regard to the package that request it - let dependencyReference = packageInformation.packageDependencies.get(dependencyName); + let dependencyReference = issuerInformation.packageDependencies.get(dependencyName); - // If there's no strict dependency that match the request, we look into peer dependencies - - if (!dependencyReference && packageInformation.packagePeers) { - const peerReferences = getPeerReferencesSafe(packageInformation, parentResolution.treePath); - const peerReference = peerReferences.get(dependencyName); - - if (peerReference === null) { - throw new Error( - `Package "${parentResolution.locator.name}" tries to access a missing peer dependency ("${dependencyName}")`, - ); - } - - dependencyReference = peerReference; - } - - // If we STILL can't find it, we fallback to the top-level dependencies - // This fallback isn't ideal, but makes working with plugins much easier - - if (!dependencyReference) { - const topLevelInformation = exports.getPackageInformation(topLevelLocator); + // If we can't find it, we check if we can potentially load it from the top-level packages + // it's a bit of a hack, but it improves compatibility with the existing Node ecosystem. Hopefully we should + // eventually be able to kill it and become stricter once pnp gets enough traction + if (dependencyReference === undefined) { + const topLevelInformation = getPackageInformationSafe(topLevelLocator); dependencyReference = topLevelInformation.packageDependencies.get(dependencyName); - - if (dependencyReference) { - parentResolution = topLevelResolution; - } } - // And if we still haven't been able to resolve it, we give up - // If the package making the request is the top-level, we can offer a nicer error message + // If we can't find the path, and if the package making the request is the top-level, we can offer nicer error messages - if (dependencyReference) { - treePath = parentResolution.treePath ? `${parentResolution.treePath}/${dependencyName}` : dependencyName; - dependencyLocator = {name: dependencyName, reference: dependencyReference}; - } else { - if (parentResolution.locator !== topLevelLocator) { - throw new Error( - `Package ${parentResolution.locator.name}@${parentResolution.locator - .reference} is trying to require package ${dependencyName} through "${request}", which is not declared in its dependencies (${Array.from( - packageInformation.packageDependencies.keys(), - ).join(`, `)})`, - ); + if (!dependencyReference) { + if (dependencyReference === null) { + if (issuerLocator === topLevelLocator) { + throw new Error( + `You seem to be requiring a peer dependency ("${dependencyName}"), but it is not installed (which might be because you're the top-level package)`, + ); + } else { + throw new Error( + `Package "${issuerLocator.name}@${issuerLocator.reference}" is trying to access a peer dependency ("${dependencyName}") that should be provided by its direct ancestor but isn't`, + ); + } } else { - throw new Error(`You cannot require a package (${dependencyName}) that is not declared in your dependencies`); + if (issuerLocator === topLevelLocator) { + throw new Error( + `You cannot require a package ("${dependencyName}") that is not declared in your dependencies`, + ); + } else { + throw new Error( + `Package ${issuerLocator.name}@${issuerLocator.reference} is trying to require package ${dependencyName} (via "${request}") without it being listed in its dependencies (${Array.from( + issuerInformation.packageDependencies.keys(), + ).join(`, `)})`, + ); + } } } // We need to check that the package exists on the filesystem, because it might not have been installed + const dependencyLocator = {name: dependencyName, reference: dependencyReference}; const dependencyInformation = exports.getPackageInformation(dependencyLocator); const dependencyLocation = dependencyInformation.packageLocation; if (!dependencyLocation) { throw new Error( - `Package ${dependencyLocator.name}@${dependencyLocator.reference} is a valid dependency, but hasn't been installed and thus cannot be required`, + `Package "${dependencyLocator.name}@${dependencyLocator.reference}" is a valid dependency, but hasn't been installed and thus cannot be required`, ); } @@ -380,42 +231,26 @@ exports.resolveRequest = function resolveRequest(request, parentResolution) { const qualifiedFilesystemPath = applyNodeExtensionResolution(filesystemPath); if (qualifiedFilesystemPath) { - filesystemPath = qualifiedFilesystemPath; + return path.normalize(qualifiedFilesystemPath); } else { - throw new Error( - `Couldn't find a suitable resolution for path "${filesystemPath}" (initial request was "${request}")`, - ); + throw new Error(`Couldn't find a suitable Node resolution for path "${filesystemPath}"`); } - - // Compute the remaining fields - - const locator = dependencyLocator; - const filesystemDirectory = path.dirname(filesystemPath); - const cacheKey = getCacheKey(filesystemPath, locator, treePath); - - const resolution = {locator, treePath, filesystemPath, filesystemDirectory, cacheKey}; - - return resolution; }; /** * Setups the hook into the Node environment */ -exports.setup = function setup(initialParentTreePath) { - const initialParentLocator = getLocatorFromTreePath(initialParentTreePath); +exports.setup = function setup() { + function getIssuer(parent) { + let issuer = parent; - if (!initialParentLocator) { - throw new Error( - `Could not find resolve the given entry point, "${initialParentTreePath}" (this is probably an internal error)`, - ); - } + while (issuer && (issuer.id === '[eval]' || issuer.id === '' || !issuer.filename)) { + issuer = issuer.parent; + } - const initialResolution = { - locator: initialParentLocator, - treePath: initialParentTreePath, - filesystemDirectory: process.cwd(), - }; + return issuer; + } Module._load = function(request, parent, isMain) { // Builtins are managed by the regular Node loader @@ -432,12 +267,13 @@ exports.setup = function setup(initialParentTreePath) { return shim; } - const parentResolution = parent && parent[pnpResolutionSymbol] ? parent[pnpResolutionSymbol] : initialResolution; - const requestResolution = exports.resolveRequest(request, parentResolution); + // Request `Module._resolveFilename` (ie. `resolveRequest`) to tell us which file we should load - // Check if the module has already been created + const filesystemPath = Module._resolveFilename(request, parent, isMain); - const cacheEntry = moduleCache.get(requestResolution.cacheKey); + // Check if the module has already been created for the given file + + const cacheEntry = moduleCache.get(filesystemPath); if (cacheEntry) { return cacheEntry.exports; @@ -445,12 +281,10 @@ exports.setup = function setup(initialParentTreePath) { // Create a new module and store it into the cache - const module = new Module(requestResolution.filesystemPath, parent); - module[pnpResolutionSymbol] = requestResolution; - - moduleCache.set(requestResolution.cacheKey, module); + const module = new Module(filesystemPath, parent); + moduleCache.set(filesystemPath, module); - // Main modules are exposed on the global instances + // The main module is exposed as global variable if (isMain) { process.mainModule = module; @@ -462,11 +296,11 @@ exports.setup = function setup(initialParentTreePath) { let hasThrown = true; try { - module.load(requestResolution.filesystemPath); + module.load(filesystemPath); hasThrown = false; } finally { if (hasThrown) { - moduleCache.delete(requestResolution.cacheKey); + moduleCache.delete(filesystemPath); } } @@ -474,18 +308,10 @@ exports.setup = function setup(initialParentTreePath) { }; Module._resolveFilename = function(request, parent, isMain, options) { - if (builtinModules.indexOf(request) !== -1) { - return request; - } - - const parentResolution = parent && parent[pnpResolutionSymbol] ? parent[pnpResolutionSymbol] : initialResolution; - const resolution = exports.resolveRequest(request, parentResolution); + const issuerModule = getIssuer(parent); + const issuer = issuerModule ? issuerModule.filename : process.cwd() + path.sep; - return serializeResolution(resolution); - }; - - fs.readFile = (target, ...args) => { - return originalReadFile.call(fs, path.normalize(target), ...args); + return exports.resolveRequest(request, issuer); }; }; @@ -502,30 +328,13 @@ exports.setupCompatibilityLayer = () => { }; const resolveSyncShim = (request, options = {}) => { - const basedir = options.basedir || path.dirname(getCaller()); - let parentResolution; - - if (basedir === $$LOCKFILE_FOLDER || basedir.startsWith($$LOCKFILE_FOLDER + `/`)) { - parentResolution = topLevelResolution; - } else if (basedir.startsWith(pnpPathMagic)) { - parentResolution = deserializeResolution(basedir); - - // HACK: since basedir is traditionally a folder, the filesystemDirectory actually is filesystemPath! - // If we don't make this change, parentResolution.filesystemDirectory will be dirname(dirname(X)): the first one - // because the user did it themselves, and the second one because deserializeResolution thought that the string - // would contain something it returned in the past (which always is a file), so it would compute the directory by - // using dirname() on this path. - parentResolution.filesystemDirectory = parentResolution.filesystemPath; - } else { - throw new Error( - `This usage of the "resolve" module is not supported on Plug'n'Play environments (got "${options.basedir}" as basedir)`, - ); - } + let basedir = options.basedir || path.dirname(getCaller()); + basedir = basedir.replace(/[\\\/]?$/, path.sep); - const resolution = exports.resolveRequest(request, parentResolution); + const resolution = exports.resolveRequest(request, basedir); if (resolution) { - return serializeResolution(resolution); + return resolution; } else { throw new Error(`Resolution failed for path "${request}"`); } @@ -538,7 +347,8 @@ exports.setupCompatibilityLayer = () => { } // We need to compute it here because otherwise resolveSyncShim will read the wrong stacktrace entry - const basedir = options.basedir || path.dirname(getCaller()); + let basedir = options.basedir || path.dirname(getCaller()); + basedir = basedir.replace(/[\\\/]?$/, path.sep); setImmediate(() => { let error; @@ -558,6 +368,6 @@ exports.setupCompatibilityLayer = () => { }; if (module.parent && module.parent.id === 'internal/preload') { - exports.setup(process.env.YARN_PNP_PATH || ''); + exports.setup(); exports.setupCompatibilityLayer(); } diff --git a/src/util/generate-pnp-map.js b/src/util/generate-pnp-map.js index 9a19c54e57..6a44b8258b 100644 --- a/src/util/generate-pnp-map.js +++ b/src/util/generate-pnp-map.js @@ -22,38 +22,82 @@ function generateMaps(packageInformationStores: PackageInformationStores): strin // Bake the information stores into our generated code code += `let packageInformationStores = new Map([\n`; - for (const [packageName, packageInformationStore] of packageInformationStores) { code += ` [${JSON.stringify(packageName)}, new Map([\n`; - for (const [ packageReference, {packageMainEntry, packageLocation, packageDependencies}, ] of packageInformationStore) { code += ` [${JSON.stringify(packageReference)}, {\n`; code += ` packageLocation: ${JSON.stringify(packageLocation)},\n`; - if (packageMainEntry) { code += ` packageMainEntry: ${JSON.stringify(packageMainEntry)},\n`; } - code += ` packageDependencies: new Map([\n`; for (const [dependencyName, dependencyReference] of packageDependencies.entries()) { code += ` [${JSON.stringify(dependencyName)}, ${JSON.stringify(dependencyReference)}],\n`; } code += ` ]),\n`; - code += ` }],\n`; } - code += ` ])],\n`; } + code += `]);\n`; + + code += `\n`; + // Also bake an inverse map that will allow us to find the package information based on the path + code += `let locatorsByLocations = new Map([\n`; + for (const [packageName, packageInformationStore] of packageInformationStores) { + for (const [packageReference, {packageLocation}] of packageInformationStore) { + code += ` [${JSON.stringify(packageLocation)}, ${JSON.stringify({ + name: packageName, + reference: packageReference, + })}],\n`; + } + } code += `]);\n`; return code; } +function generateFindPackageLocator(packageInformationStores: PackageInformationStores): string { + let code = ``; + + // We get the list of each string length we'll need to check in order to find the current package context + const lengths = new Map(); + + for (const packageInformationStore of packageInformationStores.values()) { + for (const {packageLocation} of packageInformationStore.values()) { + if (packageLocation !== null) { + lengths.set(packageLocation.length, (lengths.get(packageLocation.length) || 0) + 1); + } + } + } + + // We sort the lengths by the number of time they are used, so that the more common ones are tested before the others + const sortedLengths = Array.from(lengths.entries()).sort((a, b) => { + return b[1] - a[1]; + }); + + // Generate a function that, given a file path, returns the associated package name + code += `exports.findPackageLocator = function findPackageLocator(location) {\n`; + code += ` let match;\n`; + + for (const [length] of sortedLengths) { + code += `\n`; + code += ` if (location.length >= ${length} && location[${length} - 1] === path.sep)\n`; + code += ` if (match = locatorsByLocations.get(location.substr(0, ${length})))\n`; + code += ` return match;\n`; + } + + code += `\n`; + code += ` return null;\n`; + code += `};\n`; + + return code; +} + async function getPackageInformationStores( config: Config, seedPatterns: Array, @@ -94,6 +138,7 @@ async function getPackageInformationStores( availablePackages: Map = new Map(), ) => { const resolutions = new Map(); + const locations = new Map(); // This first pass will compute the package reference of each of the given patterns // They will usually be the package version, but not always. We need to do this in a pre-process pass, because the @@ -106,6 +151,7 @@ async function getPackageInformationStores( } const {pkg} = entry; + let {loc} = entry; const packageName = pkg.name; let packageReference = pkg.version; @@ -117,11 +163,18 @@ async function getPackageInformationStores( const peerDependencies = new Set(Array.from(Object.keys(pkg.peerDependencies || {}))); if (peerDependencies.size > 0) { - packageReference = `pnp:${getHashFrom([...parentData, packageName])}`; + const hash = getHashFrom([...parentData, packageName, packageReference]); + + const newLoc = path.resolve(path.dirname(loc), `pnp-${hash}`); + await fs.symlink(loc, newLoc); + loc = newLoc; + + packageReference = `pnp:${hash}`; } // Now that we have the final reference, we need to store it resolutions.set(packageName, packageReference); + locations.set(packageName, loc); } // Now that we have the final references, we can start the main loop, which will insert the packages into the store @@ -133,13 +186,16 @@ async function getPackageInformationStores( continue; } - const {pkg, ref, loc} = entry; + const {pkg, ref} = entry; const packageName = pkg.name; - const packageReference = resolutions.get(packageName); + const packageReference = resolutions.get(packageName); invariant(packageReference, `Package reference should have been computed during the pre-pass`); + const loc = locations.get(packageName); + invariant(loc, `Package location should have been computed during the pre-pass`); + // We can early exit if the package is already registered with the exact same name and reference, since even if // we might get slightly different dependencies (depending on how things were optimized), both sets are valid let packageInformationStore = packageInformationStores.get(packageName); @@ -157,7 +213,7 @@ async function getPackageInformationStores( packageInformation = { packageMainEntry: pkg.main, - packageLocation: (await fs.realpath(loc)).replace(/[\\\/]?$/, path.sep), + packageLocation: loc.replace(/[\\\/]?$/, path.sep), packageDependencies: new Map(), }; @@ -209,8 +265,5 @@ export async function generatePnpMap( ): Promise { const packageInformationStores = await getPackageInformationStores(config, seedPatterns, {resolver}); - return ( - generateMaps(packageInformationStores) + - pnpApi.replace(/\$\$LOCKFILE_FOLDER/g, JSON.stringify(config.lockfileFolder)) - ); + return generateMaps(packageInformationStores) + generateFindPackageLocator(packageInformationStores) + pnpApi; } diff --git a/src/util/portable-script.js b/src/util/portable-script.js index 05e1cd523c..be901cff00 100644 --- a/src/util/portable-script.js +++ b/src/util/portable-script.js @@ -28,17 +28,17 @@ async function makePortableProxyScriptUnix( ? ' ' + options.appendArguments.map(arg => `"${arg}"`).join(' ') : ''; - const pnpPathBuilder = options.pnpPackageName - ? // eslint-disable-next-line max-len - `if [ -z "$YARN_PNP_PATH" ]; then\n export YARN_PNP_PATH="${options.pnpPackageName}"\nelse\n export YARN_PNP_PATH="$YARN_PNP_PATH/${options.pnpPackageName}"\nfi\n\n` - : ''; - const filePath = `${destination}/${options.proxyBasename || path.basename(source)}`; + // Unless impossible we want to preserve any symlinks used to call us when forwarding the call to the binary (so we + // cannot use realpath or transform relative paths into absolute ones), but we also need to tell the sh interpreter + // that the symlink should be resolved relative to the script directory (hence dirname "$0" at runtime). + const sourcePath = path.isAbsolute(source) ? source : `$(dirname "$0")/../${source}`; + await fs.mkdirp(destination); await fs.writeFile( filePath, - `#!/bin/sh\n\n${pnpPathBuilder}${environment}"${source}"${prependedArguments} "$@"${appendedArguments}\n`, + `#!/bin/sh\n\n${environment}"${sourcePath}"${prependedArguments} "$@"${appendedArguments}\n`, ); await fs.chmod(filePath, 0o755); } From cf362e53161c9e4d9ac40f77d7fd3644085a7ec8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Fri, 16 Mar 2018 16:51:34 +0000 Subject: [PATCH 037/111] Adds tests for workspaces Branch: workspace-tests --- .../pkg-tests-specs/sources/index.js | 1 + .../pkg-tests/pkg-tests-specs/sources/pnp.js | 8 +- .../pkg-tests-specs/sources/workspace.js | 125 ++++++++++++++++++ packages/pkg-tests/yarn.test.js | 9 +- 4 files changed, 141 insertions(+), 2 deletions(-) create mode 100644 packages/pkg-tests/pkg-tests-specs/sources/workspace.js diff --git a/packages/pkg-tests/pkg-tests-specs/sources/index.js b/packages/pkg-tests/pkg-tests-specs/sources/index.js index 383969741e..21e97e174d 100644 --- a/packages/pkg-tests/pkg-tests-specs/sources/index.js +++ b/packages/pkg-tests/pkg-tests-specs/sources/index.js @@ -4,3 +4,4 @@ exports.basic = require('./basic'); exports.dragon = require('./dragon'); exports.pnp = require('./pnp'); exports.script = require('./script'); +exports.workspace = require('./workspace'); diff --git a/packages/pkg-tests/pkg-tests-specs/sources/pnp.js b/packages/pkg-tests/pkg-tests-specs/sources/pnp.js index a213bb9fb2..045a9c5da8 100644 --- a/packages/pkg-tests/pkg-tests-specs/sources/pnp.js +++ b/packages/pkg-tests/pkg-tests-specs/sources/pnp.js @@ -1,7 +1,7 @@ const {fs: {writeFile, writeJson}, tests: {getPackageDirectoryPath}} = require('pkg-tests-core'); module.exports = makeTemporaryEnv => { - const {basic: basicSpecs, script: scriptSpecs} = require('pkg-tests-specs'); + const {basic: basicSpecs, script: scriptSpecs, workspace: workspaceSpecs} = require('pkg-tests-specs'); describe(`Plug'n'Play`, () => { basicSpecs( @@ -16,6 +16,12 @@ module.exports = makeTemporaryEnv => { }), ); + workspaceSpecs( + makeTemporaryEnv.withConfig({ + plugNPlay: true, + }), + ); + test( `it should resolve two identical packages with the same object (easy)`, makeTemporaryEnv( diff --git a/packages/pkg-tests/pkg-tests-specs/sources/workspace.js b/packages/pkg-tests/pkg-tests-specs/sources/workspace.js new file mode 100644 index 0000000000..ef67a37341 --- /dev/null +++ b/packages/pkg-tests/pkg-tests-specs/sources/workspace.js @@ -0,0 +1,125 @@ +/* @flow */ + +import type {PackageDriver} from 'pkg-tests-core'; + +const {fs: {writeFile, writeJson}} = require('pkg-tests-core'); + +module.exports = (makeTemporaryEnv: PackageDriver) => { + describe(`Workspaces tests`, () => { + test( + `it should make workspaces require-able from the top-level`, + makeTemporaryEnv( + { + private: true, + workspaces: [`packages/*`], + }, + async ({path, run, source}) => { + await writeJson(`${path}/packages/workspace-a/package.json`, { + name: `workspace-a`, + version: `1.0.0`, + }); + + await writeFile( + `${path}/packages/workspace-a/index.js`, + ` + module.exports = 42; + `, + ); + + await run(`install`); + + await expect(source(`require('workspace-a')`)).resolves.toEqual(42); + }, + ), + ); + + test( + `it should allow workspaces to require each others`, + makeTemporaryEnv( + { + private: true, + workspaces: [`packages/*`], + }, + async ({path, run, source}) => { + await writeJson(`${path}/packages/workspace-a/package.json`, { + name: `workspace-a`, + version: `1.0.0`, + dependencies: { + [`workspace-a`]: `1.0.0`, + }, + }); + + await writeFile( + `${path}/packages/workspace-a/index.js`, + ` + module.exports = require('workspace-b/package.json'); + `, + ); + + await writeJson(`${path}/packages/workspace-b/package.json`, { + name: `workspace-b`, + version: `1.0.0`, + dependencies: { + [`workspace-b`]: `1.0.0`, + }, + }); + + await writeFile( + `${path}/packages/workspace-b/index.js`, + ` + module.exports = require('workspace-a/package.json'); + `, + ); + + await run(`install`); + + await expect(source(`require('workspace-a')`)).resolves.toMatchObject({ + name: `workspace-b`, + }); + + await expect(source(`require('workspace-b')`)).resolves.toMatchObject({ + name: `workspace-a`, + }); + }, + ), + ); + + test( + `it should resolve workspaces as regular packages if the versions don't match`, + makeTemporaryEnv( + { + private: true, + workspaces: [`packages/*`], + }, + async ({path, run, source}) => { + await writeJson(`${path}/packages/workspace/package.json`, { + name: `workspace`, + version: `1.0.0`, + dependencies: { + [`no-deps`]: `2.0.0`, + }, + }); + + await writeFile( + `${path}/packages/workspace/index.js`, + ` + module.exports = require('no-deps/package.json'); + `, + ); + + await writeJson(`${path}/packages/no-deps/package.json`, { + name: `no-deps`, + version: `1.0.0`, + }); + + await run(`install`); + + await expect(source(`require('workspace')`)).resolves.toMatchObject({ + name: `no-deps`, + version: `2.0.0`, + }); + }, + ), + ); + }); +}; diff --git a/packages/pkg-tests/yarn.test.js b/packages/pkg-tests/yarn.test.js index 4567910966..1d153023df 100644 --- a/packages/pkg-tests/yarn.test.js +++ b/packages/pkg-tests/yarn.test.js @@ -7,7 +7,13 @@ const { exec: {execFile}, } = require(`pkg-tests-core`); -const {basic: basicSpecs, dragon: dragonSpecs, pnp: pnpSpecs, script: scriptSpecs} = require(`pkg-tests-specs`); +const { + basic: basicSpecs, + dragon: dragonSpecs, + pnp: pnpSpecs, + script: scriptSpecs, + workspace: workspaceSpecs, +} = require(`pkg-tests-specs`); const pkgDriver = generatePkgDriver({ runDriver: (path, [command, ...args], {registryUrl, plugNPlay}) => { @@ -36,5 +42,6 @@ beforeEach(async () => { basicSpecs(pkgDriver); scriptSpecs(pkgDriver); +workspaceSpecs(pkgDriver); pnpSpecs(pkgDriver); dragonSpecs(pkgDriver); From 4b491e0c2d6e230cf85bb8a90894a5efa9503d29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Fri, 16 Mar 2018 14:35:57 +0000 Subject: [PATCH 038/111] Implements Module._findPath Branch: module-findpath --- src/util/generate-pnp-map-api.tpl.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/util/generate-pnp-map-api.tpl.js b/src/util/generate-pnp-map-api.tpl.js index cb942bf772..f55ec79b42 100644 --- a/src/util/generate-pnp-map-api.tpl.js +++ b/src/util/generate-pnp-map-api.tpl.js @@ -313,6 +313,24 @@ exports.setup = function setup() { return exports.resolveRequest(request, issuer); }; + + Module._findPath = function(request, paths, isMain) { + for (const path of paths) { + let resolution; + + try { + resolution = exports.resolveRequest(request, path); + } catch (error) { + continue; + } + + if (resolution) { + return resolution; + } + } + + return false; + }; }; exports.setupCompatibilityLayer = () => { From b8e3b403befe95765f072c04cd159543cabc20ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Fri, 16 Mar 2018 17:29:18 +0000 Subject: [PATCH 039/111] Fixes top level detection Branch: fix-top-level-detection --- src/util/generate-pnp-map-api.tpl.js | 4 +++- src/util/generate-pnp-map.js | 16 +++++++++++----- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/util/generate-pnp-map-api.tpl.js b/src/util/generate-pnp-map-api.tpl.js index f55ec79b42..50255bdfe2 100644 --- a/src/util/generate-pnp-map-api.tpl.js +++ b/src/util/generate-pnp-map-api.tpl.js @@ -1,5 +1,5 @@ /* eslint-disable max-len, flowtype/require-valid-file-annotation, flowtype/require-return-type */ -/* global packageInformationStores */ +/* global packageInformationStores, $$SETUP_STATIC_TABLES */ const fs = require('fs'); const Module = require('module'); @@ -17,6 +17,8 @@ const topLevelLocator = {name: null, reference: null}; const moduleShims = new Map(); const moduleCache = new Map(); +$$SETUP_STATIC_TABLES(); + /** * Returns information about a package in a safe way (will throw if they cannot be retrieved) */ diff --git a/src/util/generate-pnp-map.js b/src/util/generate-pnp-map.js index 6a44b8258b..7fa3e99613 100644 --- a/src/util/generate-pnp-map.js +++ b/src/util/generate-pnp-map.js @@ -50,10 +50,14 @@ function generateMaps(packageInformationStores: PackageInformationStores): strin code += `let locatorsByLocations = new Map([\n`; for (const [packageName, packageInformationStore] of packageInformationStores) { for (const [packageReference, {packageLocation}] of packageInformationStore) { - code += ` [${JSON.stringify(packageLocation)}, ${JSON.stringify({ - name: packageName, - reference: packageReference, - })}],\n`; + if (packageName !== null) { + code += ` [${JSON.stringify(packageLocation)}, ${JSON.stringify({ + name: packageName, + reference: packageReference, + })}],\n`; + } else { + code += ` [${JSON.stringify(packageLocation)}, topLevelLocator],\n`; + } } } code += `]);\n`; @@ -264,6 +268,8 @@ export async function generatePnpMap( {resolver}: {resolver: PackageResolver}, ): Promise { const packageInformationStores = await getPackageInformationStores(config, seedPatterns, {resolver}); + const setupStaticTables = + generateMaps(packageInformationStores) + generateFindPackageLocator(packageInformationStores); - return generateMaps(packageInformationStores) + generateFindPackageLocator(packageInformationStores) + pnpApi; + return pnpApi.replace(/\$\$SETUP_STATIC_TABLES\(\);/, setupStaticTables); } From 91a205076566db5f12924d46b24aa3e0fe319414 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Wed, 21 Mar 2018 13:41:49 +0000 Subject: [PATCH 040/111] Implements workspaces support in pnp Branch: pnp-workspaces --- .../pkg-tests-specs/sources/workspace.js | 12 +++- src/cli/commands/install.js | 5 +- src/util/generate-pnp-map.js | 64 ++++++++++++++++--- 3 files changed, 69 insertions(+), 12 deletions(-) diff --git a/packages/pkg-tests/pkg-tests-specs/sources/workspace.js b/packages/pkg-tests/pkg-tests-specs/sources/workspace.js index ef67a37341..75ff6d05f3 100644 --- a/packages/pkg-tests/pkg-tests-specs/sources/workspace.js +++ b/packages/pkg-tests/pkg-tests-specs/sources/workspace.js @@ -7,11 +7,14 @@ const {fs: {writeFile, writeJson}} = require('pkg-tests-core'); module.exports = (makeTemporaryEnv: PackageDriver) => { describe(`Workspaces tests`, () => { test( - `it should make workspaces require-able from the top-level`, + `it should make workspaces require-able from the top-level when declared as dependency`, makeTemporaryEnv( { private: true, workspaces: [`packages/*`], + dependencies: { + [`workspace-a`]: `1.0.0` + } }, async ({path, run, source}) => { await writeJson(`${path}/packages/workspace-a/package.json`, { @@ -39,6 +42,10 @@ module.exports = (makeTemporaryEnv: PackageDriver) => { { private: true, workspaces: [`packages/*`], + dependencies: { + [`workspace-a`]: `1.0.0`, + [`workspace-b`]: `1.0.0`, + } }, async ({path, run, source}) => { await writeJson(`${path}/packages/workspace-a/package.json`, { @@ -90,6 +97,9 @@ module.exports = (makeTemporaryEnv: PackageDriver) => { { private: true, workspaces: [`packages/*`], + dependencies: { + [`workspace`]: `1.0.0`, + } }, async ({path, run, source}) => { await writeJson(`${path}/packages/workspace/package.json`, { diff --git a/src/cli/commands/install.js b/src/cli/commands/install.js index 25897bd93c..81d43c0f49 100644 --- a/src/cli/commands/install.js +++ b/src/cli/commands/install.js @@ -579,7 +579,10 @@ export class Install { if (this.config.plugnplayEnabled) { steps.push((curr: number, total: number) => callThroughHook('pnpStep', async () => { - const code = await generatePnpMap(this.config, flattenedTopLevelPatterns, {resolver: this.resolver}); + const code = await generatePnpMap(this.config, flattenedTopLevelPatterns, { + resolver: this.resolver, + workspaceLayout, + }); await fs.writeFile(`${this.config.lockfileFolder}/${constants.PNP_FILENAME}`, code); }), ); diff --git a/src/util/generate-pnp-map.js b/src/util/generate-pnp-map.js index 7fa3e99613..4184b02429 100644 --- a/src/util/generate-pnp-map.js +++ b/src/util/generate-pnp-map.js @@ -1,6 +1,7 @@ // @flow import type Config from '../config.js'; +import type WorkspaceLayout from '../workspace-layout.js'; import type PackageResolver from '../package-resolver.js'; import pnpApi from './generate-pnp-map-api.tpl.js'; import * as fs from './fs.js'; @@ -14,9 +15,15 @@ type PackageInformation = {| packageMainEntry: ?string, packageDependencies: Map, |}; + type PackageInformationStore = Map; type PackageInformationStores = Map; +type GeneratePnpMapOptions = {| + resolver: PackageResolver, + workspaceLayout: ?WorkspaceLayout, +|}; + function generateMaps(packageInformationStores: PackageInformationStores): string { let code = ``; @@ -105,10 +112,14 @@ function generateFindPackageLocator(packageInformationStores: PackageInformation async function getPackageInformationStores( config: Config, seedPatterns: Array, - {resolver}: {resolver: PackageResolver}, + {resolver, workspaceLayout}: GeneratePnpMapOptions, ): Promise { const packageInformationStores: PackageInformationStores = new Map(); + const ensureTrailingSlash = (fsPath: string) => { + return fsPath.replace(/[\\\/]?$/, path.sep); + }; + const getHashFrom = (data: Array) => { const hashGenerator = crypto.createHash('sha1'); @@ -136,11 +147,7 @@ async function getPackageInformationStores( return {pkg, ref, loc}; }; - const visit = async ( - seedPatterns: Array, - parentData: Array = [], - availablePackages: Map = new Map(), - ) => { + const visit = async (seedPatterns: Array, parentData: Array = []) => { const resolutions = new Map(); const locations = new Map(); @@ -217,7 +224,7 @@ async function getPackageInformationStores( packageInformation = { packageMainEntry: pkg.main, - packageLocation: loc.replace(/[\\\/]?$/, path.sep), + packageLocation: ensureTrailingSlash(loc), packageDependencies: new Map(), }; @@ -245,6 +252,43 @@ async function getPackageInformationStores( return resolutions; }; + // If we have workspaces, we need to iterate over them all in order to add them to the map + // This is because they might not be declared as dependencies of the top-level project (and with reason, since the + // top-level package might depend on a different than the one provided in the workspaces - cf Babel, which depends + // on an old version of itself in order to compile itself) + if (workspaceLayout) { + for (const name of Object.keys(workspaceLayout.workspaces)) { + const pkg = workspaceLayout.workspaces[name].manifest; + + // Skip the aggregator, since it's essentially a duplicate of the top-level package that we'll iterate later on + if (pkg.workspaces) { + continue; + } + + const ref = pkg._reference; + invariant(ref, `Workspaces should have a reference`); + + const loc = ref.location; + invariant(loc, `Workspaces should have a location`); + + packageInformationStores.set( + name, + new Map([ + [ + pkg.version, + { + packageMainEntry: pkg.main, + packageLocation: ensureTrailingSlash(await fs.realpath(loc)), + packageDependencies: await visit(ref.dependencies, [name, pkg.version]), + }, + ], + ]), + ); + } + } + + // Register the top-level package in our map + // This will recurse on each of its dependencies as well. packageInformationStores.set( null, new Map([ @@ -252,7 +296,7 @@ async function getPackageInformationStores( null, { packageMainEntry: null, - packageLocation: (await fs.realpath(config.lockfileFolder)).replace(/[\\\/]?$/, path.sep), + packageLocation: ensureTrailingSlash(await fs.realpath(config.lockfileFolder)), packageDependencies: await visit(seedPatterns), }, ], @@ -265,9 +309,9 @@ async function getPackageInformationStores( export async function generatePnpMap( config: Config, seedPatterns: Array, - {resolver}: {resolver: PackageResolver}, + {resolver, workspaceLayout}: GeneratePnpMapOptions, ): Promise { - const packageInformationStores = await getPackageInformationStores(config, seedPatterns, {resolver}); + const packageInformationStores = await getPackageInformationStores(config, seedPatterns, {resolver, workspaceLayout}); const setupStaticTables = generateMaps(packageInformationStores) + generateFindPackageLocator(packageInformationStores); From 82e00e6aa05c637b1086593314f714465fe78224 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Fri, 23 Mar 2018 19:25:39 +0000 Subject: [PATCH 041/111] Automatically adds workspaces as dependencies of the top-level Branch: auto-workspace-dependencies --- .../pkg-tests-specs/sources/workspace.js | 5 +---- src/cli/commands/install.js | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/packages/pkg-tests/pkg-tests-specs/sources/workspace.js b/packages/pkg-tests/pkg-tests-specs/sources/workspace.js index 75ff6d05f3..734935a71c 100644 --- a/packages/pkg-tests/pkg-tests-specs/sources/workspace.js +++ b/packages/pkg-tests/pkg-tests-specs/sources/workspace.js @@ -7,14 +7,11 @@ const {fs: {writeFile, writeJson}} = require('pkg-tests-core'); module.exports = (makeTemporaryEnv: PackageDriver) => { describe(`Workspaces tests`, () => { test( - `it should make workspaces require-able from the top-level when declared as dependency`, + `it should implicitely make workspaces require-able from the top-level`, makeTemporaryEnv( { private: true, workspaces: [`packages/*`], - dependencies: { - [`workspace-a`]: `1.0.0` - } }, async ({path, run, source}) => { await writeJson(`${path}/packages/workspace-a/package.json`, { diff --git a/src/cli/commands/install.js b/src/cli/commands/install.js index 81d43c0f49..9084d8ce02 100644 --- a/src/cli/commands/install.js +++ b/src/cli/commands/install.js @@ -373,6 +373,21 @@ export class Install { stripExcluded(cwdIsRoot ? virtualDependencyManifest : workspaces[projectManifestJson.name].manifest); pushDeps('workspaces', {workspaces: virtualDep}, {hint: 'workspaces', optional: false}, true); + + const implicitWorkspaceDependencies = {...workspaceDependencies}; + + for (const type of constants.OWNED_DEPENDENCY_TYPES) { + for (const dependencyName of Object.keys(projectManifestJson[type] || {})) { + delete implicitWorkspaceDependencies[dependencyName]; + } + } + + pushDeps( + 'dependencies', + {dependencies: implicitWorkspaceDependencies}, + {hint: 'workspaces', optional: false}, + true, + ); } break; From fd745e78bf7de69cc24f64dbeaadd6a1664d8022 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Fri, 23 Mar 2018 19:26:36 +0000 Subject: [PATCH 042/111] Updates the cache path to include the 'node_modules' string Branch: node-modules-cache --- __tests__/commands/install/integration.js | 12 +++++++++--- __tests__/integration.js | 4 ++-- __tests__/lifecycle-scripts.js | 10 +++++----- src/config.js | 2 +- 4 files changed, 17 insertions(+), 11 deletions(-) diff --git a/__tests__/commands/install/integration.js b/__tests__/commands/install/integration.js index 8f5092ee83..668b8dae8f 100644 --- a/__tests__/commands/install/integration.js +++ b/__tests__/commands/install/integration.js @@ -240,11 +240,11 @@ test('changes the cache path when bumping the cache version', async () => { const reporter = new reporters.JSONReporter({stdout: inOut}); await cache(config, reporter, {}, ['dir']); - expect((JSON.parse(String(inOut.read())): any).data).toMatch(/[\\\/]v[0-9][\\\/]?$/); + expect((JSON.parse(String(inOut.read())): any).data).toMatch(/[\\\/]v[0-9]([\\\/].*)?$/); await mockConstants(config, {CACHE_VERSION: 42}, async (config): Promise => { await cache(config, reporter, {}, ['dir']); - expect((JSON.parse(String(inOut.read())): any).data).toMatch(/[\\\/]v42[\\\/]?$/); + expect((JSON.parse(String(inOut.read())): any).data).toMatch(/[\\\/]v42([\\\/].*)?$/); }); }); }); @@ -684,7 +684,13 @@ test.concurrent('install should update checksums in yarn.lock (--update-checksum const lockFileLines = explodeLockfile(lockFileContent); const packageHashInLockfile = lockFileLines[2].replace(/(^.*#)|("$)/g, ''); const installedPackageJson = path.resolve(config.cwd, 'node_modules', 'abab', 'package.json'); - const cachePackageJson = path.resolve(config.cwd, '.yarn-cache/v2/', packageCacheName, 'package.json'); + const cachePackageJson = path.resolve( + config.cwd, + '.yarn-cache/v2/', + 'node_modules', + packageCacheName, + 'package.json', + ); expect(packageHashInLockfile).toEqual(packageRealHash); expect(await fs.exists(installedPackageJson)).toBe(true); expect(await fs.exists(cachePackageJson)).toBe(true); diff --git a/__tests__/integration.js b/__tests__/integration.js index 666dfeab81..bd0764c0bc 100644 --- a/__tests__/integration.js +++ b/__tests__/integration.js @@ -373,7 +373,7 @@ test('cache folder fallback', async () => { const [stdoutOutput, stderrOutput] = await runCacheDir(); - expect(stdoutOutput.toString().trim()).toEqual(path.join(cacheFolder, `v${constants.CACHE_VERSION}`)); + expect(stdoutOutput.toString().trim()).toEqual(path.join(cacheFolder, `v${constants.CACHE_VERSION}`, `node_modules`)); expect(stderrOutput.toString()).not.toMatch(/Skipping preferred cache folder/); await fs.unlink(cacheFolder); @@ -382,7 +382,7 @@ test('cache folder fallback', async () => { const [stdoutOutput2, stderrOutput2] = await runCacheDir(); expect(stdoutOutput2.toString().trim()).toEqual( - path.join(constants.PREFERRED_MODULE_CACHE_DIRECTORIES[0], `v${constants.CACHE_VERSION}`), + path.join(constants.PREFERRED_MODULE_CACHE_DIRECTORIES[0], `v${constants.CACHE_VERSION}`, 'node_modules'), ); expect(stderrOutput2.toString()).toMatch(/Skipping preferred cache folder/); }); diff --git a/__tests__/lifecycle-scripts.js b/__tests__/lifecycle-scripts.js index 8f6660ef57..56be8ff46f 100644 --- a/__tests__/lifecycle-scripts.js +++ b/__tests__/lifecycle-scripts.js @@ -42,31 +42,31 @@ async function execCommand(cmd: string, packageName: string, env = process.env): test.concurrent('should add the global yarnrc arguments to the command line', async () => { const stdout = await execCommand('cache dir', 'yarnrc-cli'); - expect(stdout.replace(/\\/g, '/')).toMatch(/^(C:)?\/tmp\/foobar\/v[0-9]+\n$/); + expect(stdout.replace(/\\/g, '/')).toMatch(/^(C:)?\/tmp\/foobar\/v[0-9]+(\/.*)?\n$/); }); test.concurrent( 'should add the command-specific yarnrc arguments to the command line if the command name matches', async () => { const stdout = await execCommand('cache dir', 'yarnrc-cli-command-specific-ok'); - expect(stdout.replace(/\\/g, '/')).toMatch(/^(C:)?\/tmp\/foobar\/v[0-9]+\n$/); + expect(stdout.replace(/\\/g, '/')).toMatch(/^(C:)?\/tmp\/foobar\/v[0-9]+(\/.*)?\n$/); }, ); test.concurrent("should not add the command-specific yarnrc arguments if the command name doesn't match", async () => { const stdout = await execCommand('cache dir', 'yarnrc-cli-command-specific-ko'); - expect(stdout.replace(/\\/g, '/')).not.toMatch(/^(C:)?\/tmp\/foobar\/v[0-9]+\n$/); + expect(stdout.replace(/\\/g, '/')).not.toMatch(/^(C:)?\/tmp\/foobar\/v[0-9]+(\/.*)?\n$/); }); test.concurrent('should allow overriding the yarnrc values from the command line', async () => { const stdout = await execCommand('cache dir --cache-folder /tmp/toto', 'yarnrc-cli'); - expect(stdout.replace(/\\/g, '/')).toMatch(/^(C:)?\/tmp\/toto\/v[0-9]+\n$/); + expect(stdout.replace(/\\/g, '/')).toMatch(/^(C:)?\/tmp\/toto\/v[0-9]+(\/.*)?\n$/); }); // Test disabled for now, cf rc.js test.concurrent('should resolve the yarnrc values relative to where the file lives', async () => { const stdout = await execCommand('cache dir', 'yarnrc-cli-relative'); - expect(stdout.replace(/\\/g, '/')).toMatch(/^(C:)?(\/[^\/]+)+\/foobar\/hello\/world\/v[0-9]+\n$/); + expect(stdout.replace(/\\/g, '/')).toMatch(/^(C:)?(\/[^\/]+)+\/foobar\/hello\/world\/v[0-9]+(\/.*)?\n$/); }); test.concurrent( diff --git a/src/config.js b/src/config.js index 8ab8f25cbc..cd9f532472 100644 --- a/src/config.js +++ b/src/config.js @@ -337,7 +337,7 @@ export default class Config { this.packBuiltPackages = Boolean(this.getOption('experimental-pack-script-packages-in-mirror')); //init & create cacheFolder, tempFolder - this.cacheFolder = path.join(this._cacheRootFolder, 'v' + String(constants.CACHE_VERSION)); + this.cacheFolder = path.join(this._cacheRootFolder, 'v' + String(constants.CACHE_VERSION), 'node_modules'); this.tempFolder = opts.tempFolder || path.join(this.cacheFolder, '.tmp'); await fs.mkdirp(this.cacheFolder); await fs.mkdirp(this.tempFolder); From ff45d9a5c788f9e565165590878e929112529ab6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Fri, 23 Mar 2018 19:33:43 +0000 Subject: [PATCH 043/111] Prevents pnp from bootstrapping when running non-pnp-installed scripts Branch: fix-npm-run --- .../pkg-tests/pkg-tests-specs/sources/pnp.js | 22 ++++++++++- .../pkg-tests-specs/sources/workspace.js | 4 +- src/util/generate-pnp-map-api.tpl.js | 37 ++++++++++++------- 3 files changed, 47 insertions(+), 16 deletions(-) diff --git a/packages/pkg-tests/pkg-tests-specs/sources/pnp.js b/packages/pkg-tests/pkg-tests-specs/sources/pnp.js index 045a9c5da8..69e3ed49ea 100644 --- a/packages/pkg-tests/pkg-tests-specs/sources/pnp.js +++ b/packages/pkg-tests/pkg-tests-specs/sources/pnp.js @@ -1,4 +1,4 @@ -const {fs: {writeFile, writeJson}, tests: {getPackageDirectoryPath}} = require('pkg-tests-core'); +const {fs: {createTemporaryFolder, writeFile, writeJson}, tests: {getPackageDirectoryPath}} = require('pkg-tests-core'); module.exports = makeTemporaryEnv => { const {basic: basicSpecs, script: scriptSpecs, workspace: workspaceSpecs} = require('pkg-tests-specs'); @@ -335,4 +335,24 @@ module.exports = makeTemporaryEnv => { ), ); }); + + test( + `it should not setup pnp when calling a script outside of the install tree`, + makeTemporaryEnv( + {}, + { + plugNPlay: true, + }, + async ({path, run, source}) => { + await run(`install`); + + const tmp = await createTemporaryFolder(); + + await writeFile(`${tmp}/node_modules/dep/index.js`, `module.exports = 42;`); + await writeFile(`${tmp}/index.js`, `require('dep')`); + + await run(`node`, `${tmp}/index.js`); + }, + ), + ); }; diff --git a/packages/pkg-tests/pkg-tests-specs/sources/workspace.js b/packages/pkg-tests/pkg-tests-specs/sources/workspace.js index 734935a71c..c356c0154d 100644 --- a/packages/pkg-tests/pkg-tests-specs/sources/workspace.js +++ b/packages/pkg-tests/pkg-tests-specs/sources/workspace.js @@ -42,7 +42,7 @@ module.exports = (makeTemporaryEnv: PackageDriver) => { dependencies: { [`workspace-a`]: `1.0.0`, [`workspace-b`]: `1.0.0`, - } + }, }, async ({path, run, source}) => { await writeJson(`${path}/packages/workspace-a/package.json`, { @@ -96,7 +96,7 @@ module.exports = (makeTemporaryEnv: PackageDriver) => { workspaces: [`packages/*`], dependencies: { [`workspace`]: `1.0.0`, - } + }, }, async ({path, run, source}) => { await writeJson(`${path}/packages/workspace/package.json`, { diff --git a/src/util/generate-pnp-map-api.tpl.js b/src/util/generate-pnp-map-api.tpl.js index 50255bdfe2..00131a79a4 100644 --- a/src/util/generate-pnp-map-api.tpl.js +++ b/src/util/generate-pnp-map-api.tpl.js @@ -19,6 +19,21 @@ const moduleCache = new Map(); $$SETUP_STATIC_TABLES(); +/** + * Returns the module that should be used to resolve require calls. It's usually the direct parent, except if we're + * inside an eval expression. + */ + +function getIssuerModule(parent) { + let issuer = parent; + + while (issuer && (issuer.id === '[eval]' || issuer.id === '' || !issuer.filename)) { + issuer = issuer.parent; + } + + return issuer; +} + /** * Returns information about a package in a safe way (will throw if they cannot be retrieved) */ @@ -244,16 +259,6 @@ exports.resolveRequest = function resolveRequest(request, issuer) { */ exports.setup = function setup() { - function getIssuer(parent) { - let issuer = parent; - - while (issuer && (issuer.id === '[eval]' || issuer.id === '' || !issuer.filename)) { - issuer = issuer.parent; - } - - return issuer; - } - Module._load = function(request, parent, isMain) { // Builtins are managed by the regular Node loader @@ -310,7 +315,7 @@ exports.setup = function setup() { }; Module._resolveFilename = function(request, parent, isMain, options) { - const issuerModule = getIssuer(parent); + const issuerModule = getIssuerModule(parent); const issuer = issuerModule ? issuerModule.filename : process.cwd() + path.sep; return exports.resolveRequest(request, issuer); @@ -388,6 +393,12 @@ exports.setupCompatibilityLayer = () => { }; if (module.parent && module.parent.id === 'internal/preload') { - exports.setup(); - exports.setupCompatibilityLayer(); + const issuerPath = process.argv[1] || process.cwd() + path.sep; + const issuerLocator = exports.findPackageLocator(issuerPath); + + // We don't want to boot pnp if the script being run isn't part of the project we've installed + if (issuerLocator) { + exports.setup(); + exports.setupCompatibilityLayer(); + } } From bf2a116b35e8838972d24605c7b5403744e9188c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Fri, 23 Mar 2018 19:35:05 +0000 Subject: [PATCH 044/111] Installs peer dependencies symlinks inside a project folder Branch: per-project-virtual-deps --- src/util/generate-pnp-map.js | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/util/generate-pnp-map.js b/src/util/generate-pnp-map.js index 4184b02429..f293b746e4 100644 --- a/src/util/generate-pnp-map.js +++ b/src/util/generate-pnp-map.js @@ -161,7 +161,7 @@ async function getPackageInformationStores( continue; } - const {pkg} = entry; + const {pkg, ref} = entry; let {loc} = entry; const packageName = pkg.name; @@ -176,9 +176,16 @@ async function getPackageInformationStores( if (peerDependencies.size > 0) { const hash = getHashFrom([...parentData, packageName, packageReference]); - const newLoc = path.resolve(path.dirname(loc), `pnp-${hash}`); - await fs.symlink(loc, newLoc); - loc = newLoc; + const newLocDir = + ref.remote.type !== 'workspace' + ? path.resolve(config.lockfileFolder, '.pnp', 'global', 'node_modules') + : path.resolve(config.lockfileFolder, '.pnp', 'local'); + + const physicalLoc = loc; + const virtualLoc = (loc = path.resolve(newLocDir, `pnp-${hash}`)); + + await fs.mkdirp(path.dirname(virtualLoc)); + await fs.symlink(physicalLoc, virtualLoc); packageReference = `pnp:${hash}`; } From b1d59c1830ff0344536a94b6aada903431e5255e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Wed, 4 Apr 2018 16:43:57 +0100 Subject: [PATCH 045/111] Adds a sample application that showcases webpack, babel, react, jest Branch: sample-app --- pnp-env/.babelrc | 11 + pnp-env/.gitignore | 3 +- pnp-env/jest.config.js | 4 + pnp-env/package.json | 21 +- pnp-env/scripts/jest-resolver.js | 5 + pnp-env/scripts/webpack-resolver.js | 35 + pnp-env/sources/__tests__/fibonacci.js | 36 + pnp-env/sources/fibonacci.js | 22 + pnp-env/sources/index.js | 38 + pnp-env/webpack.config.js | 41 + pnp-env/yarn.lock | 4243 ++++++++++++++++++++++-- 11 files changed, 4125 insertions(+), 334 deletions(-) create mode 100644 pnp-env/.babelrc create mode 100644 pnp-env/jest.config.js create mode 100644 pnp-env/scripts/jest-resolver.js create mode 100644 pnp-env/scripts/webpack-resolver.js create mode 100644 pnp-env/sources/__tests__/fibonacci.js create mode 100644 pnp-env/sources/fibonacci.js create mode 100644 pnp-env/sources/index.js create mode 100644 pnp-env/webpack.config.js diff --git a/pnp-env/.babelrc b/pnp-env/.babelrc new file mode 100644 index 0000000000..e40a7275b0 --- /dev/null +++ b/pnp-env/.babelrc @@ -0,0 +1,11 @@ +{ + "presets": ["react", ["env", { + "targets": { + "browsers": ["last 2 versions"] + } + }]], + "plugins": [ + "transform-class-properties", + "transform-decorators-legacy" + ] +} diff --git a/pnp-env/.gitignore b/pnp-env/.gitignore index 4f513c2e2c..ede4892698 100644 --- a/pnp-env/.gitignore +++ b/pnp-env/.gitignore @@ -1,3 +1,4 @@ +dist node_modules yarn-error.log -.pnp.js +.pnp* diff --git a/pnp-env/jest.config.js b/pnp-env/jest.config.js new file mode 100644 index 0000000000..9553f3c51b --- /dev/null +++ b/pnp-env/jest.config.js @@ -0,0 +1,4 @@ +module.exports = { + transform: { [`^.+\\.js$`]: require.resolve('babel-jest') }, + resolver: './scripts/jest-resolver', +}; diff --git a/pnp-env/package.json b/pnp-env/package.json index 803ca5078d..da7a71a02b 100644 --- a/pnp-env/package.json +++ b/pnp-env/package.json @@ -1,10 +1,23 @@ { "dependencies": { - "babel-core": "^6.26.0", - "babel-preset-env": "^1.6.1", + "core-decorators": "^0.20.0", "lodash": "^4.17.5", "react": "^16.2.0", - "react-dom": "^16.2.0", - "webpack": "^3.11.0" + "react-dom": "^16.2.0" + }, + "devDependencies": { + "babel-core": "^6.4.1", + "babel-jest": "^22.4.3", + "babel-loader": "^7.1.4", + "babel-plugin-transform-class-properties": "^6.24.1", + "babel-plugin-transform-decorators-legacy": "^1.3.4", + "babel-preset-env": "^1.6.1", + "babel-preset-react": "^6.24.1", + "html-webpack-plugin": "^3.1.0", + "http-server": "^0.11.1", + "jest": "^22.4.3", + "jest-environment-jsdom": "^22.4.3", + "webpack": "^4.4.1", + "webpack-cli": "^2.0.13" } } diff --git a/pnp-env/scripts/jest-resolver.js b/pnp-env/scripts/jest-resolver.js new file mode 100644 index 0000000000..a70dc9c755 --- /dev/null +++ b/pnp-env/scripts/jest-resolver.js @@ -0,0 +1,5 @@ +let pnp = require('../.pnp.js'); + +module.exports = (request, {basedir}) => { + return pnp.resolveRequest(request, `${basedir}/`); +}; diff --git a/pnp-env/scripts/webpack-resolver.js b/pnp-env/scripts/webpack-resolver.js new file mode 100644 index 0000000000..9745ed55bb --- /dev/null +++ b/pnp-env/scripts/webpack-resolver.js @@ -0,0 +1,35 @@ +const pnp = require(`../.pnp.js`); + +module.exports = { + apply: function(resolver) { + const resolvedHook = resolver.ensureHook(`resolved`); + resolver.getHook(`resolve`).tapAsync(`PnpResolver`, (request, resolveContext, callback) => { + if (request.context.issuer === undefined) { + return callback(); + } + + let issuer; + let resolution; + + if (!request.context.issuer) { + issuer = `${request.path}/`; + } else if (request.context.issuer.startsWith(`/`)) { + issuer = request.context.issuer; + } else { + throw new Error(`Cannot successfully resolve this dependency`); + } + + try { + resolution = pnp.resolveRequest(request.request, issuer); + } catch (error) { + // TODO This is not good! But the `debug` package tries to require `supports-color` without declaring it in its + // package.json, and Webpack accepts this because it`s in a try/catch, so we need to do it as well. + return callback(error); + } + + resolver.doResolve(resolvedHook, Object.assign({}, request, { + path: resolution, + }), null, resolveContext, callback); + }); + } +}; diff --git a/pnp-env/sources/__tests__/fibonacci.js b/pnp-env/sources/__tests__/fibonacci.js new file mode 100644 index 0000000000..27bcf6a1c8 --- /dev/null +++ b/pnp-env/sources/__tests__/fibonacci.js @@ -0,0 +1,36 @@ +import { fibonacci } from '../fibonacci'; + +describe(`fibonacci`, () => { + it(`should work for negative values`, () => { + expect(fibonacci(-10)).toEqual(-55); + expect(fibonacci(-9)).toEqual(34); + expect(fibonacci(-8)).toEqual(-21); + expect(fibonacci(-7)).toEqual(13); + expect(fibonacci(-6)).toEqual(-8); + expect(fibonacci(-5)).toEqual(5); + expect(fibonacci(-4)).toEqual(-3); + expect(fibonacci(-3)).toEqual(2); + expect(fibonacci(-2)).toEqual(-1); + expect(fibonacci(-1)).toEqual(1); + }); + + it(`should work for zero values`, () => { + expect(fibonacci(-0)).toEqual(0); + expect(fibonacci(+0)).toEqual(0); + }); + + it(`should work for positive values`, () => { + expect(fibonacci(+1)).toEqual(1); + expect(fibonacci(+2)).toEqual(1); + expect(fibonacci(+5)).toEqual(5); + expect(fibonacci(+10)).toEqual(55); + }); + + it(`should return -Infinity for -Infinity`, () => { + expect(fibonacci(-Infinity)).toEqual(-Infinity); + }); + + it(`should return +Infinity for +Infinity`, () => { + expect(fibonacci(+Infinity)).toEqual(+Infinity); + }); +}); diff --git a/pnp-env/sources/fibonacci.js b/pnp-env/sources/fibonacci.js new file mode 100644 index 0000000000..ca5bb4d07f --- /dev/null +++ b/pnp-env/sources/fibonacci.js @@ -0,0 +1,22 @@ +export function fibonacci(n) { + + if (n === -Infinity) + return -Infinity; + + if (n === +Infinity) + return +Infinity; + + if (n === 0) + return 0; + + let A = (1 + Math.sqrt(5)) / 2; + let B = (1 - Math.sqrt(5)) / 2; + + let res = Math.ceil((Math.pow(A, n) - Math.pow(B, n)) / Math.sqrt(5)); + + if (res <= 0) + res -= 1; + + return res; + +} diff --git a/pnp-env/sources/index.js b/pnp-env/sources/index.js new file mode 100644 index 0000000000..63e4606380 --- /dev/null +++ b/pnp-env/sources/index.js @@ -0,0 +1,38 @@ +import { autobind } from 'core-decorators'; +import React from 'react'; +import ReactDOM from 'react-dom'; + +import { fibonacci } from './fibonacci'; + +class Application extends React.PureComponent { + + state = { + n: `1`, + }; + + @autobind handleChange(e) { + + this.setState({ + n: e.target.value, + }); + + } + + render() { + + return

; + + } + +} + +ReactDOM.render(, document.body); diff --git a/pnp-env/webpack.config.js b/pnp-env/webpack.config.js new file mode 100644 index 0000000000..219dc6c0c5 --- /dev/null +++ b/pnp-env/webpack.config.js @@ -0,0 +1,41 @@ +const HtmlWebpackPlugin = require(`html-webpack-plugin`); +const PnpWebpackPlugin = require(`./scripts/webpack-resolver`); + +module.exports = { + + mode: `production`, + + entry: { + [`app`]: `./sources/index.js`, + }, + + output: { + filename: `[name].js`, + }, + + module: { + rules: [{ + test: /\.js$/, + exclude: /node_modules/, + loader: require.resolve('babel-loader'), + options: {}, + }] + }, + + resolve: { + plugins: [ + PnpWebpackPlugin, + ] + }, + + resolveLoader: { + plugins: [ + PnpWebpackPlugin, + ] + }, + + plugins: [ + new HtmlWebpackPlugin() + ] + +}; diff --git a/pnp-env/yarn.lock b/pnp-env/yarn.lock index 6eddbcf761..e60f8bfb3b 100644 --- a/pnp-env/yarn.lock +++ b/pnp-env/yarn.lock @@ -2,23 +2,47 @@ # yarn lockfile v1 +"@babel/code-frame@^7.0.0-beta.35": + version "7.0.0-beta.42" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0-beta.42.tgz#a9c83233fa7cd06b39dc77adbb908616ff4f1962" + dependencies: + "@babel/highlight" "7.0.0-beta.42" + +"@babel/highlight@7.0.0-beta.42": + version "7.0.0-beta.42" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.0.0-beta.42.tgz#a502a1c0d6f99b2b0e81d468a1b0c0e81e3f3623" + dependencies: + chalk "^2.0.0" + esutils "^2.0.2" + js-tokens "^3.0.0" + +"@sindresorhus/is@^0.7.0": + version "0.7.0" + resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.7.0.tgz#9a06f4f137ee84d7df0460c1fdb1135ffa6c50fd" + +abab@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/abab/-/abab-1.0.4.tgz#5faad9c2c07f60dd76770f71cf025b62a63cfd4e" + abbrev@1: version "1.1.1" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" -acorn-dynamic-import@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/acorn-dynamic-import/-/acorn-dynamic-import-2.0.2.tgz#c752bd210bef679501b6c6cb7fc84f8f47158cc4" +acorn-dynamic-import@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/acorn-dynamic-import/-/acorn-dynamic-import-3.0.0.tgz#901ceee4c7faaef7e07ad2a47e890675da50a278" dependencies: - acorn "^4.0.3" + acorn "^5.0.0" -acorn@^4.0.3: - version "4.0.13" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.13.tgz#105495ae5361d697bd195c825192e1ad7f253787" +acorn-globals@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-4.1.0.tgz#ab716025dbe17c54d3ef81d32ece2b2d99fe2538" + dependencies: + acorn "^5.0.0" -acorn@^5.0.0: - version "5.4.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.4.1.tgz#fdc58d9d17f4a4e98d102ded826a9b9759125102" +acorn@^5.0.0, acorn@^5.3.0: + version "5.5.3" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.5.3.tgz#f473dd47e0277a08e28e9bec5aeeb04751f0b8c9" ajv-keywords@^3.1.0: version "3.1.0" @@ -31,13 +55,23 @@ ajv@^4.9.1: co "^4.6.0" json-stable-stringify "^1.0.1" +ajv@^5.1.0: + version "5.5.2" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965" + dependencies: + co "^4.6.0" + fast-deep-equal "^1.0.0" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.3.0" + ajv@^6.1.0: - version "6.1.1" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.1.1.tgz#978d597fbc2b7d0e5a5c3ddeb149a682f2abfa0e" + version "6.4.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.4.0.tgz#d3aff78e9277549771daf0164cff48482b754fc6" dependencies: fast-deep-equal "^1.0.0" fast-json-stable-stringify "^2.0.0" json-schema-traverse "^0.3.0" + uri-js "^3.0.2" align-text@^0.1.1, align-text@^0.1.3: version "0.1.4" @@ -47,6 +81,18 @@ align-text@^0.1.1, align-text@^0.1.3: longest "^1.0.1" repeat-string "^1.5.2" +amdefine@>=0.0.4: + version "1.0.1" + resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" + +ansi-escapes@^1.0.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" + +ansi-escapes@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.1.0.tgz#f73207bb81207d75fd6c83f125af26eea378ca30" + ansi-regex@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" @@ -59,14 +105,34 @@ ansi-styles@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" -anymatch@^1.3.0: - version "1.3.2" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.2.tgz#553dcb8f91e3c889845dfdba34c77721b90b9d7a" +ansi-styles@^3.2.0, ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + dependencies: + color-convert "^1.9.0" + +ansi-styles@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-1.0.0.tgz#cb102df1c56f5123eab8b67cd7b98027a0279178" + +any-observable@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/any-observable/-/any-observable-0.2.0.tgz#c67870058003579009083f54ac0abafb5c33d242" + +anymatch@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" + dependencies: + micromatch "^3.1.4" + normalize-path "^2.1.1" + +append-transform@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/append-transform/-/append-transform-0.4.0.tgz#d76ebf8ca94d276e247a36bad44a4b74ab611991" dependencies: - micromatch "^2.1.5" - normalize-path "^2.0.0" + default-require-extensions "^1.0.0" -aproba@^1.0.3: +aproba@^1.0.3, aproba@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" @@ -77,20 +143,60 @@ are-we-there-yet@~1.1.2: delegates "^1.0.0" readable-stream "^2.0.6" +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + dependencies: + sprintf-js "~1.0.2" + arr-diff@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" dependencies: arr-flatten "^1.0.1" -arr-flatten@^1.0.1: +arr-diff@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" + +arr-flatten@^1.0.1, arr-flatten@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" +arr-union@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" + +array-differ@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/array-differ/-/array-differ-1.0.0.tgz#eff52e3758249d33be402b8bb8e564bb2b5d4031" + +array-equal@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93" + +array-union@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" + dependencies: + array-uniq "^1.0.1" + +array-uniq@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" + array-unique@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" +array-unique@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" + +arrify@^1.0.0, arrify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" + asap@~2.0.3: version "2.0.6" resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" @@ -121,11 +227,35 @@ assert@^1.1.1: dependencies: util "0.10.3" +assign-symbols@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" + +ast-types@0.10.1: + version "0.10.1" + resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.10.1.tgz#f52fca9715579a14f841d67d7f8d25432ab6a3dd" + +ast-types@0.11.3: + version "0.11.3" + resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.11.3.tgz#c20757fe72ee71278ea0ff3d87e5c2ca30d9edf8" + +astral-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" + async-each@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" -async@^2.1.2: +async-limiter@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8" + +async@^1.4.0, async@^1.5.0, async@^1.5.2: + version "1.5.2" + resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" + +async@^2.1.4, async@^2.6.0: version "2.6.0" resolved "https://registry.yarnpkg.com/async/-/async-2.6.0.tgz#61a29abb6fcc026fea77e56d1c6ec53a795951f4" dependencies: @@ -135,11 +265,19 @@ asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" +atob@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.0.tgz#ab2b150e51d7b122b9efc8d7340c06b6c41076bc" + aws-sign2@~0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" -aws4@^1.2.1: +aws-sign2@~0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" + +aws4@^1.2.1, aws4@^1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e" @@ -151,7 +289,7 @@ babel-code-frame@^6.26.0: esutils "^2.0.2" js-tokens "^3.0.2" -babel-core@^6.26.0: +babel-core@^6.0.0, babel-core@^6.26.0, babel-core@^6.4.1: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.26.0.tgz#af32f78b31a6fcef119c87b0fd8d9753f03a0bb8" dependencies: @@ -175,7 +313,7 @@ babel-core@^6.26.0: slash "^1.0.0" source-map "^0.5.6" -babel-generator@^6.26.0: +babel-generator@^6.18.0, babel-generator@^6.26.0: version "6.26.1" resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.26.1.tgz#1844408d3b8f0d35a404ea7ac180f087a601bd90" dependencies: @@ -188,6 +326,14 @@ babel-generator@^6.26.0: source-map "^0.5.7" trim-right "^1.0.1" +babel-helper-bindify-decorators@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-bindify-decorators/-/babel-helper-bindify-decorators-6.24.1.tgz#14c19e5f142d7b47f19a52431e52b1ccbc40a330" + dependencies: + babel-runtime "^6.22.0" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + babel-helper-builder-binary-assignment-operator-visitor@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz#cce4517ada356f4220bcae8a02c2b346f9a56664" @@ -196,6 +342,14 @@ babel-helper-builder-binary-assignment-operator-visitor@^6.24.1: babel-runtime "^6.22.0" babel-types "^6.24.1" +babel-helper-builder-react-jsx@^6.24.1: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-helper-builder-react-jsx/-/babel-helper-builder-react-jsx-6.26.0.tgz#39ff8313b75c8b65dceff1f31d383e0ff2a408a0" + dependencies: + babel-runtime "^6.26.0" + babel-types "^6.26.0" + esutils "^2.0.2" + babel-helper-call-delegate@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz#ece6aacddc76e41c3461f88bfc575bd0daa2df8d" @@ -222,6 +376,15 @@ babel-helper-explode-assignable-expression@^6.24.1: babel-traverse "^6.24.1" babel-types "^6.24.1" +babel-helper-explode-class@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-explode-class/-/babel-helper-explode-class-6.24.1.tgz#7dc2a3910dee007056e1e31d640ced3d54eaa9eb" + dependencies: + babel-helper-bindify-decorators "^6.24.1" + babel-runtime "^6.22.0" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + babel-helper-function-name@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz#d3475b8c03ed98242a25b48351ab18399d3580a9" @@ -289,6 +452,21 @@ babel-helpers@^6.24.1: babel-runtime "^6.22.0" babel-template "^6.24.1" +babel-jest@^22.4.3: + version "22.4.3" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-22.4.3.tgz#4b7a0b6041691bbd422ab49b3b73654a49a6627a" + dependencies: + babel-plugin-istanbul "^4.1.5" + babel-preset-jest "^22.4.3" + +babel-loader@^7.1.4: + version "7.1.4" + resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-7.1.4.tgz#e3463938bd4e6d55d1c174c5485d406a188ed015" + dependencies: + find-cache-dir "^1.0.0" + loader-utils "^1.0.2" + mkdirp "^0.5.1" + babel-messages@^6.23.0: version "6.23.0" resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e" @@ -301,19 +479,75 @@ babel-plugin-check-es2015-constants@^6.22.0: dependencies: babel-runtime "^6.22.0" +babel-plugin-istanbul@^4.1.5: + version "4.1.5" + resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-4.1.5.tgz#6760cdd977f411d3e175bb064f2bc327d99b2b6e" + dependencies: + find-up "^2.1.0" + istanbul-lib-instrument "^1.7.5" + test-exclude "^4.1.1" + +babel-plugin-jest-hoist@^22.4.3: + version "22.4.3" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-22.4.3.tgz#7d8bcccadc2667f96a0dcc6afe1891875ee6c14a" + babel-plugin-syntax-async-functions@^6.8.0: version "6.13.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95" +babel-plugin-syntax-async-generators@^6.5.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-generators/-/babel-plugin-syntax-async-generators-6.13.0.tgz#6bc963ebb16eccbae6b92b596eb7f35c342a8b9a" + +babel-plugin-syntax-class-constructor-call@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-class-constructor-call/-/babel-plugin-syntax-class-constructor-call-6.18.0.tgz#9cb9d39fe43c8600bec8146456ddcbd4e1a76416" + +babel-plugin-syntax-class-properties@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz#d7eb23b79a317f8543962c505b827c7d6cac27de" + +babel-plugin-syntax-decorators@^6.1.18, babel-plugin-syntax-decorators@^6.13.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-decorators/-/babel-plugin-syntax-decorators-6.13.0.tgz#312563b4dbde3cc806cee3e416cceeaddd11ac0b" + +babel-plugin-syntax-dynamic-import@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-dynamic-import/-/babel-plugin-syntax-dynamic-import-6.18.0.tgz#8d6a26229c83745a9982a441051572caa179b1da" + babel-plugin-syntax-exponentiation-operator@^6.8.0: version "6.13.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de" +babel-plugin-syntax-export-extensions@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-export-extensions/-/babel-plugin-syntax-export-extensions-6.13.0.tgz#70a1484f0f9089a4e84ad44bac353c95b9b12721" + +babel-plugin-syntax-flow@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-flow/-/babel-plugin-syntax-flow-6.18.0.tgz#4c3ab20a2af26aa20cd25995c398c4eb70310c8d" + +babel-plugin-syntax-jsx@^6.3.13, babel-plugin-syntax-jsx@^6.8.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz#0af32a9a6e13ca7a3fd5069e62d7b0f58d0d8946" + +babel-plugin-syntax-object-rest-spread@^6.13.0, babel-plugin-syntax-object-rest-spread@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz#fd6536f2bce13836ffa3a5458c4903a597bb3bf5" + babel-plugin-syntax-trailing-function-commas@^6.22.0: version "6.22.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz#ba0360937f8d06e40180a43fe0d5616fff532cf3" -babel-plugin-transform-async-to-generator@^6.22.0: +babel-plugin-transform-async-generator-functions@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-generator-functions/-/babel-plugin-transform-async-generator-functions-6.24.1.tgz#f058900145fd3e9907a6ddf28da59f215258a5db" + dependencies: + babel-helper-remap-async-to-generator "^6.24.1" + babel-plugin-syntax-async-generators "^6.5.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-async-to-generator@^6.22.0, babel-plugin-transform-async-to-generator@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz#6536e378aff6cb1d5517ac0e40eb3e9fc8d08761" dependencies: @@ -321,6 +555,41 @@ babel-plugin-transform-async-to-generator@^6.22.0: babel-plugin-syntax-async-functions "^6.8.0" babel-runtime "^6.22.0" +babel-plugin-transform-class-constructor-call@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-constructor-call/-/babel-plugin-transform-class-constructor-call-6.24.1.tgz#80dc285505ac067dcb8d6c65e2f6f11ab7765ef9" + dependencies: + babel-plugin-syntax-class-constructor-call "^6.18.0" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-class-properties@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.24.1.tgz#6a79763ea61d33d36f37b611aa9def81a81b46ac" + dependencies: + babel-helper-function-name "^6.24.1" + babel-plugin-syntax-class-properties "^6.8.0" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-decorators-legacy@^1.3.4: + version "1.3.4" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-decorators-legacy/-/babel-plugin-transform-decorators-legacy-1.3.4.tgz#741b58f6c5bce9e6027e0882d9c994f04f366925" + dependencies: + babel-plugin-syntax-decorators "^6.1.18" + babel-runtime "^6.2.0" + babel-template "^6.3.0" + +babel-plugin-transform-decorators@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-decorators/-/babel-plugin-transform-decorators-6.24.1.tgz#788013d8f8c6b5222bdf7b344390dfd77569e24d" + dependencies: + babel-helper-explode-class "^6.24.1" + babel-plugin-syntax-decorators "^6.13.0" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-types "^6.24.1" + babel-plugin-transform-es2015-arrow-functions@^6.22.0: version "6.22.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz#452692cb711d5f79dc7f85e440ce41b9f244d221" @@ -333,7 +602,7 @@ babel-plugin-transform-es2015-block-scoped-functions@^6.22.0: dependencies: babel-runtime "^6.22.0" -babel-plugin-transform-es2015-block-scoping@^6.23.0: +babel-plugin-transform-es2015-block-scoping@^6.23.0, babel-plugin-transform-es2015-block-scoping@^6.24.1: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz#d70f5299c1308d05c12f463813b0a09e73b1895f" dependencies: @@ -343,7 +612,7 @@ babel-plugin-transform-es2015-block-scoping@^6.23.0: babel-types "^6.26.0" lodash "^4.17.4" -babel-plugin-transform-es2015-classes@^6.23.0: +babel-plugin-transform-es2015-classes@^6.23.0, babel-plugin-transform-es2015-classes@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz#5a4c58a50c9c9461e564b4b2a3bfabc97a2584db" dependencies: @@ -357,33 +626,33 @@ babel-plugin-transform-es2015-classes@^6.23.0: babel-traverse "^6.24.1" babel-types "^6.24.1" -babel-plugin-transform-es2015-computed-properties@^6.22.0: +babel-plugin-transform-es2015-computed-properties@^6.22.0, babel-plugin-transform-es2015-computed-properties@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz#6fe2a8d16895d5634f4cd999b6d3480a308159b3" dependencies: babel-runtime "^6.22.0" babel-template "^6.24.1" -babel-plugin-transform-es2015-destructuring@^6.23.0: +babel-plugin-transform-es2015-destructuring@^6.22.0, babel-plugin-transform-es2015-destructuring@^6.23.0: version "6.23.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz#997bb1f1ab967f682d2b0876fe358d60e765c56d" dependencies: babel-runtime "^6.22.0" -babel-plugin-transform-es2015-duplicate-keys@^6.22.0: +babel-plugin-transform-es2015-duplicate-keys@^6.22.0, babel-plugin-transform-es2015-duplicate-keys@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz#73eb3d310ca969e3ef9ec91c53741a6f1576423e" dependencies: babel-runtime "^6.22.0" babel-types "^6.24.1" -babel-plugin-transform-es2015-for-of@^6.23.0: +babel-plugin-transform-es2015-for-of@^6.22.0, babel-plugin-transform-es2015-for-of@^6.23.0: version "6.23.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz#f47c95b2b613df1d3ecc2fdb7573623c75248691" dependencies: babel-runtime "^6.22.0" -babel-plugin-transform-es2015-function-name@^6.22.0: +babel-plugin-transform-es2015-function-name@^6.22.0, babel-plugin-transform-es2015-function-name@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz#834c89853bc36b1af0f3a4c5dbaa94fd8eacaa8b" dependencies: @@ -414,7 +683,7 @@ babel-plugin-transform-es2015-modules-commonjs@^6.23.0, babel-plugin-transform-e babel-template "^6.26.0" babel-types "^6.26.0" -babel-plugin-transform-es2015-modules-systemjs@^6.23.0: +babel-plugin-transform-es2015-modules-systemjs@^6.23.0, babel-plugin-transform-es2015-modules-systemjs@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz#ff89a142b9119a906195f5f106ecf305d9407d23" dependencies: @@ -422,7 +691,7 @@ babel-plugin-transform-es2015-modules-systemjs@^6.23.0: babel-runtime "^6.22.0" babel-template "^6.24.1" -babel-plugin-transform-es2015-modules-umd@^6.23.0: +babel-plugin-transform-es2015-modules-umd@^6.23.0, babel-plugin-transform-es2015-modules-umd@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz#ac997e6285cd18ed6176adb607d602344ad38468" dependencies: @@ -430,14 +699,14 @@ babel-plugin-transform-es2015-modules-umd@^6.23.0: babel-runtime "^6.22.0" babel-template "^6.24.1" -babel-plugin-transform-es2015-object-super@^6.22.0: +babel-plugin-transform-es2015-object-super@^6.22.0, babel-plugin-transform-es2015-object-super@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz#24cef69ae21cb83a7f8603dad021f572eb278f8d" dependencies: babel-helper-replace-supers "^6.24.1" babel-runtime "^6.22.0" -babel-plugin-transform-es2015-parameters@^6.23.0: +babel-plugin-transform-es2015-parameters@^6.23.0, babel-plugin-transform-es2015-parameters@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz#57ac351ab49caf14a97cd13b09f66fdf0a625f2b" dependencies: @@ -448,7 +717,7 @@ babel-plugin-transform-es2015-parameters@^6.23.0: babel-traverse "^6.24.1" babel-types "^6.24.1" -babel-plugin-transform-es2015-shorthand-properties@^6.22.0: +babel-plugin-transform-es2015-shorthand-properties@^6.22.0, babel-plugin-transform-es2015-shorthand-properties@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz#24f875d6721c87661bbd99a4622e51f14de38aa0" dependencies: @@ -461,7 +730,7 @@ babel-plugin-transform-es2015-spread@^6.22.0: dependencies: babel-runtime "^6.22.0" -babel-plugin-transform-es2015-sticky-regex@^6.22.0: +babel-plugin-transform-es2015-sticky-regex@^6.22.0, babel-plugin-transform-es2015-sticky-regex@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz#00c1cdb1aca71112cdf0cf6126c2ed6b457ccdbc" dependencies: @@ -475,13 +744,13 @@ babel-plugin-transform-es2015-template-literals@^6.22.0: dependencies: babel-runtime "^6.22.0" -babel-plugin-transform-es2015-typeof-symbol@^6.23.0: +babel-plugin-transform-es2015-typeof-symbol@^6.22.0, babel-plugin-transform-es2015-typeof-symbol@^6.23.0: version "6.23.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz#dec09f1cddff94b52ac73d505c84df59dcceb372" dependencies: babel-runtime "^6.22.0" -babel-plugin-transform-es2015-unicode-regex@^6.22.0: +babel-plugin-transform-es2015-unicode-regex@^6.22.0, babel-plugin-transform-es2015-unicode-regex@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz#d38b12f42ea7323f729387f18a7c5ae1faeb35e9" dependencies: @@ -489,7 +758,7 @@ babel-plugin-transform-es2015-unicode-regex@^6.22.0: babel-runtime "^6.22.0" regexpu-core "^2.0.0" -babel-plugin-transform-exponentiation-operator@^6.22.0: +babel-plugin-transform-exponentiation-operator@^6.22.0, babel-plugin-transform-exponentiation-operator@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz#2ab0c9c7f3098fa48907772bb813fe41e8de3a0e" dependencies: @@ -497,7 +766,56 @@ babel-plugin-transform-exponentiation-operator@^6.22.0: babel-plugin-syntax-exponentiation-operator "^6.8.0" babel-runtime "^6.22.0" -babel-plugin-transform-regenerator@^6.22.0: +babel-plugin-transform-export-extensions@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-export-extensions/-/babel-plugin-transform-export-extensions-6.22.0.tgz#53738b47e75e8218589eea946cbbd39109bbe653" + dependencies: + babel-plugin-syntax-export-extensions "^6.8.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-flow-strip-types@^6.22.0, babel-plugin-transform-flow-strip-types@^6.8.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-flow-strip-types/-/babel-plugin-transform-flow-strip-types-6.22.0.tgz#84cb672935d43714fdc32bce84568d87441cf7cf" + dependencies: + babel-plugin-syntax-flow "^6.18.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-object-rest-spread@^6.22.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz#0f36692d50fef6b7e2d4b3ac1478137a963b7b06" + dependencies: + babel-plugin-syntax-object-rest-spread "^6.8.0" + babel-runtime "^6.26.0" + +babel-plugin-transform-react-display-name@^6.23.0: + version "6.25.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-display-name/-/babel-plugin-transform-react-display-name-6.25.0.tgz#67e2bf1f1e9c93ab08db96792e05392bf2cc28d1" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-react-jsx-self@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-jsx-self/-/babel-plugin-transform-react-jsx-self-6.22.0.tgz#df6d80a9da2612a121e6ddd7558bcbecf06e636e" + dependencies: + babel-plugin-syntax-jsx "^6.8.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-react-jsx-source@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-jsx-source/-/babel-plugin-transform-react-jsx-source-6.22.0.tgz#66ac12153f5cd2d17b3c19268f4bf0197f44ecd6" + dependencies: + babel-plugin-syntax-jsx "^6.8.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-react-jsx@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-jsx/-/babel-plugin-transform-react-jsx-6.24.1.tgz#840a028e7df460dfc3a2d29f0c0d91f6376e66a3" + dependencies: + babel-helper-builder-react-jsx "^6.24.1" + babel-plugin-syntax-jsx "^6.8.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-regenerator@^6.22.0, babel-plugin-transform-regenerator@^6.24.1: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz#e0703696fbde27f0a3efcacf8b4dca2f7b3a8f2f" dependencies: @@ -545,7 +863,87 @@ babel-preset-env@^1.6.1: invariant "^2.2.2" semver "^5.3.0" -babel-register@^6.26.0: +babel-preset-es2015@^6.9.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-preset-es2015/-/babel-preset-es2015-6.24.1.tgz#d44050d6bc2c9feea702aaf38d727a0210538939" + dependencies: + babel-plugin-check-es2015-constants "^6.22.0" + babel-plugin-transform-es2015-arrow-functions "^6.22.0" + babel-plugin-transform-es2015-block-scoped-functions "^6.22.0" + babel-plugin-transform-es2015-block-scoping "^6.24.1" + babel-plugin-transform-es2015-classes "^6.24.1" + babel-plugin-transform-es2015-computed-properties "^6.24.1" + babel-plugin-transform-es2015-destructuring "^6.22.0" + babel-plugin-transform-es2015-duplicate-keys "^6.24.1" + babel-plugin-transform-es2015-for-of "^6.22.0" + babel-plugin-transform-es2015-function-name "^6.24.1" + babel-plugin-transform-es2015-literals "^6.22.0" + babel-plugin-transform-es2015-modules-amd "^6.24.1" + babel-plugin-transform-es2015-modules-commonjs "^6.24.1" + babel-plugin-transform-es2015-modules-systemjs "^6.24.1" + babel-plugin-transform-es2015-modules-umd "^6.24.1" + babel-plugin-transform-es2015-object-super "^6.24.1" + babel-plugin-transform-es2015-parameters "^6.24.1" + babel-plugin-transform-es2015-shorthand-properties "^6.24.1" + babel-plugin-transform-es2015-spread "^6.22.0" + babel-plugin-transform-es2015-sticky-regex "^6.24.1" + babel-plugin-transform-es2015-template-literals "^6.22.0" + babel-plugin-transform-es2015-typeof-symbol "^6.22.0" + babel-plugin-transform-es2015-unicode-regex "^6.24.1" + babel-plugin-transform-regenerator "^6.24.1" + +babel-preset-flow@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-preset-flow/-/babel-preset-flow-6.23.0.tgz#e71218887085ae9a24b5be4169affb599816c49d" + dependencies: + babel-plugin-transform-flow-strip-types "^6.22.0" + +babel-preset-jest@^22.4.3: + version "22.4.3" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-22.4.3.tgz#e92eef9813b7026ab4ca675799f37419b5a44156" + dependencies: + babel-plugin-jest-hoist "^22.4.3" + babel-plugin-syntax-object-rest-spread "^6.13.0" + +babel-preset-react@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-preset-react/-/babel-preset-react-6.24.1.tgz#ba69dfaea45fc3ec639b6a4ecea6e17702c91380" + dependencies: + babel-plugin-syntax-jsx "^6.3.13" + babel-plugin-transform-react-display-name "^6.23.0" + babel-plugin-transform-react-jsx "^6.24.1" + babel-plugin-transform-react-jsx-self "^6.22.0" + babel-plugin-transform-react-jsx-source "^6.22.0" + babel-preset-flow "^6.23.0" + +babel-preset-stage-1@^6.5.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-preset-stage-1/-/babel-preset-stage-1-6.24.1.tgz#7692cd7dcd6849907e6ae4a0a85589cfb9e2bfb0" + dependencies: + babel-plugin-transform-class-constructor-call "^6.24.1" + babel-plugin-transform-export-extensions "^6.22.0" + babel-preset-stage-2 "^6.24.1" + +babel-preset-stage-2@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-preset-stage-2/-/babel-preset-stage-2-6.24.1.tgz#d9e2960fb3d71187f0e64eec62bc07767219bdc1" + dependencies: + babel-plugin-syntax-dynamic-import "^6.18.0" + babel-plugin-transform-class-properties "^6.24.1" + babel-plugin-transform-decorators "^6.24.1" + babel-preset-stage-3 "^6.24.1" + +babel-preset-stage-3@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-preset-stage-3/-/babel-preset-stage-3-6.24.1.tgz#836ada0a9e7a7fa37cb138fb9326f87934a48395" + dependencies: + babel-plugin-syntax-trailing-function-commas "^6.22.0" + babel-plugin-transform-async-generator-functions "^6.24.1" + babel-plugin-transform-async-to-generator "^6.24.1" + babel-plugin-transform-exponentiation-operator "^6.24.1" + babel-plugin-transform-object-rest-spread "^6.22.0" + +babel-register@^6.26.0, babel-register@^6.9.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.26.0.tgz#6ed021173e2fcb486d7acb45c6009a856f647071" dependencies: @@ -557,14 +955,14 @@ babel-register@^6.26.0: mkdirp "^0.5.1" source-map-support "^0.4.15" -babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.26.0: +babel-runtime@^6.18.0, babel-runtime@^6.2.0, babel-runtime@^6.22.0, babel-runtime@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" dependencies: core-js "^2.4.0" regenerator-runtime "^0.11.0" -babel-template@^6.24.1, babel-template@^6.26.0: +babel-template@^6.16.0, babel-template@^6.24.1, babel-template@^6.26.0, babel-template@^6.3.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.26.0.tgz#de03e2d16396b069f46dd9fff8521fb1a0e35e02" dependencies: @@ -574,7 +972,7 @@ babel-template@^6.24.1, babel-template@^6.26.0: babylon "^6.18.0" lodash "^4.17.4" -babel-traverse@^6.24.1, babel-traverse@^6.26.0: +babel-traverse@^6.18.0, babel-traverse@^6.24.1, babel-traverse@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee" dependencies: @@ -588,7 +986,7 @@ babel-traverse@^6.24.1, babel-traverse@^6.26.0: invariant "^2.2.2" lodash "^4.17.4" -babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.26.0: +babel-types@^6.18.0, babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497" dependencies: @@ -597,10 +995,14 @@ babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.26.0: lodash "^4.17.4" to-fast-properties "^1.0.3" -babylon@^6.18.0: +babylon@^6.17.3, babylon@^6.18.0: version "6.18.0" resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" +babylon@^7.0.0-beta.30: + version "7.0.0-beta.42" + resolved "https://registry.yarnpkg.com/babylon/-/babylon-7.0.0-beta.42.tgz#67cfabcd4f3ec82999d29031ccdea89d0ba99657" + balanced-match@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" @@ -609,6 +1011,18 @@ base64-js@^1.0.2: version "1.2.3" resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.3.tgz#fb13668233d9614cf5fb4bce95a9ba4096cdf801" +base@^0.11.1: + version "0.11.2" + resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" + dependencies: + cache-base "^1.0.1" + class-utils "^0.3.5" + component-emitter "^1.2.1" + define-property "^1.0.0" + isobject "^3.0.1" + mixin-deep "^1.2.0" + pascalcase "^0.1.1" + bcrypt-pbkdf@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d" @@ -623,22 +1037,46 @@ binary-extensions@^1.0.0: version "1.11.0" resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.11.0.tgz#46aa1751fb6a2f93ee5e689bb1087d4b14c6c205" +binaryextensions@2: + version "2.1.1" + resolved "https://registry.yarnpkg.com/binaryextensions/-/binaryextensions-2.1.1.tgz#3209a51ca4a4ad541a3b8d3d6a6d5b83a2485935" + block-stream@*: version "0.0.9" resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" dependencies: inherits "~2.0.0" +bluebird@^3.5.1: + version "3.5.1" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.1.tgz#d9551f9de98f1fcda1e683d17ee91a0602ee2eb9" + bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0: version "4.11.8" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" +boolbase@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" + boom@2.x.x: version "2.10.1" resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f" dependencies: hoek "2.x.x" +boom@4.x.x: + version "4.3.1" + resolved "https://registry.yarnpkg.com/boom/-/boom-4.3.1.tgz#4f8a3005cb4a7e3889f749030fd25b96e01d2e31" + dependencies: + hoek "4.x.x" + +boom@5.x.x: + version "5.2.0" + resolved "https://registry.yarnpkg.com/boom/-/boom-5.2.0.tgz#5dd9da6ee3a5f302077436290cb717d3f4a54e02" + dependencies: + hoek "4.x.x" + brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" @@ -654,10 +1092,37 @@ braces@^1.8.2: preserve "^0.2.0" repeat-element "^1.1.2" +braces@^2.3.0, braces@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.1.tgz#7086c913b4e5a08dbe37ac0ee6a2500c4ba691bb" + dependencies: + arr-flatten "^1.1.0" + array-unique "^0.3.2" + define-property "^1.0.0" + extend-shallow "^2.0.1" + fill-range "^4.0.0" + isobject "^3.0.1" + kind-of "^6.0.2" + repeat-element "^1.1.2" + snapdragon "^0.8.1" + snapdragon-node "^2.0.1" + split-string "^3.0.2" + to-regex "^3.0.1" + brorand@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" +browser-process-hrtime@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-0.1.2.tgz#425d68a58d3447f02a04aa894187fce8af8b7b8e" + +browser-resolve@^1.11.2: + version "1.11.2" + resolved "https://registry.yarnpkg.com/browser-resolve/-/browser-resolve-1.11.2.tgz#8ff09b0a2c421718a1051c260b32e48f442938ce" + dependencies: + resolve "1.1.7" + browserify-aes@^1.0.0, browserify-aes@^1.0.4: version "1.1.1" resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.1.1.tgz#38b7ab55edb806ff2dcda1a7f1620773a477c49f" @@ -717,6 +1182,16 @@ browserslist@^2.1.2: caniuse-lite "^1.0.30000792" electron-to-chromium "^1.3.30" +bser@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/bser/-/bser-2.0.0.tgz#9ac78d3ed5d915804fd87acb158bc797147a1719" + dependencies: + node-int64 "^0.4.0" + +buffer-from@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.0.0.tgz#4cb8832d23612589b0406e9e2956c17f06fdf531" + buffer-xor@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" @@ -737,6 +1212,61 @@ 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" +cacache@^10.0.4: + version "10.0.4" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-10.0.4.tgz#6452367999eff9d4188aefd9a14e9d7c6a263460" + dependencies: + bluebird "^3.5.1" + chownr "^1.0.1" + glob "^7.1.2" + graceful-fs "^4.1.11" + lru-cache "^4.1.1" + mississippi "^2.0.0" + mkdirp "^0.5.1" + move-concurrently "^1.0.1" + promise-inflight "^1.0.1" + rimraf "^2.6.2" + ssri "^5.2.4" + unique-filename "^1.1.0" + y18n "^4.0.0" + +cache-base@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" + dependencies: + collection-visit "^1.0.0" + component-emitter "^1.2.1" + get-value "^2.0.6" + has-value "^1.0.0" + isobject "^3.0.1" + set-value "^2.0.0" + to-object-path "^0.3.0" + union-value "^1.0.0" + unset-value "^1.0.0" + +cacheable-request@^2.1.1: + version "2.1.4" + resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-2.1.4.tgz#0d808801b6342ad33c91df9d0b44dc09b91e5c3d" + dependencies: + clone-response "1.0.2" + get-stream "3.0.0" + http-cache-semantics "3.8.1" + keyv "3.0.0" + lowercase-keys "1.0.0" + normalize-url "2.0.1" + responselike "1.0.2" + +callsites@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50" + +camel-case@3.0.x: + version "3.0.0" + resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-3.0.0.tgz#ca3c3688a4e9cf3a4cda777dc4dcbc713249cf73" + dependencies: + no-case "^2.2.0" + upper-case "^1.1.1" + camelcase@^1.0.2: version "1.2.1" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39" @@ -746,8 +1276,8 @@ camelcase@^4.1.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" caniuse-lite@^1.0.30000792: - version "1.0.30000809" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000809.tgz#1e12c1344b8f74d56737ee2614bcedb648943479" + version "1.0.30000821" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000821.tgz#0f3223f1e048ed96451c56ca6cf197058c42cb93" caseless@~0.12.0: version "0.12.0" @@ -760,7 +1290,7 @@ center-align@^0.1.1: align-text "^0.1.3" lazy-cache "^1.0.3" -chalk@^1.1.3: +chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" dependencies: @@ -770,20 +1300,55 @@ chalk@^1.1.3: strip-ansi "^3.0.0" supports-color "^2.0.0" -chokidar@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468" +chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.3.2.tgz#250dc96b07491bfd601e648d66ddf5f60c7a5c65" + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chalk@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-0.4.0.tgz#5199a3ddcd0c1efe23bc08c1b027b06176e0c64f" + dependencies: + ansi-styles "~1.0.0" + has-color "~0.1.0" + strip-ansi "~0.1.0" + +chardet@^0.4.0: + version "0.4.2" + resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.4.2.tgz#b5473b33dc97c424e5d98dc87d55d4d8a29c8bf2" + +chokidar@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.0.3.tgz#dcbd4f6cbb2a55b4799ba8a840ac527e5f4b1176" dependencies: - anymatch "^1.3.0" + anymatch "^2.0.0" async-each "^1.0.0" - glob-parent "^2.0.0" + braces "^2.3.0" + glob-parent "^3.1.0" inherits "^2.0.1" is-binary-path "^1.0.0" - is-glob "^2.0.0" + is-glob "^4.0.0" + normalize-path "^2.1.1" path-is-absolute "^1.0.0" readdirp "^2.0.0" + upath "^1.0.0" optionalDependencies: - fsevents "^1.0.0" + fsevents "^1.1.2" + +chownr@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.0.1.tgz#e2a75042a9551908bebd25b8523d5f9769d79181" + +chrome-trace-event@^0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-0.1.2.tgz#90f36885d5345a50621332f0717b595883d5d982" + +ci-info@^1.0.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.1.3.tgz#710193264bb05c77b8c90d02f5aaf22216a667b2" cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: version "1.0.4" @@ -792,22 +1357,104 @@ cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: inherits "^2.0.1" safe-buffer "^5.0.1" -cliui@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1" +class-utils@^0.3.5: + version "0.3.6" + resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" dependencies: - center-align "^0.1.1" - right-align "^0.1.1" - wordwrap "0.0.2" + arr-union "^3.1.0" + define-property "^0.2.5" + isobject "^3.0.0" + static-extend "^0.1.1" -cliui@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" +clean-css@4.1.x: + version "4.1.11" + resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.1.11.tgz#2ecdf145aba38f54740f26cefd0ff3e03e125d6a" + dependencies: + source-map "0.5.x" + +cli-cursor@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987" + dependencies: + restore-cursor "^1.0.1" + +cli-cursor@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" + dependencies: + restore-cursor "^2.0.0" + +cli-spinners@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-0.1.2.tgz#bb764d88e185fb9e1e6a2a1f19772318f605e31c" + +cli-table@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/cli-table/-/cli-table-0.3.1.tgz#f53b05266a8b1a0b934b3d0821e6e2dc5914ae23" + dependencies: + colors "1.0.3" + +cli-truncate@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-0.2.1.tgz#9f15cfbb0705005369216c626ac7d05ab90dd574" dependencies: + slice-ansi "0.0.4" string-width "^1.0.1" - strip-ansi "^3.0.1" + +cli-width@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" + +cliui@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1" + dependencies: + center-align "^0.1.1" + right-align "^0.1.1" + wordwrap "0.0.2" + +cliui@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-4.0.0.tgz#743d4650e05f36d1ed2575b59638d87322bfbbcc" + dependencies: + string-width "^2.1.1" + strip-ansi "^4.0.0" wrap-ansi "^2.0.0" +clone-buffer@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/clone-buffer/-/clone-buffer-1.0.0.tgz#e3e25b207ac4e701af721e2cb5a16792cac3dc58" + +clone-response@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b" + dependencies: + mimic-response "^1.0.0" + +clone-stats@^0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/clone-stats/-/clone-stats-0.0.1.tgz#b88f94a82cf38b8791d58046ea4029ad88ca99d1" + +clone-stats@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/clone-stats/-/clone-stats-1.0.0.tgz#b3782dff8bb5474e18b9b6bf0fdfe782f8777680" + +clone@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" + +clone@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f" + +cloneable-readable@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/cloneable-readable/-/cloneable-readable-1.1.2.tgz#d591dee4a8f8bc15da43ce97dceeba13d43e2a65" + dependencies: + inherits "^2.0.1" + process-nextick-args "^2.0.0" + readable-stream "^2.3.5" + co@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" @@ -816,16 +1463,70 @@ code-point-at@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" -combined-stream@^1.0.5, combined-stream@~1.0.5: +collection-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" + dependencies: + map-visit "^1.0.0" + object-visit "^1.0.0" + +color-convert@^1.9.0: + version "1.9.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.1.tgz#c1261107aeb2f294ebffec9ed9ecad529a6097ed" + dependencies: + color-name "^1.1.1" + +color-name@^1.1.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + +colors@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" + +colors@^1.1.2: + version "1.2.1" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.2.1.tgz#f4a3d302976aaf042356ba1ade3b1a2c62d9d794" + +combined-stream@1.0.6, combined-stream@^1.0.5, combined-stream@~1.0.5: version "1.0.6" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.6.tgz#723e7df6e801ac5613113a7e445a9b69cb632818" dependencies: delayed-stream "~1.0.0" +commander@2.15.x, commander@~2.15.0: + version "2.15.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f" + +commander@~2.13.0: + version "2.13.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.13.0.tgz#6964bca67685df7c1f1430c584f07d7597885b9c" + +commondir@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" + +compare-versions@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-3.1.0.tgz#43310256a5c555aaed4193c04d8f154cf9c6efd5" + +component-emitter@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" + concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" +concat-stream@^1.5.0: + version "1.6.2" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" + dependencies: + buffer-from "^1.0.0" + inherits "^2.0.3" + readable-stream "^2.2.2" + typedarray "^0.0.6" + console-browserify@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10" @@ -840,22 +1541,49 @@ constants-browserify@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" -convert-source-map@^1.5.0: +content-type-parser@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/content-type-parser/-/content-type-parser-1.0.2.tgz#caabe80623e63638b2502fd4c7f12ff4ce2352e7" + +convert-source-map@^1.4.0, convert-source-map@^1.5.0: version "1.5.1" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.1.tgz#b8278097b9bc229365de5c62cf5fcaed8b5599e5" +copy-concurrently@^1.0.0: + version "1.0.5" + resolved "https://registry.yarnpkg.com/copy-concurrently/-/copy-concurrently-1.0.5.tgz#92297398cae34937fcafd6ec8139c18051f0b5e0" + dependencies: + aproba "^1.1.1" + fs-write-stream-atomic "^1.0.8" + iferr "^0.1.5" + mkdirp "^0.5.1" + rimraf "^2.5.4" + run-queue "^1.0.0" + +copy-descriptor@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" + +core-decorators@^0.20.0: + version "0.20.0" + resolved "https://registry.yarnpkg.com/core-decorators/-/core-decorators-0.20.0.tgz#605896624053af8c28efbe735c25a301a61c65c5" + core-js@^1.0.0: version "1.2.7" resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" -core-js@^2.4.0, core-js@^2.5.0: - version "2.5.3" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.3.tgz#8acc38345824f16d8365b7c9b4259168e8ed603e" +core-js@^2.4.0, core-js@^2.4.1, core-js@^2.5.0: + version "2.5.4" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.4.tgz#f2c8bf181f2a80b92f360121429ce63a2f0aeae0" core-util-is@1.0.2, core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" +corser@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/corser/-/corser-2.0.1.tgz#8eda252ecaab5840dcd975ceb90d9370c819ff87" + create-ecdh@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.0.tgz#888c723596cdf7612f6498233eebd7a35301737d" @@ -883,7 +1611,7 @@ create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4: safe-buffer "^5.0.1" sha.js "^2.4.8" -cross-spawn@^5.0.1: +cross-spawn@^5.0.1, cross-spawn@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" dependencies: @@ -891,12 +1619,28 @@ cross-spawn@^5.0.1: shebang-command "^1.2.0" which "^1.2.9" +cross-spawn@^6.0.5: + version "6.0.5" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" + dependencies: + nice-try "^1.0.4" + path-key "^2.0.1" + semver "^5.5.0" + shebang-command "^1.2.0" + which "^1.2.9" + cryptiles@2.x.x: version "2.0.5" resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8" dependencies: boom "2.x.x" +cryptiles@3.x.x: + version "3.1.2" + resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-3.1.2.tgz#a89fbb220f5ce25ec56e8c4aa8a4fd7b5b0d29fe" + dependencies: + boom "5.x.x" + crypto-browserify@^3.11.0: version "3.12.0" resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" @@ -913,11 +1657,36 @@ crypto-browserify@^3.11.0: randombytes "^2.0.0" randomfill "^1.0.3" -d@1: - version "1.0.0" - resolved "https://registry.yarnpkg.com/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f" +css-select@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/css-select/-/css-select-1.2.0.tgz#2b3a110539c5355f1cd8d314623e870b121ec858" + dependencies: + boolbase "~1.0.0" + css-what "2.1" + domutils "1.5.1" + nth-check "~1.0.1" + +css-what@2.1: + version "2.1.0" + resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.0.tgz#9467d032c38cfaefb9f2d79501253062f87fa1bd" + +cssom@0.3.x, "cssom@>= 0.3.2 < 0.4.0": + version "0.3.2" + resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.2.tgz#b8036170c79f07a90ff2f16e22284027a243848b" + +"cssstyle@>= 0.2.37 < 0.3.0": + version "0.2.37" + resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-0.2.37.tgz#541097234cb2513c83ceed3acddc27ff27987d54" dependencies: - es5-ext "^0.10.9" + cssom "0.3.x" + +cyclist@~0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-0.2.2.tgz#1b33792e11e914a2fd6d6ed6447464444e5fa640" + +dargs@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/dargs/-/dargs-5.1.0.tgz#ec7ea50c78564cd36c9d5ec18f66329fade27829" dashdash@^1.12.0: version "1.14.1" @@ -925,24 +1694,84 @@ dashdash@^1.12.0: dependencies: assert-plus "^1.0.0" +date-fns@^1.27.2: + version "1.29.0" + resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.29.0.tgz#12e609cdcb935127311d04d33334e2960a2a54e6" + date-now@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b" -debug@^2.2.0, debug@^2.6.8: +dateformat@^3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae" + +debug@^2.2.0, debug@^2.3.3, debug@^2.6.8: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" dependencies: ms "2.0.0" +debug@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" + dependencies: + ms "2.0.0" + decamelize@^1.0.0, decamelize@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" -deep-extend@~0.4.0: +decode-uri-component@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" + +decompress-response@^3.2.0, decompress-response@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" + dependencies: + mimic-response "^1.0.0" + +deep-extend@^0.4.0, deep-extend@~0.4.0: version "0.4.2" resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.2.tgz#48b699c27e334bf89f10892be432f6e4c7d34a7f" +deep-is@~0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" + +default-require-extensions@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/default-require-extensions/-/default-require-extensions-1.0.0.tgz#f37ea15d3e13ffd9b437d33e1a75b5fb97874cb8" + dependencies: + strip-bom "^2.0.0" + +define-properties@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.2.tgz#83a73f2fea569898fb737193c8f873caf6d45c94" + dependencies: + foreach "^2.0.5" + object-keys "^1.0.8" + +define-property@^0.2.5: + version "0.2.5" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" + dependencies: + is-descriptor "^0.1.0" + +define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" + dependencies: + is-descriptor "^1.0.0" + +define-property@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" + dependencies: + is-descriptor "^1.0.2" + isobject "^3.0.1" + delayed-stream@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" @@ -958,6 +1787,10 @@ des.js@^1.0.0: inherits "^2.0.1" minimalistic-assert "^1.0.0" +detect-conflict@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/detect-conflict/-/detect-conflict-1.0.1.tgz#088657a66a961c05019db7c4230883b1c6b4176e" + detect-indent@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" @@ -968,6 +1801,14 @@ detect-libc@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" +detect-newline@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-2.1.0.tgz#f41f1c10be4b00e87b5f13da680759f2c5bfd3e2" + +diff@^3.2.0, diff@^3.3.1, diff@^3.5.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" + diffie-hellman@^5.0.0: version "5.0.2" resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.2.tgz#b5835739270cfe26acf632099fded2a07f209e5e" @@ -976,19 +1817,99 @@ diffie-hellman@^5.0.0: miller-rabin "^4.0.0" randombytes "^2.0.0" +dom-converter@~0.1: + version "0.1.4" + resolved "https://registry.yarnpkg.com/dom-converter/-/dom-converter-0.1.4.tgz#a45ef5727b890c9bffe6d7c876e7b19cb0e17f3b" + dependencies: + utila "~0.3" + +dom-serializer@0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.0.tgz#073c697546ce0780ce23be4a28e293e40bc30c82" + dependencies: + domelementtype "~1.1.1" + entities "~1.1.1" + domain-browser@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda" +domelementtype@1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.0.tgz#b17aed82e8ab59e52dd9c19b1756e0fc187204c2" + +domelementtype@~1.1.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.1.3.tgz#bd28773e2642881aec51544924299c5cd822185b" + +domexception@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/domexception/-/domexception-1.0.1.tgz#937442644ca6a31261ef36e3ec677fe805582c90" + dependencies: + webidl-conversions "^4.0.2" + +domhandler@2.1: + version "2.1.0" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.1.0.tgz#d2646f5e57f6c3bab11cf6cb05d3c0acf7412594" + dependencies: + domelementtype "1" + +domutils@1.1: + version "1.1.6" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.1.6.tgz#bddc3de099b9a2efacc51c623f28f416ecc57485" + dependencies: + domelementtype "1" + +domutils@1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.5.1.tgz#dcd8488a26f563d61079e48c9f7b7e32373682cf" + dependencies: + dom-serializer "0" + domelementtype "1" + +duplexer3@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" + +duplexify@^3.4.2, duplexify@^3.5.3: + version "3.5.4" + resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.5.4.tgz#4bb46c1796eabebeec4ca9a2e66b808cb7a3d8b4" + dependencies: + end-of-stream "^1.0.0" + inherits "^2.0.1" + readable-stream "^2.0.0" + stream-shift "^1.0.0" + ecc-jsbn@~0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505" dependencies: jsbn "~0.1.0" +ecstatic@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/ecstatic/-/ecstatic-3.2.0.tgz#1b1aee1ca7c6b99cfb5cf6c9b26b481b90c4409f" + dependencies: + he "^1.1.1" + mime "^1.4.1" + minimist "^1.1.0" + url-join "^2.0.2" + +editions@^1.3.3: + version "1.3.4" + resolved "https://registry.yarnpkg.com/editions/-/editions-1.3.4.tgz#3662cb592347c3168eb8e498a0ff73271d67f50b" + +ejs@^2.3.1: + version "2.5.8" + resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.5.8.tgz#2ab6954619f225e6193b7ac5f7c39c48fefe4380" + electron-to-chromium@^1.3.30: - version "1.3.33" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.33.tgz#bf00703d62a7c65238136578c352d6c5c042a545" + version "1.3.41" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.41.tgz#7e33643e00cd85edfd17e04194f6d00e73737235" + +elegant-spinner@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/elegant-spinner/-/elegant-spinner-1.0.1.tgz#db043521c95d7e303fd8f345bedc3349cfb0729e" elliptic@^6.0.0: version "6.4.0" @@ -1012,100 +1933,98 @@ encoding@^0.1.11: dependencies: iconv-lite "~0.4.13" -enhanced-resolve@^3.4.0: - version "3.4.1" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-3.4.1.tgz#0421e339fd71419b3da13d129b3979040230476e" +end-of-stream@^1.0.0, end-of-stream@^1.1.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43" + dependencies: + once "^1.4.0" + +enhanced-resolve@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.0.0.tgz#e34a6eaa790f62fccd71d93959f56b2b432db10a" dependencies: graceful-fs "^4.1.2" memory-fs "^0.4.0" - object-assign "^4.0.1" - tapable "^0.2.7" + tapable "^1.0.0" + +entities@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0" -errno@^0.1.3: +errno@^0.1.3, errno@~0.1.7: version "0.1.7" resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618" dependencies: prr "~1.0.1" -error-ex@^1.2.0: +error-ex@^1.2.0, error-ex@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.1.tgz#f855a86ce61adc4e8621c3cda21e7a7612c3a8dc" dependencies: is-arrayish "^0.2.1" -es5-ext@^0.10.14, es5-ext@^0.10.35, es5-ext@^0.10.9, es5-ext@~0.10.14: - version "0.10.39" - resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.39.tgz#fca21b67559277ca4ac1a1ed7048b107b6f76d87" - dependencies: - es6-iterator "~2.0.3" - es6-symbol "~3.1.1" - -es6-iterator@^2.0.1, es6-iterator@~2.0.1, es6-iterator@~2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7" - dependencies: - d "1" - es5-ext "^0.10.35" - es6-symbol "^3.1.1" - -es6-map@^0.1.3: - version "0.1.5" - resolved "https://registry.yarnpkg.com/es6-map/-/es6-map-0.1.5.tgz#9136e0503dcc06a301690f0bb14ff4e364e949f0" - dependencies: - d "1" - es5-ext "~0.10.14" - es6-iterator "~2.0.1" - es6-set "~0.1.5" - es6-symbol "~3.1.1" - event-emitter "~0.3.5" - -es6-set@~0.1.5: - version "0.1.5" - resolved "https://registry.yarnpkg.com/es6-set/-/es6-set-0.1.5.tgz#d2b3ec5d4d800ced818db538d28974db0a73ccb1" +error@^7.0.2: + version "7.0.2" + resolved "https://registry.yarnpkg.com/error/-/error-7.0.2.tgz#a5f75fff4d9926126ddac0ea5dc38e689153cb02" dependencies: - d "1" - es5-ext "~0.10.14" - es6-iterator "~2.0.1" - es6-symbol "3.1.1" - event-emitter "~0.3.5" + string-template "~0.2.1" + xtend "~4.0.0" -es6-symbol@3.1.1, es6-symbol@^3.1.1, es6-symbol@~3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.1.tgz#bf00ef4fdab6ba1b46ecb7b629b4c7ed5715cc77" +es-abstract@^1.5.1: + version "1.11.0" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.11.0.tgz#cce87d518f0496893b1a30cd8461835535480681" dependencies: - d "1" - es5-ext "~0.10.14" + es-to-primitive "^1.1.1" + function-bind "^1.1.1" + has "^1.0.1" + is-callable "^1.1.3" + is-regex "^1.0.4" -es6-weak-map@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/es6-weak-map/-/es6-weak-map-2.0.2.tgz#5e3ab32251ffd1538a1f8e5ffa1357772f92d96f" +es-to-primitive@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.1.1.tgz#45355248a88979034b6792e19bb81f2b7975dd0d" dependencies: - d "1" - es5-ext "^0.10.14" - es6-iterator "^2.0.1" - es6-symbol "^3.1.1" + is-callable "^1.1.1" + is-date-object "^1.0.1" + is-symbol "^1.0.1" -escape-string-regexp@^1.0.2: +escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" -escope@^3.6.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/escope/-/escope-3.6.0.tgz#e01975e812781a163a6dadfdd80398dc64c889c3" +escodegen@^1.9.0: + version "1.9.1" + resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.9.1.tgz#dbae17ef96c8e4bedb1356f4504fa4cc2f7cb7e2" + dependencies: + esprima "^3.1.3" + estraverse "^4.2.0" + esutils "^2.0.2" + optionator "^0.8.1" + optionalDependencies: + source-map "~0.6.1" + +eslint-scope@^3.7.1: + version "3.7.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-3.7.1.tgz#3d63c3edfda02e06e01a452ad88caacc7cdcb6e8" dependencies: - es6-map "^0.1.3" - es6-weak-map "^2.0.1" esrecurse "^4.1.0" estraverse "^4.1.1" +esprima@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633" + +esprima@^4.0.0, esprima@~4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804" + esrecurse@^4.1.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.0.tgz#fa9568d98d3823f9a41d91e902dcab9ea6e5b163" + version "4.2.1" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf" dependencies: estraverse "^4.1.0" - object-assign "^4.0.1" -estraverse@^4.1.0, estraverse@^4.1.1: +estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" @@ -1113,12 +2032,9 @@ esutils@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" -event-emitter@~0.3.5: - version "0.3.5" - resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39" - dependencies: - d "1" - es5-ext "~0.10.14" +eventemitter3@1.x.x: + version "1.2.0" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-1.2.0.tgz#1c86991d816ad1e504750e73874224ecf3bec508" events@^1.0.0: version "1.1.1" @@ -1131,6 +2047,12 @@ evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: md5.js "^1.3.4" safe-buffer "^5.1.1" +exec-sh@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.2.1.tgz#163b98a6e89e6b65b47c2a28d215bc1f63989c38" + dependencies: + merge "^1.1.3" + execa@^0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777" @@ -1143,28 +2065,99 @@ execa@^0.7.0: signal-exit "^3.0.0" strip-eof "^1.0.0" +exit-hook@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8" + +exit@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" + expand-brackets@^0.1.4: version "0.1.5" resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" dependencies: is-posix-bracket "^0.1.0" +expand-brackets@^2.1.4: + version "2.1.4" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" + dependencies: + debug "^2.3.3" + define-property "^0.2.5" + extend-shallow "^2.0.1" + posix-character-classes "^0.1.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + expand-range@^1.8.1: version "1.8.2" resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" dependencies: fill-range "^2.1.0" -extend@~3.0.0: +expand-tilde@^2.0.0, expand-tilde@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-2.0.2.tgz#97e801aa052df02454de46b02bf621642cdc8502" + dependencies: + homedir-polyfill "^1.0.1" + +expect@^22.4.3: + version "22.4.3" + resolved "https://registry.yarnpkg.com/expect/-/expect-22.4.3.tgz#d5a29d0a0e1fb2153557caef2674d4547e914674" + dependencies: + ansi-styles "^3.2.0" + jest-diff "^22.4.3" + jest-get-type "^22.4.3" + jest-matcher-utils "^22.4.3" + jest-message-util "^22.4.3" + jest-regex-util "^22.4.3" + +extend-shallow@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" + dependencies: + is-extendable "^0.1.0" + +extend-shallow@^3.0.0, extend-shallow@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" + dependencies: + assign-symbols "^1.0.0" + is-extendable "^1.0.1" + +extend@~3.0.0, extend@~3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" +external-editor@^2.0.4, external-editor@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.1.0.tgz#3d026a21b7f95b5726387d4200ac160d372c3b48" + dependencies: + chardet "^0.4.0" + iconv-lite "^0.4.17" + tmp "^0.0.33" + extglob@^0.3.1: version "0.3.2" resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" dependencies: is-extglob "^1.0.0" +extglob@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" + dependencies: + array-unique "^0.3.2" + define-property "^1.0.0" + expand-brackets "^2.1.4" + extend-shallow "^2.0.1" + fragment-cache "^0.2.1" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + extsprintf@1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" @@ -1174,13 +2167,23 @@ extsprintf@^1.2.0: resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" fast-deep-equal@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz#96256a3bc975595eb36d82e9929d060d893439ff" + version "1.1.0" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614" fast-json-stable-stringify@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" +fast-levenshtein@~2.0.4: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + +fb-watchman@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.0.tgz#54e9abf7dfa2f26cd9b1636c588c1afc05de5d58" + dependencies: + bser "^2.0.0" + fbjs@^0.8.16: version "0.8.16" resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.16.tgz#5e67432f550dc41b572bf55847b8aca64e5337db" @@ -1193,10 +2196,30 @@ fbjs@^0.8.16: setimmediate "^1.0.5" ua-parser-js "^0.7.9" +figures@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" + dependencies: + escape-string-regexp "^1.0.5" + object-assign "^4.1.0" + +figures@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" + dependencies: + escape-string-regexp "^1.0.5" + filename-regex@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" +fileset@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/fileset/-/fileset-2.0.3.tgz#8e7548a96d3cc2327ee5e674168723a333bba2a0" + dependencies: + glob "^7.0.3" + minimatch "^3.0.3" + fill-range@^2.1.0: version "2.2.3" resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723" @@ -1207,15 +2230,56 @@ fill-range@^2.1.0: repeat-element "^1.1.2" repeat-string "^1.5.2" -find-up@^2.0.0: +fill-range@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" + dependencies: + extend-shallow "^2.0.1" + is-number "^3.0.0" + repeat-string "^1.6.1" + to-regex-range "^2.1.0" + +find-cache-dir@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-1.0.0.tgz#9288e3e9e3cc3748717d39eade17cf71fc30ee6f" + dependencies: + commondir "^1.0.1" + make-dir "^1.0.0" + pkg-dir "^2.0.0" + +find-up@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" + dependencies: + path-exists "^2.0.0" + pinkie-promise "^2.0.0" + +find-up@^2.0.0, find-up@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" dependencies: locate-path "^2.0.0" -for-in@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" +first-chunk-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/first-chunk-stream/-/first-chunk-stream-2.0.0.tgz#1bdecdb8e083c0664b91945581577a43a9f31d70" + dependencies: + readable-stream "^2.0.2" + +flow-parser@^0.*: + version "0.69.0" + resolved "https://registry.yarnpkg.com/flow-parser/-/flow-parser-0.69.0.tgz#378b5128d6d0b554a8b2f16a4ca3e1ab9649f00e" + +flush-write-stream@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.0.3.tgz#c5d586ef38af6097650b49bc41b55fabb19f35bd" + dependencies: + inherits "^2.0.1" + readable-stream "^2.0.4" + +for-in@^1.0.1, for-in@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" for-own@^0.1.4: version "0.1.5" @@ -1223,6 +2287,10 @@ for-own@^0.1.4: dependencies: for-in "^1.0.1" +foreach@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" + forever-agent@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" @@ -1235,11 +2303,41 @@ form-data@~2.1.1: combined-stream "^1.0.5" mime-types "^2.1.12" +form-data@~2.3.1: + version "2.3.2" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.2.tgz#4970498be604c20c005d4f5c23aecd21d6b49099" + dependencies: + asynckit "^0.4.0" + combined-stream "1.0.6" + mime-types "^2.1.12" + +fragment-cache@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" + dependencies: + map-cache "^0.2.2" + +from2@^2.1.0, from2@^2.1.1: + version "2.3.0" + resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" + dependencies: + inherits "^2.0.1" + readable-stream "^2.0.0" + +fs-write-stream-atomic@^1.0.8: + version "1.0.10" + resolved "https://registry.yarnpkg.com/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz#b47df53493ef911df75731e70a9ded0189db40c9" + dependencies: + graceful-fs "^4.1.2" + iferr "^0.1.5" + imurmurhash "^0.1.4" + readable-stream "1 || 2" + fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" -fsevents@^1.0.0: +fsevents@^1.1.1, fsevents@^1.1.2: version "1.1.3" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.1.3.tgz#11f82318f5fe7bb2cd22965a108e9306208216d8" dependencies: @@ -1263,6 +2361,10 @@ fstream@^1.0.0, fstream@^1.0.10, fstream@^1.0.2: mkdirp ">=0.5 0" rimraf "2" +function-bind@^1.0.2, function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + gauge@~2.7.3: version "2.7.4" resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" @@ -1280,16 +2382,40 @@ get-caller-file@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5" -get-stream@^3.0.0: +get-stream@3.0.0, get-stream@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" +get-value@^2.0.3, get-value@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" + getpass@^0.1.1: version "0.1.7" resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" dependencies: assert-plus "^1.0.0" +gh-got@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/gh-got/-/gh-got-6.0.0.tgz#d74353004c6ec466647520a10bd46f7299d268d0" + dependencies: + got "^7.0.0" + is-plain-obj "^1.1.0" + +github-username@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/github-username/-/github-username-4.1.0.tgz#cbe280041883206da4212ae9e4b5f169c30bf417" + dependencies: + gh-got "^6.0.0" + +glob-all@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/glob-all/-/glob-all-3.1.0.tgz#8913ddfb5ee1ac7812656241b03d5217c64b02ab" + dependencies: + glob "^7.0.5" + yargs "~1.2.6" + glob-base@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" @@ -1303,7 +2429,14 @@ glob-parent@^2.0.0: dependencies: is-glob "^2.0.0" -glob@^7.0.5: +glob-parent@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" + dependencies: + is-glob "^3.1.0" + path-dirname "^1.0.0" + +glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.1, glob@^7.1.2: version "7.1.2" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" dependencies: @@ -1314,18 +2447,111 @@ glob@^7.0.5: once "^1.3.0" path-is-absolute "^1.0.0" +global-modules@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-1.0.0.tgz#6d770f0eb523ac78164d72b5e71a8877265cc3ea" + dependencies: + global-prefix "^1.0.1" + is-windows "^1.0.1" + resolve-dir "^1.0.0" + +global-prefix@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-1.0.2.tgz#dbf743c6c14992593c655568cb66ed32c0122ebe" + dependencies: + expand-tilde "^2.0.2" + homedir-polyfill "^1.0.1" + ini "^1.3.4" + is-windows "^1.0.1" + which "^1.2.14" + globals@^9.18.0: version "9.18.0" resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" -graceful-fs@^4.1.2: +globby@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-6.1.0.tgz#f5a6d70e8395e21c858fb0489d64df02424d506c" + dependencies: + array-union "^1.0.1" + glob "^7.0.3" + object-assign "^4.0.1" + pify "^2.0.0" + pinkie-promise "^2.0.0" + +got@^7.0.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/got/-/got-7.1.0.tgz#05450fd84094e6bbea56f451a43a9c289166385a" + dependencies: + decompress-response "^3.2.0" + duplexer3 "^0.1.4" + get-stream "^3.0.0" + is-plain-obj "^1.1.0" + is-retry-allowed "^1.0.0" + is-stream "^1.0.0" + isurl "^1.0.0-alpha5" + lowercase-keys "^1.0.0" + p-cancelable "^0.3.0" + p-timeout "^1.1.1" + safe-buffer "^5.0.1" + timed-out "^4.0.0" + url-parse-lax "^1.0.0" + url-to-options "^1.0.1" + +got@^8.2.0: + version "8.3.0" + resolved "https://registry.yarnpkg.com/got/-/got-8.3.0.tgz#6ba26e75f8a6cc4c6b3eb1fe7ce4fec7abac8533" + dependencies: + "@sindresorhus/is" "^0.7.0" + cacheable-request "^2.1.1" + decompress-response "^3.3.0" + duplexer3 "^0.1.4" + get-stream "^3.0.0" + into-stream "^3.1.0" + is-retry-allowed "^1.1.0" + isurl "^1.0.0-alpha5" + lowercase-keys "^1.0.0" + mimic-response "^1.0.0" + p-cancelable "^0.4.0" + p-timeout "^2.0.1" + pify "^3.0.0" + safe-buffer "^5.1.1" + timed-out "^4.0.1" + url-parse-lax "^3.0.0" + url-to-options "^1.0.1" + +graceful-fs@^4.1.11, graceful-fs@^4.1.2: version "4.1.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" +grouped-queue@^0.3.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/grouped-queue/-/grouped-queue-0.3.3.tgz#c167d2a5319c5a0e0964ef6a25b7c2df8996c85c" + dependencies: + lodash "^4.17.2" + +growly@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" + +handlebars@^4.0.3: + version "4.0.11" + resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.11.tgz#630a35dfe0294bc281edae6ffc5d329fc7982dcc" + dependencies: + async "^1.4.0" + optimist "^0.6.1" + source-map "^0.4.4" + optionalDependencies: + uglify-js "^2.6" + har-schema@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-1.0.5.tgz#d263135f43307c02c602afc8fe95970c0151369e" +har-schema@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" + har-validator@~4.2.1: version "4.2.1" resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-4.2.1.tgz#33481d0f1bbff600dd203d75812a6a5fba002e2a" @@ -1333,20 +2559,78 @@ har-validator@~4.2.1: ajv "^4.9.1" har-schema "^1.0.5" +har-validator@~5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.0.3.tgz#ba402c266194f15956ef15e0fcf242993f6a7dfd" + dependencies: + ajv "^5.1.0" + har-schema "^2.0.0" + has-ansi@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" dependencies: ansi-regex "^2.0.0" -has-flag@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51" +has-color@~0.1.0: + version "0.1.7" + resolved "https://registry.yarnpkg.com/has-color/-/has-color-0.1.7.tgz#67144a5260c34fc3cca677d041daf52fe7b78b2f" + +has-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa" + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + +has-symbol-support-x@^1.4.1: + version "1.4.2" + resolved "https://registry.yarnpkg.com/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz#1409f98bc00247da45da67cee0a36f282ff26455" + +has-to-string-tag-x@^1.2.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz#a045ab383d7b4b2012a00148ab0aa5f290044d4d" + dependencies: + has-symbol-support-x "^1.4.1" has-unicode@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" +has-value@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" + dependencies: + get-value "^2.0.3" + has-values "^0.1.4" + isobject "^2.0.0" + +has-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" + dependencies: + get-value "^2.0.6" + has-values "^1.0.0" + isobject "^3.0.0" + +has-values@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" + +has-values@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" + dependencies: + is-number "^3.0.0" + kind-of "^4.0.0" + +has@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.1.tgz#8461733f538b0837c9361e39a9ab9e9704dc2f28" + dependencies: + function-bind "^1.0.2" + hash-base@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-2.0.2.tgz#66ea1d856db4e8a5470cadf6fce23ae5244ef2e1" @@ -1376,6 +2660,19 @@ hawk@3.1.3, hawk@~3.1.3: hoek "2.x.x" sntp "1.x.x" +hawk@~6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/hawk/-/hawk-6.0.2.tgz#af4d914eb065f9b5ce4d9d11c1cb2126eecc3038" + dependencies: + boom "4.x.x" + cryptiles "3.x.x" + hoek "4.x.x" + sntp "2.x.x" + +he@1.1.x, he@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd" + hmac-drbg@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" @@ -1388,6 +2685,10 @@ hoek@2.x.x: version "2.16.3" resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" +hoek@4.x.x: + version "4.2.1" + resolved "https://registry.yarnpkg.com/hoek/-/hoek-4.2.1.tgz#9634502aa12c445dd5a7c5734b572bb8738aacbb" + home-or-tmp@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" @@ -1395,9 +2696,79 @@ home-or-tmp@^2.0.0: os-homedir "^1.0.0" os-tmpdir "^1.0.1" +homedir-polyfill@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz#4c2bbc8a758998feebf5ed68580f76d46768b4bc" + dependencies: + parse-passwd "^1.0.0" + hosted-git-info@^2.1.4: - version "2.5.0" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.5.0.tgz#6d60e34b3abbc8313062c3b798ef8d901a07af3c" + version "2.6.0" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.6.0.tgz#23235b29ab230c576aab0d4f13fc046b0b038222" + +html-encoding-sniffer@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz#e70d84b94da53aa375e11fe3a351be6642ca46f8" + dependencies: + whatwg-encoding "^1.0.1" + +html-minifier@^3.2.3: + version "3.5.12" + resolved "https://registry.yarnpkg.com/html-minifier/-/html-minifier-3.5.12.tgz#6bfad4d0327f5b8d2b62f5854654ac3703b9b031" + dependencies: + camel-case "3.0.x" + clean-css "4.1.x" + commander "2.15.x" + he "1.1.x" + ncname "1.0.x" + param-case "2.1.x" + relateurl "0.2.x" + uglify-js "3.3.x" + +html-webpack-plugin@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-3.1.0.tgz#6e02baaedb1e906310917f03239c793a75af2885" + dependencies: + html-minifier "^3.2.3" + loader-utils "^0.2.16" + lodash "^4.17.3" + pretty-error "^2.0.2" + tapable "^1.0.0" + toposort "^1.0.0" + util.promisify "1.0.0" + +htmlparser2@~3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.3.0.tgz#cc70d05a59f6542e43f0e685c982e14c924a9efe" + dependencies: + domelementtype "1" + domhandler "2.1" + domutils "1.1" + readable-stream "1.0" + +http-cache-semantics@3.8.1: + version "3.8.1" + resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz#39b0e16add9b605bf0a9ef3d9daaf4843b4cacd2" + +http-proxy@^1.8.1: + version "1.16.2" + resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.16.2.tgz#06dff292952bf64dbe8471fa9df73066d4f37742" + dependencies: + eventemitter3 "1.x.x" + requires-port "1.x.x" + +http-server@^0.11.1: + version "0.11.1" + resolved "https://registry.yarnpkg.com/http-server/-/http-server-0.11.1.tgz#2302a56a6ffef7f9abea0147d838a5e9b6b6a79b" + dependencies: + colors "1.0.3" + corser "~2.0.0" + ecstatic "^3.0.0" + http-proxy "^1.8.1" + opener "~1.4.0" + optimist "0.6.x" + portfinder "^1.0.13" + union "~0.4.3" http-signature@~1.1.0: version "1.1.1" @@ -1407,17 +2778,50 @@ http-signature@~1.1.0: jsprim "^1.2.2" sshpk "^1.7.0" +http-signature@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" + dependencies: + assert-plus "^1.0.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + https-browserify@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" -iconv-lite@~0.4.13: +iconv-lite@0.4.19, iconv-lite@^0.4.17, iconv-lite@~0.4.13: version "0.4.19" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" ieee754@^1.1.4: - version "1.1.8" - resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4" + version "1.1.11" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.11.tgz#c16384ffe00f5b7835824e67b6f2bd44a5229455" + +iferr@^0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501" + +import-local@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-1.0.0.tgz#5e4ffdc03f4fe6c009c6729beb29631c2f8227bc" + dependencies: + pkg-dir "^2.0.0" + resolve-cwd "^2.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + +indent-string@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80" + dependencies: + repeating "^2.0.0" + +indent-string@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-3.2.0.tgz#4a5fd6d27cc332f37e5419a504dbb837105c9289" indexof@0.0.1: version "0.0.1" @@ -1438,17 +2842,61 @@ inherits@2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" -ini@~1.3.0: +ini@^1.3.4, ini@~1.3.0: version "1.3.5" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" -interpret@^1.0.0: +inquirer@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.3.0.tgz#9dd2f2ad765dcab1ff0443b491442a20ba227dc9" + dependencies: + ansi-escapes "^3.0.0" + chalk "^2.0.0" + cli-cursor "^2.1.0" + cli-width "^2.0.0" + external-editor "^2.0.4" + figures "^2.0.0" + lodash "^4.3.0" + mute-stream "0.0.7" + run-async "^2.2.0" + rx-lite "^4.0.8" + rx-lite-aggregates "^4.0.8" + string-width "^2.1.0" + strip-ansi "^4.0.0" + through "^2.3.6" + +inquirer@^5.1.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-5.2.0.tgz#db350c2b73daca77ff1243962e9f22f099685726" + dependencies: + ansi-escapes "^3.0.0" + chalk "^2.0.0" + cli-cursor "^2.1.0" + cli-width "^2.0.0" + external-editor "^2.1.0" + figures "^2.0.0" + lodash "^4.3.0" + mute-stream "0.0.7" + run-async "^2.2.0" + rxjs "^5.5.2" + string-width "^2.1.0" + strip-ansi "^4.0.0" + through "^2.3.6" + +interpret@^1.0.0, interpret@^1.0.4: version "1.1.0" resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.1.0.tgz#7ed1b1410c6a0e0f78cf95d3b8440c63f78b8614" +into-stream@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/into-stream/-/into-stream-3.1.0.tgz#96fb0a936c12babd6ff1752a17d05616abd094c6" + dependencies: + from2 "^2.1.1" + p-is-promise "^1.1.0" + invariant@^2.2.2: - version "2.2.2" - resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.2.tgz#9e1f56ac0acdb6bf303306f338be3b204ae60360" + version "2.2.4" + resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" dependencies: loose-envify "^1.0.0" @@ -1456,6 +2904,18 @@ invert-kv@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" +is-accessor-descriptor@^0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" + dependencies: + kind-of "^3.0.2" + +is-accessor-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" + dependencies: + kind-of "^6.0.0" + is-arrayish@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" @@ -1476,6 +2936,48 @@ is-builtin-module@^1.0.0: dependencies: builtin-modules "^1.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" + +is-ci@^1.0.10: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-1.1.0.tgz#247e4162e7860cebbdaf30b774d6b0ac7dcfe7a5" + dependencies: + ci-info "^1.0.0" + +is-data-descriptor@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" + dependencies: + kind-of "^3.0.2" + +is-data-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" + dependencies: + kind-of "^6.0.0" + +is-date-object@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16" + +is-descriptor@^0.1.0: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" + dependencies: + is-accessor-descriptor "^0.1.6" + is-data-descriptor "^0.1.4" + kind-of "^5.0.0" + +is-descriptor@^1.0.0, is-descriptor@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" + dependencies: + is-accessor-descriptor "^1.0.0" + is-data-descriptor "^1.0.0" + kind-of "^6.0.2" + is-dotfile@^1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" @@ -1486,14 +2988,24 @@ is-equal-shallow@^0.1.3: dependencies: is-primitive "^2.0.0" -is-extendable@^0.1.1: +is-extendable@^0.1.0, is-extendable@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" +is-extendable@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" + dependencies: + is-plain-object "^2.0.4" + is-extglob@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" +is-extglob@^2.1.0, is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + is-finite@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" @@ -1510,12 +3022,28 @@ is-fullwidth-code-point@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" +is-generator-fn@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-1.0.0.tgz#969d49e1bb3329f6bb7f09089be26578b2ddd46a" + is-glob@^2.0.0, is-glob@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" dependencies: is-extglob "^1.0.0" +is-glob@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" + dependencies: + is-extglob "^2.1.0" + +is-glob@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.0.tgz#9521c76845cc2610a85203ddf080a958c2ffabc0" + dependencies: + is-extglob "^2.1.1" + is-number@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" @@ -1528,6 +3056,36 @@ is-number@^3.0.0: dependencies: kind-of "^3.0.2" +is-number@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff" + +is-object@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-object/-/is-object-1.0.1.tgz#8952688c5ec2ffd6b03ecc85e769e02903083470" + +is-observable@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/is-observable/-/is-observable-0.2.0.tgz#b361311d83c6e5d726cabf5e250b0237106f5ae2" + dependencies: + symbol-observable "^0.2.2" + +is-odd@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-odd/-/is-odd-2.0.0.tgz#7646624671fd7ea558ccd9a2795182f2958f1b24" + dependencies: + is-number "^4.0.0" + +is-plain-obj@^1.0.0, is-plain-obj@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" + +is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + dependencies: + isobject "^3.0.1" + is-posix-bracket@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" @@ -1536,14 +3094,50 @@ is-primitive@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" -is-stream@^1.0.1, is-stream@^1.1.0: +is-promise@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" + +is-regex@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" + dependencies: + has "^1.0.1" + +is-retry-allowed@^1.0.0, is-retry-allowed@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz#11a060568b67339444033d0125a61a20d564fb34" + +is-scoped@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-scoped/-/is-scoped-1.0.0.tgz#449ca98299e713038256289ecb2b540dc437cb30" + dependencies: + scoped-regex "^1.0.0" + +is-stream@^1.0.0, is-stream@^1.0.1, is-stream@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" +is-symbol@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.1.tgz#3cc59f00025194b6ab2e38dbae6689256b660572" + is-typedarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" +is-utf8@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" + +is-windows@^1.0.1, is-windows@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" + +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" @@ -1558,6 +3152,10 @@ isobject@^2.0.0: dependencies: isarray "1.0.0" +isobject@^3.0.0, isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + isomorphic-fetch@^2.1.1: version "2.2.1" resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9" @@ -1569,41 +3167,471 @@ isstream@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" -js-tokens@^3.0.0, js-tokens@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" - -jsbn@~0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" - -jsesc@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" - -jsesc@~0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" +istanbul-api@^1.1.14: + version "1.3.1" + resolved "https://registry.yarnpkg.com/istanbul-api/-/istanbul-api-1.3.1.tgz#4c3b05d18c0016d1022e079b98dc82c40f488954" + dependencies: + async "^2.1.4" + compare-versions "^3.1.0" + fileset "^2.0.2" + istanbul-lib-coverage "^1.2.0" + istanbul-lib-hook "^1.2.0" + istanbul-lib-instrument "^1.10.1" + istanbul-lib-report "^1.1.4" + istanbul-lib-source-maps "^1.2.4" + istanbul-reports "^1.3.0" + js-yaml "^3.7.0" + mkdirp "^0.5.1" + once "^1.4.0" -json-loader@^0.5.4: - version "0.5.7" - resolved "https://registry.yarnpkg.com/json-loader/-/json-loader-0.5.7.tgz#dca14a70235ff82f0ac9a3abeb60d337a365185d" +istanbul-lib-coverage@^1.1.1, istanbul-lib-coverage@^1.1.2, istanbul-lib-coverage@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-1.2.0.tgz#f7d8f2e42b97e37fe796114cb0f9d68b5e3a4341" -json-schema-traverse@^0.3.0: - version "0.3.1" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340" +istanbul-lib-hook@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-hook/-/istanbul-lib-hook-1.2.0.tgz#ae556fd5a41a6e8efa0b1002b1e416dfeaf9816c" + dependencies: + append-transform "^0.4.0" -json-schema@0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" +istanbul-lib-instrument@^1.10.1, istanbul-lib-instrument@^1.7.5, istanbul-lib-instrument@^1.8.0: + version "1.10.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-1.10.1.tgz#724b4b6caceba8692d3f1f9d0727e279c401af7b" + dependencies: + babel-generator "^6.18.0" + babel-template "^6.16.0" + babel-traverse "^6.18.0" + babel-types "^6.18.0" + babylon "^6.18.0" + istanbul-lib-coverage "^1.2.0" + semver "^5.3.0" -json-stable-stringify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" +istanbul-lib-report@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-1.1.4.tgz#e886cdf505c4ebbd8e099e4396a90d0a28e2acb5" dependencies: - jsonify "~0.0.0" + istanbul-lib-coverage "^1.2.0" + mkdirp "^0.5.1" + path-parse "^1.0.5" + supports-color "^3.1.2" -json-stringify-safe@~5.0.1: +istanbul-lib-source-maps@^1.2.1: + version "1.2.3" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.2.3.tgz#20fb54b14e14b3fb6edb6aca3571fd2143db44e6" + dependencies: + debug "^3.1.0" + istanbul-lib-coverage "^1.1.2" + mkdirp "^0.5.1" + rimraf "^2.6.1" + source-map "^0.5.3" + +istanbul-lib-source-maps@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.2.4.tgz#cc7ccad61629f4efff8e2f78adb8c522c9976ec7" + dependencies: + debug "^3.1.0" + istanbul-lib-coverage "^1.2.0" + mkdirp "^0.5.1" + rimraf "^2.6.1" + source-map "^0.5.3" + +istanbul-reports@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-1.3.0.tgz#2f322e81e1d9520767597dca3c20a0cce89a3554" + dependencies: + handlebars "^4.0.3" + +istextorbinary@^2.1.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/istextorbinary/-/istextorbinary-2.2.1.tgz#a5231a08ef6dd22b268d0895084cf8d58b5bec53" + dependencies: + binaryextensions "2" + editions "^1.3.3" + textextensions "2" + +isurl@^1.0.0-alpha5: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isurl/-/isurl-1.0.0.tgz#b27f4f49f3cdaa3ea44a0a5b7f3462e6edc39d67" + dependencies: + has-to-string-tag-x "^1.2.0" + is-object "^1.0.1" + +jest-changed-files@^22.4.3: + version "22.4.3" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-22.4.3.tgz#8882181e022c38bd46a2e4d18d44d19d90a90fb2" + dependencies: + throat "^4.0.0" + +jest-cli@^22.4.3: + version "22.4.3" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-22.4.3.tgz#bf16c4a5fb7edc3fa5b9bb7819e34139e88a72c7" + dependencies: + ansi-escapes "^3.0.0" + chalk "^2.0.1" + exit "^0.1.2" + glob "^7.1.2" + graceful-fs "^4.1.11" + import-local "^1.0.0" + is-ci "^1.0.10" + istanbul-api "^1.1.14" + istanbul-lib-coverage "^1.1.1" + istanbul-lib-instrument "^1.8.0" + istanbul-lib-source-maps "^1.2.1" + jest-changed-files "^22.4.3" + jest-config "^22.4.3" + jest-environment-jsdom "^22.4.3" + jest-get-type "^22.4.3" + jest-haste-map "^22.4.3" + jest-message-util "^22.4.3" + jest-regex-util "^22.4.3" + jest-resolve-dependencies "^22.4.3" + jest-runner "^22.4.3" + jest-runtime "^22.4.3" + jest-snapshot "^22.4.3" + jest-util "^22.4.3" + jest-validate "^22.4.3" + jest-worker "^22.4.3" + micromatch "^2.3.11" + node-notifier "^5.2.1" + realpath-native "^1.0.0" + rimraf "^2.5.4" + slash "^1.0.0" + string-length "^2.0.0" + strip-ansi "^4.0.0" + which "^1.2.12" + yargs "^10.0.3" + +jest-config@^22.4.3: + version "22.4.3" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-22.4.3.tgz#0e9d57db267839ea31309119b41dc2fa31b76403" + dependencies: + chalk "^2.0.1" + glob "^7.1.1" + jest-environment-jsdom "^22.4.3" + jest-environment-node "^22.4.3" + jest-get-type "^22.4.3" + jest-jasmine2 "^22.4.3" + jest-regex-util "^22.4.3" + jest-resolve "^22.4.3" + jest-util "^22.4.3" + jest-validate "^22.4.3" + pretty-format "^22.4.3" + +jest-diff@^22.4.3: + version "22.4.3" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-22.4.3.tgz#e18cc3feff0aeef159d02310f2686d4065378030" + dependencies: + chalk "^2.0.1" + diff "^3.2.0" + jest-get-type "^22.4.3" + pretty-format "^22.4.3" + +jest-docblock@^22.4.3: + version "22.4.3" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-22.4.3.tgz#50886f132b42b280c903c592373bb6e93bb68b19" + dependencies: + detect-newline "^2.1.0" + +jest-environment-jsdom@^22.4.3: + version "22.4.3" + resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-22.4.3.tgz#d67daa4155e33516aecdd35afd82d4abf0fa8a1e" + dependencies: + jest-mock "^22.4.3" + jest-util "^22.4.3" + jsdom "^11.5.1" + +jest-environment-node@^22.4.3: + version "22.4.3" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-22.4.3.tgz#54c4eaa374c83dd52a9da8759be14ebe1d0b9129" + dependencies: + jest-mock "^22.4.3" + jest-util "^22.4.3" + +jest-get-type@^22.4.3: + version "22.4.3" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-22.4.3.tgz#e3a8504d8479342dd4420236b322869f18900ce4" + +jest-haste-map@^22.4.3: + version "22.4.3" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-22.4.3.tgz#25842fa2ba350200767ac27f658d58b9d5c2e20b" + dependencies: + fb-watchman "^2.0.0" + graceful-fs "^4.1.11" + jest-docblock "^22.4.3" + jest-serializer "^22.4.3" + jest-worker "^22.4.3" + micromatch "^2.3.11" + sane "^2.0.0" + +jest-jasmine2@^22.4.3: + version "22.4.3" + resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-22.4.3.tgz#4daf64cd14c793da9db34a7c7b8dcfe52a745965" + dependencies: + chalk "^2.0.1" + co "^4.6.0" + expect "^22.4.3" + graceful-fs "^4.1.11" + is-generator-fn "^1.0.0" + jest-diff "^22.4.3" + jest-matcher-utils "^22.4.3" + jest-message-util "^22.4.3" + jest-snapshot "^22.4.3" + jest-util "^22.4.3" + source-map-support "^0.5.0" + +jest-leak-detector@^22.4.3: + version "22.4.3" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-22.4.3.tgz#2b7b263103afae8c52b6b91241a2de40117e5b35" + dependencies: + pretty-format "^22.4.3" + +jest-matcher-utils@^22.4.3: + version "22.4.3" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-22.4.3.tgz#4632fe428ebc73ebc194d3c7b65d37b161f710ff" + dependencies: + chalk "^2.0.1" + jest-get-type "^22.4.3" + pretty-format "^22.4.3" + +jest-message-util@^22.4.3: + version "22.4.3" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-22.4.3.tgz#cf3d38aafe4befddbfc455e57d65d5239e399eb7" + dependencies: + "@babel/code-frame" "^7.0.0-beta.35" + chalk "^2.0.1" + micromatch "^2.3.11" + slash "^1.0.0" + stack-utils "^1.0.1" + +jest-mock@^22.4.3: + version "22.4.3" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-22.4.3.tgz#f63ba2f07a1511772cdc7979733397df770aabc7" + +jest-regex-util@^22.4.3: + version "22.4.3" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-22.4.3.tgz#a826eb191cdf22502198c5401a1fc04de9cef5af" + +jest-resolve-dependencies@^22.4.3: + version "22.4.3" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-22.4.3.tgz#e2256a5a846732dc3969cb72f3c9ad7725a8195e" + dependencies: + jest-regex-util "^22.4.3" + +jest-resolve@^22.4.3: + version "22.4.3" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-22.4.3.tgz#0ce9d438c8438229aa9b916968ec6b05c1abb4ea" + dependencies: + browser-resolve "^1.11.2" + chalk "^2.0.1" + +jest-runner@^22.4.3: + version "22.4.3" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-22.4.3.tgz#298ddd6a22b992c64401b4667702b325e50610c3" + dependencies: + exit "^0.1.2" + jest-config "^22.4.3" + jest-docblock "^22.4.3" + jest-haste-map "^22.4.3" + jest-jasmine2 "^22.4.3" + jest-leak-detector "^22.4.3" + jest-message-util "^22.4.3" + jest-runtime "^22.4.3" + jest-util "^22.4.3" + jest-worker "^22.4.3" + throat "^4.0.0" + +jest-runtime@^22.4.3: + version "22.4.3" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-22.4.3.tgz#b69926c34b851b920f666c93e86ba2912087e3d0" + dependencies: + babel-core "^6.0.0" + babel-jest "^22.4.3" + babel-plugin-istanbul "^4.1.5" + chalk "^2.0.1" + convert-source-map "^1.4.0" + exit "^0.1.2" + graceful-fs "^4.1.11" + jest-config "^22.4.3" + jest-haste-map "^22.4.3" + jest-regex-util "^22.4.3" + jest-resolve "^22.4.3" + jest-util "^22.4.3" + jest-validate "^22.4.3" + json-stable-stringify "^1.0.1" + micromatch "^2.3.11" + realpath-native "^1.0.0" + slash "^1.0.0" + strip-bom "3.0.0" + write-file-atomic "^2.1.0" + yargs "^10.0.3" + +jest-serializer@^22.4.3: + version "22.4.3" + resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-22.4.3.tgz#a679b81a7f111e4766235f4f0c46d230ee0f7436" + +jest-snapshot@^22.4.3: + version "22.4.3" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-22.4.3.tgz#b5c9b42846ffb9faccb76b841315ba67887362d2" + dependencies: + chalk "^2.0.1" + jest-diff "^22.4.3" + jest-matcher-utils "^22.4.3" + mkdirp "^0.5.1" + natural-compare "^1.4.0" + pretty-format "^22.4.3" + +jest-util@^22.4.3: + version "22.4.3" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-22.4.3.tgz#c70fec8eec487c37b10b0809dc064a7ecf6aafac" + dependencies: + callsites "^2.0.0" + chalk "^2.0.1" + graceful-fs "^4.1.11" + is-ci "^1.0.10" + jest-message-util "^22.4.3" + mkdirp "^0.5.1" + source-map "^0.6.0" + +jest-validate@^22.4.3: + version "22.4.3" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-22.4.3.tgz#0780954a5a7daaeec8d3c10834b9280865976b30" + dependencies: + chalk "^2.0.1" + jest-config "^22.4.3" + jest-get-type "^22.4.3" + leven "^2.1.0" + pretty-format "^22.4.3" + +jest-worker@^22.4.3: + version "22.4.3" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-22.4.3.tgz#5c421417cba1c0abf64bf56bd5fb7968d79dd40b" + dependencies: + merge-stream "^1.0.1" + +jest@^22.4.3: + version "22.4.3" + resolved "https://registry.yarnpkg.com/jest/-/jest-22.4.3.tgz#2261f4b117dc46d9a4a1a673d2150958dee92f16" + dependencies: + import-local "^1.0.0" + jest-cli "^22.4.3" + +js-tokens@^3.0.0, js-tokens@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" + +js-yaml@^3.7.0: + version "3.11.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.11.0.tgz#597c1a8bd57152f26d622ce4117851a51f5ebaef" + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +jsbn@~0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" + +jscodeshift@^0.4.0: + version "0.4.1" + resolved "https://registry.yarnpkg.com/jscodeshift/-/jscodeshift-0.4.1.tgz#da91a1c2eccfa03a3387a21d39948e251ced444a" + dependencies: + async "^1.5.0" + babel-plugin-transform-flow-strip-types "^6.8.0" + babel-preset-es2015 "^6.9.0" + babel-preset-stage-1 "^6.5.0" + babel-register "^6.9.0" + babylon "^6.17.3" + colors "^1.1.2" + flow-parser "^0.*" + lodash "^4.13.1" + micromatch "^2.3.7" + node-dir "0.1.8" + nomnom "^1.8.1" + recast "^0.12.5" + temp "^0.8.1" + write-file-atomic "^1.2.0" + +jscodeshift@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/jscodeshift/-/jscodeshift-0.5.0.tgz#bdb7b6cc20dd62c16aa728c3fa2d2fe66ca7c748" + dependencies: + babel-plugin-transform-flow-strip-types "^6.8.0" + babel-preset-es2015 "^6.9.0" + babel-preset-stage-1 "^6.5.0" + babel-register "^6.9.0" + babylon "^7.0.0-beta.30" + colors "^1.1.2" + flow-parser "^0.*" + lodash "^4.13.1" + micromatch "^2.3.7" + neo-async "^2.5.0" + node-dir "0.1.8" + nomnom "^1.8.1" + recast "^0.14.1" + temp "^0.8.1" + write-file-atomic "^1.2.0" + +jsdom@^11.5.1: + version "11.6.2" + resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-11.6.2.tgz#25d1ef332d48adf77fc5221fe2619967923f16bb" + dependencies: + abab "^1.0.4" + acorn "^5.3.0" + acorn-globals "^4.1.0" + array-equal "^1.0.0" + browser-process-hrtime "^0.1.2" + content-type-parser "^1.0.2" + cssom ">= 0.3.2 < 0.4.0" + cssstyle ">= 0.2.37 < 0.3.0" + domexception "^1.0.0" + escodegen "^1.9.0" + html-encoding-sniffer "^1.0.2" + left-pad "^1.2.0" + nwmatcher "^1.4.3" + parse5 "4.0.0" + pn "^1.1.0" + request "^2.83.0" + request-promise-native "^1.0.5" + sax "^1.2.4" + symbol-tree "^3.2.2" + tough-cookie "^2.3.3" + w3c-hr-time "^1.0.1" + webidl-conversions "^4.0.2" + whatwg-encoding "^1.0.3" + whatwg-url "^6.4.0" + ws "^4.0.0" + xml-name-validator "^3.0.0" + +jsesc@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" + +jsesc@~0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + +json-buffer@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" + +json-parse-better-errors@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.1.tgz#50183cd1b2d25275de069e9e71b467ac9eab973a" + +json-schema-traverse@^0.3.0: + version "0.3.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340" + +json-schema@0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" + +json-stable-stringify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" + dependencies: + jsonify "~0.0.0" + +json-stringify-safe@~5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" @@ -1624,7 +3652,13 @@ jsprim@^1.2.2: json-schema "0.2.3" verror "1.10.0" -kind-of@^3.0.2: +keyv@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.0.0.tgz#44923ba39e68b12a7cec7df6c3268c031f2ef373" + dependencies: + json-buffer "3.0.0" + +kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: version "3.2.2" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" dependencies: @@ -1636,6 +3670,14 @@ kind-of@^4.0.0: dependencies: is-buffer "^1.1.5" +kind-of@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" + +kind-of@^6.0.0, kind-of@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051" + lazy-cache@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e" @@ -1646,20 +3688,102 @@ lcid@^1.0.0: dependencies: invert-kv "^1.0.0" -load-json-file@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8" +left-pad@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/left-pad/-/left-pad-1.2.0.tgz#d30a73c6b8201d8f7d8e7956ba9616087a68e0ee" + +leven@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/leven/-/leven-2.1.0.tgz#c2e7a9f772094dee9d34202ae8acce4687875580" + +levn@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + dependencies: + prelude-ls "~1.1.2" + type-check "~0.3.2" + +listr-silent-renderer@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/listr-silent-renderer/-/listr-silent-renderer-1.1.1.tgz#924b5a3757153770bf1a8e3fbf74b8bbf3f9242e" + +listr-update-renderer@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/listr-update-renderer/-/listr-update-renderer-0.4.0.tgz#344d980da2ca2e8b145ba305908f32ae3f4cc8a7" + dependencies: + chalk "^1.1.3" + cli-truncate "^0.2.1" + elegant-spinner "^1.0.1" + figures "^1.7.0" + indent-string "^3.0.0" + log-symbols "^1.0.2" + log-update "^1.0.2" + strip-ansi "^3.0.1" + +listr-verbose-renderer@^0.4.0: + version "0.4.1" + resolved "https://registry.yarnpkg.com/listr-verbose-renderer/-/listr-verbose-renderer-0.4.1.tgz#8206f4cf6d52ddc5827e5fd14989e0e965933a35" + dependencies: + chalk "^1.1.3" + cli-cursor "^1.0.2" + date-fns "^1.27.2" + figures "^1.7.0" + +listr@^0.13.0: + version "0.13.0" + resolved "https://registry.yarnpkg.com/listr/-/listr-0.13.0.tgz#20bb0ba30bae660ee84cc0503df4be3d5623887d" + dependencies: + chalk "^1.1.3" + cli-truncate "^0.2.1" + figures "^1.7.0" + indent-string "^2.1.0" + is-observable "^0.2.0" + is-promise "^2.1.0" + is-stream "^1.1.0" + listr-silent-renderer "^1.1.1" + listr-update-renderer "^0.4.0" + listr-verbose-renderer "^0.4.0" + log-symbols "^1.0.2" + log-update "^1.0.2" + ora "^0.2.3" + p-map "^1.1.1" + rxjs "^5.4.2" + stream-to-observable "^0.2.0" + strip-ansi "^3.0.1" + +load-json-file@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" dependencies: graceful-fs "^4.1.2" parse-json "^2.2.0" pify "^2.0.0" + pinkie-promise "^2.0.0" + strip-bom "^2.0.0" + +load-json-file@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b" + dependencies: + graceful-fs "^4.1.2" + parse-json "^4.0.0" + pify "^3.0.0" strip-bom "^3.0.0" loader-runner@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.3.0.tgz#f482aea82d543e07921700d5a46ef26fdac6b8a2" -loader-utils@^1.1.0: +loader-utils@^0.2.16: + version "0.2.17" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-0.2.17.tgz#f86e6374d43205a6e6c60e9196f17c0299bfb348" + dependencies: + big.js "^3.1.3" + emojis-list "^2.0.0" + json5 "^0.5.0" + object-assign "^4.0.1" + +loader-utils@^1.0.2, loader-utils@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.1.0.tgz#c98aef488bcceda2ffb5e2de646d6a754429f5cd" dependencies: @@ -1674,10 +3798,33 @@ locate-path@^2.0.0: p-locate "^2.0.0" path-exists "^3.0.0" -lodash@^4.14.0, lodash@^4.17.4, lodash@^4.17.5: +lodash.sortby@^4.7.0: + version "4.7.0" + resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" + +lodash@^4.13.1, lodash@^4.14.0, lodash@^4.17.2, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.3.0: version "4.17.5" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.5.tgz#99a92d65c0272debe8c96b6057bc8fbfa3bed511" +log-symbols@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-1.0.2.tgz#376ff7b58ea3086a0f09facc74617eca501e1a18" + dependencies: + chalk "^1.0.0" + +log-symbols@^2.1.0, log-symbols@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a" + dependencies: + chalk "^2.0.1" + +log-update@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/log-update/-/log-update-1.0.2.tgz#19929f64c4093d2d2e7075a1dad8af59c296b8d1" + dependencies: + ansi-escapes "^1.0.0" + cli-cursor "^1.0.2" + longest@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" @@ -1688,13 +3835,47 @@ loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.3.1: dependencies: js-tokens "^3.0.0" -lru-cache@^4.0.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.1.tgz#622e32e82488b49279114a4f9ecf45e7cd6bba55" +lower-case@^1.1.1: + version "1.1.4" + resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-1.1.4.tgz#9a2cabd1b9e8e0ae993a4bf7d5875c39c42e8eac" + +lowercase-keys@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.0.tgz#4e3366b39e7f5457e35f1324bdf6f88d0bfc7306" + +lowercase-keys@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" + +lru-cache@^4.0.1, lru-cache@^4.1.1: + version "4.1.2" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.2.tgz#45234b2e6e2f2b33da125624c4664929a0224c3f" dependencies: pseudomap "^1.0.2" yallist "^2.1.2" +make-dir@^1.0.0, make-dir@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.2.0.tgz#6d6a49eead4aae296c53bbf3a1a008bd6c89469b" + dependencies: + pify "^3.0.0" + +makeerror@1.0.x: + version "1.0.11" + resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c" + dependencies: + tmpl "1.0.x" + +map-cache@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" + +map-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" + dependencies: + object-visit "^1.0.0" + md5.js@^1.3.4: version "1.3.4" resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.4.tgz#e9bdbde94a20a5ac18b04340fc5764d5b09d901d" @@ -1702,6 +3883,29 @@ md5.js@^1.3.4: hash-base "^3.0.0" inherits "^2.0.1" +mem-fs-editor@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/mem-fs-editor/-/mem-fs-editor-3.0.2.tgz#dd0a6eaf2bb8a6b37740067aa549eb530105af9f" + dependencies: + commondir "^1.0.1" + deep-extend "^0.4.0" + ejs "^2.3.1" + glob "^7.0.3" + globby "^6.1.0" + mkdirp "^0.5.0" + multimatch "^2.0.0" + rimraf "^2.2.8" + through2 "^2.0.0" + vinyl "^2.0.1" + +mem-fs@^1.1.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/mem-fs/-/mem-fs-1.1.3.tgz#b8ae8d2e3fcb6f5d3f9165c12d4551a065d989cc" + dependencies: + through2 "^2.0.0" + vinyl "^1.1.0" + vinyl-file "^2.0.0" + mem@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/mem/-/mem-1.1.0.tgz#5edd52b485ca1d900fe64895505399a0dfa45f76" @@ -1715,7 +3919,17 @@ memory-fs@^0.4.0, memory-fs@~0.4.1: errno "^0.1.3" readable-stream "^2.0.1" -micromatch@^2.1.5: +merge-stream@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-1.0.1.tgz#4041202d508a342ba00174008df0c251b8c135e1" + dependencies: + readable-stream "^2.0.1" + +merge@^1.1.3: + version "1.2.0" + resolved "https://registry.yarnpkg.com/merge/-/merge-1.2.0.tgz#7531e39d4949c281a66b8c5a6e0265e8b05894da" + +micromatch@^2.3.11, micromatch@^2.3.7: version "2.3.11" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" dependencies: @@ -1733,6 +3947,24 @@ micromatch@^2.1.5: parse-glob "^3.0.4" regex-cache "^0.4.2" +micromatch@^3.1.4, micromatch@^3.1.8: + version "3.1.10" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + braces "^2.3.1" + define-property "^2.0.2" + extend-shallow "^3.0.2" + extglob "^2.0.4" + fragment-cache "^0.2.1" + kind-of "^6.0.2" + nanomatch "^1.2.9" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.2" + miller-rabin@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" @@ -1744,16 +3976,24 @@ mime-db@~1.33.0: version "1.33.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.33.0.tgz#a3492050a5cb9b63450541e39d9788d2272783db" -mime-types@^2.1.12, mime-types@~2.1.7: +mime-types@^2.1.12, mime-types@~2.1.17, mime-types@~2.1.7: version "2.1.18" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.18.tgz#6f323f60a83d11146f831ff11fd66e2fe5503bb8" dependencies: mime-db "~1.33.0" +mime@^1.4.1: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + mimic-fn@^1.0.0: version "1.2.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" +mimic-response@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.0.tgz#df3d3652a73fded6b9b0b24146e6fd052353458e" + minimalistic-assert@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz#702be2dda6b37f4836bcb3f5db56641b64a1d3d3" @@ -1762,7 +4002,7 @@ minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" -minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.4: +minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" dependencies: @@ -1772,23 +4012,122 @@ minimist@0.0.8: version "0.0.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" -minimist@^1.2.0: +minimist@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.1.0.tgz#99df657a52574c21c9057497df742790b2b4c0de" + +minimist@^1.1.0, minimist@^1.1.1, minimist@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" -"mkdirp@>=0.5 0", mkdirp@^0.5.1, mkdirp@~0.5.0: +minimist@~0.0.1: + version "0.0.10" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" + +mississippi@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-2.0.0.tgz#3442a508fafc28500486feea99409676e4ee5a6f" + dependencies: + concat-stream "^1.5.0" + duplexify "^3.4.2" + end-of-stream "^1.1.0" + flush-write-stream "^1.0.0" + from2 "^2.1.0" + parallel-transform "^1.1.0" + pump "^2.0.1" + pumpify "^1.3.3" + stream-each "^1.1.0" + through2 "^2.0.0" + +mixin-deep@^1.2.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.1.tgz#a49e7268dce1a0d9698e45326c5626df3543d0fe" + dependencies: + for-in "^1.0.2" + is-extendable "^1.0.1" + +mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0: version "0.5.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" dependencies: minimist "0.0.8" +move-concurrently@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92" + dependencies: + aproba "^1.1.1" + copy-concurrently "^1.0.0" + fs-write-stream-atomic "^1.0.8" + mkdirp "^0.5.1" + rimraf "^2.5.4" + run-queue "^1.0.3" + ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" +multimatch@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/multimatch/-/multimatch-2.1.0.tgz#9c7906a22fb4c02919e2f5f75161b4cdbd4b2a2b" + dependencies: + array-differ "^1.0.0" + array-union "^1.0.1" + arrify "^1.0.0" + minimatch "^3.0.0" + +mute-stream@0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" + nan@^2.3.0: - version "2.8.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.8.0.tgz#ed715f3fe9de02b57a5e6252d90a96675e1f085a" + version "2.10.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.10.0.tgz#96d0cd610ebd58d4b4de9cc0c6828cda99c7548f" + +nanomatch@^1.2.9: + version "1.2.9" + resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.9.tgz#879f7150cb2dab7a471259066c104eee6e0fa7c2" + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + define-property "^2.0.2" + extend-shallow "^3.0.2" + fragment-cache "^0.2.1" + is-odd "^2.0.0" + is-windows "^1.0.2" + kind-of "^6.0.2" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + +ncname@1.0.x: + version "1.0.0" + resolved "https://registry.yarnpkg.com/ncname/-/ncname-1.0.0.tgz#5b57ad18b1ca092864ef62b0b1ed8194f383b71c" + dependencies: + xml-char-classes "^1.0.0" + +neo-async@^2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.5.0.tgz#76b1c823130cca26acfbaccc8fbaf0a2fa33b18f" + +nice-try@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.4.tgz#d93962f6c52f2c1558c0fbda6d512819f1efe1c4" + +no-case@^2.2.0: + version "2.3.2" + resolved "https://registry.yarnpkg.com/no-case/-/no-case-2.3.2.tgz#60b813396be39b3f1288a4c1ed5d1e7d28b464ac" + dependencies: + lower-case "^1.1.1" + +node-dir@0.1.8: + version "0.1.8" + resolved "https://registry.yarnpkg.com/node-dir/-/node-dir-0.1.8.tgz#55fb8deb699070707fb67f91a460f0448294c77d" node-fetch@^1.0.1: version "1.7.3" @@ -1797,6 +4136,10 @@ node-fetch@^1.0.1: encoding "^0.1.11" is-stream "^1.0.1" +node-int64@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" + node-libs-browser@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.1.0.tgz#5f94263d404f6e44767d726901fff05478d600df" @@ -1825,6 +4168,15 @@ node-libs-browser@^2.0.0: util "^0.10.3" vm-browserify "0.0.4" +node-notifier@^5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-5.2.1.tgz#fa313dd08f5517db0e2502e5758d664ac69f9dea" + dependencies: + growly "^1.3.0" + semver "^5.4.1" + shellwords "^0.1.1" + which "^1.3.0" + node-pre-gyp@^0.6.39: version "0.6.39" resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.39.tgz#c00e96860b23c0e1420ac7befc5044e1d78d8649" @@ -1841,6 +4193,13 @@ node-pre-gyp@^0.6.39: tar "^2.2.1" tar-pack "^3.4.0" +nomnom@^1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/nomnom/-/nomnom-1.8.1.tgz#2151f722472ba79e50a76fc125bb8c8f2e4dc2a7" + dependencies: + chalk "~0.4.0" + underscore "~1.6.0" + nopt@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" @@ -1857,12 +4216,20 @@ normalize-package-data@^2.3.2: semver "2 || 3 || 4 || 5" validate-npm-package-license "^3.0.1" -normalize-path@^2.0.0, normalize-path@^2.0.1: +normalize-path@^2.0.1, normalize-path@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" dependencies: remove-trailing-separator "^1.0.1" +normalize-url@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-2.0.1.tgz#835a9da1551fa26f70e92329069a23aa6574d7e6" + dependencies: + prepend-http "^2.0.0" + query-string "^5.0.1" + sort-keys "^2.0.0" + npm-run-path@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" @@ -1878,11 +4245,21 @@ npmlog@^4.0.2: gauge "~2.7.3" set-blocking "~2.0.0" +nth-check@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-1.0.1.tgz#9929acdf628fc2c41098deab82ac580cf149aae4" + dependencies: + boolbase "~1.0.0" + number-is-nan@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" -oauth-sign@~0.8.1: +nwmatcher@^1.4.3: + version "1.4.4" + resolved "https://registry.yarnpkg.com/nwmatcher/-/nwmatcher-1.4.4.tgz#2285631f34a95f0d0395cd900c96ed39b58f346e" + +oauth-sign@~0.8.1, oauth-sign@~0.8.2: version "0.8.2" resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" @@ -1890,6 +4267,31 @@ object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" +object-copy@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" + dependencies: + copy-descriptor "^0.1.0" + define-property "^0.2.5" + kind-of "^3.0.3" + +object-keys@^1.0.8: + version "1.0.11" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.11.tgz#c54601778ad560f1142ce0e01bcca8b56d13426d" + +object-visit@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" + dependencies: + isobject "^3.0.0" + +object.getownpropertydescriptors@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz#8758c846f5b407adab0f236e0986f14b051caa16" + dependencies: + define-properties "^1.1.2" + es-abstract "^1.5.1" + object.omit@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" @@ -1897,12 +4299,59 @@ object.omit@^2.0.0: for-own "^0.1.4" is-extendable "^0.1.1" -once@^1.3.0, once@^1.3.3: +object.pick@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" + dependencies: + isobject "^3.0.1" + +once@^1.3.0, once@^1.3.1, once@^1.3.3, once@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" dependencies: wrappy "1" +onetime@^1.0.0: + version "1.1.0" + resolved "http://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" + +onetime@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" + dependencies: + mimic-fn "^1.0.0" + +opener@~1.4.0: + version "1.4.3" + resolved "https://registry.yarnpkg.com/opener/-/opener-1.4.3.tgz#5c6da2c5d7e5831e8ffa3964950f8d6674ac90b8" + +optimist@0.6.x, optimist@^0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" + dependencies: + minimist "~0.0.1" + wordwrap "~0.0.2" + +optionator@^0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" + dependencies: + deep-is "~0.1.3" + fast-levenshtein "~2.0.4" + levn "~0.3.0" + prelude-ls "~1.1.2" + type-check "~0.3.2" + wordwrap "~1.0.0" + +ora@^0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/ora/-/ora-0.2.3.tgz#37527d220adcd53c39b73571d754156d5db657a4" + dependencies: + chalk "^1.1.1" + cli-cursor "^1.0.2" + cli-spinners "^0.1.2" + object-assign "^4.0.1" + os-browserify@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" @@ -1919,7 +4368,7 @@ os-locale@^2.0.0: lcid "^1.0.0" mem "^1.1.0" -os-tmpdir@^1.0.0, os-tmpdir@^1.0.1: +os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" @@ -1930,10 +4379,32 @@ osenv@^0.1.4: os-homedir "^1.0.0" os-tmpdir "^1.0.0" +p-cancelable@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-0.3.0.tgz#b9e123800bcebb7ac13a479be195b507b98d30fa" + +p-cancelable@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-0.4.0.tgz#bcb41d35bf6097fc4367a065b6eb84b9b124eff0" + +p-each-series@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-each-series/-/p-each-series-1.0.0.tgz#930f3d12dd1f50e7434457a22cd6f04ac6ad7f71" + dependencies: + p-reduce "^1.0.0" + p-finally@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" +p-is-promise@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-1.1.0.tgz#9c9456989e9f6588017b0434d56097675c3da05e" + +p-lazy@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-lazy/-/p-lazy-1.0.0.tgz#ec53c802f2ee3ac28f166cc82d0b2b02de27a835" + p-limit@^1.1.0: version "1.2.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.2.0.tgz#0e92b6bedcb59f022c13d0f1949dc82d15909f1c" @@ -1946,6 +4417,26 @@ p-locate@^2.0.0: dependencies: p-limit "^1.1.0" +p-map@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-1.2.0.tgz#e4e94f311eabbc8633a1e79908165fca26241b6b" + +p-reduce@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-reduce/-/p-reduce-1.0.0.tgz#18c2b0dd936a4690a529f8231f58a0fdb6a47dfa" + +p-timeout@^1.1.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-1.2.1.tgz#5eb3b353b7fce99f101a1038880bb054ebbea386" + dependencies: + p-finally "^1.0.0" + +p-timeout@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-2.0.1.tgz#d8dd1979595d2dc0139e1fe46b8b646cb3cdf038" + dependencies: + p-finally "^1.0.0" + p-try@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" @@ -1954,6 +4445,20 @@ pako@~1.0.5: version "1.0.6" resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.6.tgz#0101211baa70c4bca4a0f63f2206e97b7dfaf258" +parallel-transform@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/parallel-transform/-/parallel-transform-1.1.0.tgz#d410f065b05da23081fcd10f28854c29bda33b06" + dependencies: + cyclist "~0.2.2" + inherits "^2.0.3" + readable-stream "^2.1.5" + +param-case@2.1.x: + version "2.1.1" + resolved "https://registry.yarnpkg.com/param-case/-/param-case-2.1.1.tgz#df94fd8cf6531ecf75e6bef9a0858fbc72be2247" + dependencies: + no-case "^2.2.0" + parse-asn1@^5.0.0: version "5.1.0" resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.0.tgz#37c4f9b7ed3ab65c74817b5f2480937fbf97c712" @@ -1979,10 +4484,39 @@ parse-json@^2.2.0: dependencies: error-ex "^1.2.0" +parse-json@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" + dependencies: + error-ex "^1.3.1" + json-parse-better-errors "^1.0.1" + +parse-passwd@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" + +parse5@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-4.0.0.tgz#6d78656e3da8d78b4ec0b906f7c08ef1dfe3f608" + +pascalcase@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" + path-browserify@0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.0.tgz#a0b870729aae214005b7d5032ec2cbbb0fb4451a" +path-dirname@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" + +path-exists@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" + dependencies: + pinkie-promise "^2.0.0" + path-exists@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" @@ -1991,15 +4525,27 @@ path-is-absolute@^1.0.0, path-is-absolute@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" -path-key@^2.0.0: +path-key@^2.0.0, path-key@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" -path-type@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73" +path-parse@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1" + +path-type@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" dependencies: + graceful-fs "^4.1.2" pify "^2.0.0" + pinkie-promise "^2.0.0" + +path-type@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" + dependencies: + pify "^3.0.0" pbkdf2@^3.0.3: version "3.0.14" @@ -2015,19 +4561,93 @@ performance-now@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5" -pify@^2.0.0: +performance-now@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" + +pify@^2.0.0, pify@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" +pify@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" + +pinkie-promise@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" + dependencies: + pinkie "^2.0.0" + +pinkie@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" + +pkg-dir@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b" + dependencies: + find-up "^2.1.0" + +pn@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/pn/-/pn-1.1.0.tgz#e2f4cef0e219f463c179ab37463e4e1ecdccbafb" + +portfinder@^1.0.13: + version "1.0.13" + resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.13.tgz#bb32ecd87c27104ae6ee44b5a3ccbf0ebb1aede9" + dependencies: + async "^1.5.2" + debug "^2.2.0" + mkdirp "0.5.x" + +posix-character-classes@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" + +prelude-ls@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + +prepend-http@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" + +prepend-http@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" + preserve@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" -private@^0.1.6, private@^0.1.7: +prettier@^1.5.3: + version "1.11.1" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.11.1.tgz#61e43fc4cd44e68f2b0dfc2c38cd4bb0fccdcc75" + +pretty-bytes@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-4.0.2.tgz#b2bf82e7350d65c6c33aa95aaa5a4f6327f61cd9" + +pretty-error@^2.0.2: + version "2.1.1" + resolved "https://registry.yarnpkg.com/pretty-error/-/pretty-error-2.1.1.tgz#5f4f87c8f91e5ae3f3ba87ab4cf5e03b1a17f1a3" + dependencies: + renderkid "^2.0.1" + utila "~0.4" + +pretty-format@^22.4.3: + version "22.4.3" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-22.4.3.tgz#f873d780839a9c02e9664c8a082e9ee79eaac16f" + dependencies: + ansi-regex "^3.0.0" + ansi-styles "^3.2.0" + +private@^0.1.6, private@^0.1.7, private@~0.1.5: version "0.1.8" resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" -process-nextick-args@~2.0.0: +process-nextick-args@^2.0.0, process-nextick-args@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" @@ -2035,6 +4655,10 @@ process@^0.11.10: version "0.11.10" resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" +promise-inflight@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" + promise@^7.1.1: version "7.3.1" resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf" @@ -2042,8 +4666,8 @@ promise@^7.1.1: asap "~2.0.3" prop-types@^15.6.0: - version "15.6.0" - resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.0.tgz#ceaf083022fc46b4a35f69e13ef75aed0d639856" + version "15.6.1" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.1.tgz#36644453564255ddda391191fb3a125cbdf654ca" dependencies: fbjs "^0.8.16" loose-envify "^1.3.1" @@ -2067,6 +4691,21 @@ public-encrypt@^4.0.0: parse-asn1 "^5.0.0" randombytes "^2.0.1" +pump@^2.0.0, pump@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909" + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +pumpify@^1.3.3: + version "1.4.0" + resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-1.4.0.tgz#80b7c5df7e24153d03f0e7ac8a05a5d068bd07fb" + dependencies: + duplexify "^3.5.3" + inherits "^2.0.3" + pump "^2.0.0" + punycode@1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" @@ -2075,10 +4714,30 @@ punycode@^1.2.4, punycode@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" +punycode@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.0.tgz#5f863edc89b96db09074bad7947bf09056ca4e7d" + +qs@~2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/qs/-/qs-2.3.3.tgz#e9e85adbe75da0bbe4c8e0476a086290f863b404" + qs@~6.4.0: version "6.4.0" resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233" +qs@~6.5.1: + version "6.5.1" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8" + +query-string@^5.0.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/query-string/-/query-string-5.1.1.tgz#a78c012b71c17e05f2e3fa2319dd330682efb3cb" + dependencies: + decode-uri-component "^0.2.0" + object-assign "^4.1.0" + strict-uri-encode "^1.0.0" + querystring-es3@^0.2.0: version "0.2.1" resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" @@ -2108,8 +4767,8 @@ randomfill@^1.0.3: safe-buffer "^5.1.0" rc@^1.1.7: - version "1.2.5" - resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.5.tgz#275cd687f6e3b36cc756baa26dfee80a790301fd" + version "1.2.6" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.6.tgz#eb18989c6d4f4f162c399f79ddd29f3835568092" dependencies: deep-extend "~0.4.0" ini "~1.3.0" @@ -2134,24 +4793,46 @@ react@^16.2.0: object-assign "^4.1.1" prop-types "^15.6.0" -read-pkg-up@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be" +read-chunk@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/read-chunk/-/read-chunk-2.1.0.tgz#6a04c0928005ed9d42e1a6ac5600e19cbc7ff655" + dependencies: + pify "^3.0.0" + safe-buffer "^5.1.1" + +read-pkg-up@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" + dependencies: + find-up "^1.0.0" + read-pkg "^1.0.0" + +read-pkg-up@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-3.0.0.tgz#3ed496685dba0f8fe118d0691dc51f4a1ff96f07" dependencies: find-up "^2.0.0" - read-pkg "^2.0.0" + read-pkg "^3.0.0" -read-pkg@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8" +read-pkg@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" dependencies: - load-json-file "^2.0.0" + load-json-file "^1.0.0" normalize-package-data "^2.3.2" - path-type "^2.0.0" + path-type "^1.0.0" -readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.3.3: - version "2.3.4" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.4.tgz#c946c3f47fa7d8eabc0b6150f4a12f69a4574071" +read-pkg@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389" + dependencies: + load-json-file "^4.0.0" + normalize-package-data "^2.3.2" + path-type "^3.0.0" + +"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.5: + version "2.3.5" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.5.tgz#b4f85003a938cbb6ecbce2a124fb1012bd1a838d" dependencies: core-util-is "~1.0.0" inherits "~2.0.3" @@ -2161,6 +4842,15 @@ readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable string_decoder "~1.0.3" util-deprecate "~1.0.1" +readable-stream@1.0: + version "1.0.34" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + readdirp@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78" @@ -2170,6 +4860,37 @@ readdirp@^2.0.0: readable-stream "^2.0.2" set-immediate-shim "^1.0.1" +realpath-native@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/realpath-native/-/realpath-native-1.0.0.tgz#7885721a83b43bd5327609f0ddecb2482305fdf0" + dependencies: + util.promisify "^1.0.0" + +recast@^0.12.5: + version "0.12.9" + resolved "https://registry.yarnpkg.com/recast/-/recast-0.12.9.tgz#e8e52bdb9691af462ccbd7c15d5a5113647a15f1" + dependencies: + ast-types "0.10.1" + core-js "^2.4.1" + esprima "~4.0.0" + private "~0.1.5" + source-map "~0.6.1" + +recast@^0.14.1: + version "0.14.7" + resolved "https://registry.yarnpkg.com/recast/-/recast-0.14.7.tgz#4f1497c2b5826d42a66e8e3c9d80c512983ff61d" + dependencies: + ast-types "0.11.3" + esprima "~4.0.0" + private "~0.1.5" + source-map "~0.6.1" + +rechoir@^0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" + dependencies: + resolve "^1.1.6" + regenerate@^1.2.1: version "1.3.3" resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.3.tgz#0c336d3980553d755c39b586ae3b20aa49c82b7f" @@ -2192,6 +4913,13 @@ regex-cache@^0.4.2: dependencies: is-equal-shallow "^0.1.3" +regex-not@^1.0.0, regex-not@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" + dependencies: + extend-shallow "^3.0.2" + safe-regex "^1.1.0" + regexpu-core@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240" @@ -2210,15 +4938,29 @@ regjsparser@^0.1.4: dependencies: jsesc "~0.5.0" +relateurl@0.2.x: + version "0.2.7" + resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9" + remove-trailing-separator@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" +renderkid@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/renderkid/-/renderkid-2.0.1.tgz#898cabfc8bede4b7b91135a3ffd323e58c0db319" + dependencies: + css-select "^1.1.0" + dom-converter "~0.1" + htmlparser2 "~3.3.0" + strip-ansi "^3.0.0" + utila "~0.3" + repeat-element@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" -repeat-string@^1.5.2: +repeat-string@^1.5.2, repeat-string@^1.6.1: version "1.6.1" resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" @@ -2228,6 +4970,28 @@ repeating@^2.0.0: dependencies: is-finite "^1.0.0" +replace-ext@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-0.0.1.tgz#29bbd92078a739f0bcce2b4ee41e837953522924" + +replace-ext@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-1.0.0.tgz#de63128373fcbf7c3ccfa4de5a480c45a67958eb" + +request-promise-core@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/request-promise-core/-/request-promise-core-1.1.1.tgz#3eee00b2c5aa83239cfb04c5700da36f81cd08b6" + dependencies: + lodash "^4.13.1" + +request-promise-native@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/request-promise-native/-/request-promise-native-1.0.5.tgz#5281770f68e0c9719e5163fd3fab482215f4fda5" + dependencies: + request-promise-core "1.1.1" + stealthy-require "^1.1.0" + tough-cookie ">=2.3.3" + request@2.81.0: version "2.81.0" resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0" @@ -2255,6 +5019,33 @@ request@2.81.0: tunnel-agent "^0.6.0" uuid "^3.0.0" +request@^2.83.0: + version "2.85.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.85.0.tgz#5a03615a47c61420b3eb99b7dba204f83603e1fa" + dependencies: + aws-sign2 "~0.7.0" + aws4 "^1.6.0" + caseless "~0.12.0" + combined-stream "~1.0.5" + extend "~3.0.1" + forever-agent "~0.6.1" + form-data "~2.3.1" + har-validator "~5.0.3" + hawk "~6.0.2" + http-signature "~1.2.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.17" + oauth-sign "~0.8.2" + performance-now "^2.1.0" + qs "~6.5.1" + safe-buffer "^5.1.1" + stringstream "~0.0.5" + tough-cookie "~2.3.3" + tunnel-agent "^0.6.0" + uuid "^3.1.0" + require-directory@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" @@ -2263,18 +5054,81 @@ require-main-filename@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" +requires-port@1.x.x: + version "1.0.0" + resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + +resolve-cwd@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a" + dependencies: + resolve-from "^3.0.0" + +resolve-dir@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-1.0.1.tgz#79a40644c362be82f26effe739c9bb5382046f43" + dependencies: + expand-tilde "^2.0.0" + global-modules "^1.0.0" + +resolve-from@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" + +resolve-url@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" + +resolve@1.1.7: + version "1.1.7" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" + +resolve@^1.1.6: + version "1.6.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.6.0.tgz#0fbd21278b27b4004481c395349e7aba60a9ff5c" + dependencies: + path-parse "^1.0.5" + +responselike@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" + dependencies: + lowercase-keys "^1.0.0" + +restore-cursor@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541" + dependencies: + exit-hook "^1.0.0" + onetime "^1.0.0" + +restore-cursor@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" + dependencies: + onetime "^2.0.0" + signal-exit "^3.0.2" + +ret@~0.1.10: + version "0.1.15" + resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" + right-align@^0.1.1: version "0.1.3" resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef" dependencies: align-text "^0.1.1" -rimraf@2, rimraf@^2.5.1, rimraf@^2.6.1: +rimraf@2, rimraf@^2.2.8, rimraf@^2.5.1, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2: version "2.6.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" dependencies: glob "^7.0.5" +rimraf@~2.2.6: + version "2.2.8" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.2.8.tgz#e439be2aaee327321952730f99a8929e4fc50582" + ripemd160@^2.0.0, ripemd160@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.1.tgz#0f4584295c53a3628af7e6d79aca21ce57d1c6e7" @@ -2282,14 +5136,81 @@ ripemd160@^2.0.0, ripemd160@^2.0.1: hash-base "^2.0.0" inherits "^2.0.1" +run-async@^2.0.0, run-async@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" + dependencies: + is-promise "^2.1.0" + +run-queue@^1.0.0, run-queue@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/run-queue/-/run-queue-1.0.3.tgz#e848396f057d223f24386924618e25694161ec47" + dependencies: + aproba "^1.1.1" + +rx-lite-aggregates@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz#753b87a89a11c95467c4ac1626c4efc4e05c67be" + dependencies: + rx-lite "*" + +rx-lite@*, rx-lite@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-4.0.8.tgz#0b1e11af8bc44836f04a6407e92da42467b79444" + +rxjs@^5.4.2, rxjs@^5.5.2: + version "5.5.8" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-5.5.8.tgz#b2b0809a57614ad6254c03d7446dea0d83ca3791" + dependencies: + symbol-observable "1.0.1" + safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" -"semver@2 || 3 || 4 || 5", semver@^5.3.0: +safe-regex@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" + dependencies: + ret "~0.1.10" + +sane@^2.0.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/sane/-/sane-2.5.0.tgz#6359cd676f5efd9988b264d8ce3b827dd6b27bec" + dependencies: + anymatch "^2.0.0" + exec-sh "^0.2.0" + fb-watchman "^2.0.0" + micromatch "^3.1.4" + minimist "^1.1.1" + walker "~1.0.5" + watch "~0.18.0" + optionalDependencies: + fsevents "^1.1.1" + +sax@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" + +schema-utils@^0.4.2, schema-utils@^0.4.5: + version "0.4.5" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-0.4.5.tgz#21836f0608aac17b78f9e3e24daff14a5ca13a3e" + dependencies: + ajv "^6.1.0" + ajv-keywords "^3.1.0" + +scoped-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/scoped-regex/-/scoped-regex-1.0.0.tgz#a346bb1acd4207ae70bd7c0c7ca9e566b6baddb8" + +"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.4.1, semver@^5.5.0: version "5.5.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" +serialize-javascript@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-1.4.0.tgz#7c958514db6ac2443a8abc062dc9f7886a7f6005" + set-blocking@^2.0.0, set-blocking@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" @@ -2298,13 +5219,31 @@ set-immediate-shim@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" +set-value@^0.4.3: + version "0.4.3" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-0.4.3.tgz#7db08f9d3d22dc7f78e53af3c3bf4666ecdfccf1" + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.1" + to-object-path "^0.3.0" + +set-value@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.0.tgz#71ae4a88f0feefbbf52d1ea604f3fb315ebb6274" + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.3" + split-string "^3.0.1" + setimmediate@^1.0.4, setimmediate@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" sha.js@^2.4.0, sha.js@^2.4.8: - version "2.4.10" - resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.10.tgz#b1fde5cd7d11a5626638a07c604ab909cfa31f9b" + version "2.4.11" + resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" dependencies: inherits "^2.0.1" safe-buffer "^5.0.1" @@ -2319,7 +5258,19 @@ shebang-regex@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" -signal-exit@^3.0.0: +shelljs@^0.8.0: + version "0.8.1" + resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.1.tgz#729e038c413a2254c4078b95ed46e0397154a9f1" + dependencies: + glob "^7.0.0" + interpret "^1.0.0" + rechoir "^0.6.2" + +shellwords@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" + +signal-exit@^3.0.0, signal-exit@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" @@ -2327,47 +5278,138 @@ slash@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" +slice-ansi@0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35" + +slide@^1.1.5: + version "1.1.6" + resolved "https://registry.yarnpkg.com/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707" + +snapdragon-node@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" + dependencies: + define-property "^1.0.0" + isobject "^3.0.0" + snapdragon-util "^3.0.1" + +snapdragon-util@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" + dependencies: + kind-of "^3.2.0" + +snapdragon@^0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" + dependencies: + base "^0.11.1" + debug "^2.2.0" + define-property "^0.2.5" + extend-shallow "^2.0.1" + map-cache "^0.2.2" + source-map "^0.5.6" + source-map-resolve "^0.5.0" + use "^3.1.0" + sntp@1.x.x: version "1.0.9" resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198" dependencies: hoek "2.x.x" +sntp@2.x.x: + version "2.1.0" + resolved "https://registry.yarnpkg.com/sntp/-/sntp-2.1.0.tgz#2c6cec14fedc2222739caf9b5c3d85d1cc5a2cc8" + dependencies: + hoek "4.x.x" + +sort-keys@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-2.0.0.tgz#658535584861ec97d730d6cf41822e1f56684128" + dependencies: + is-plain-obj "^1.0.0" + source-list-map@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.0.tgz#aaa47403f7b245a92fbc97ea08f250d6087ed085" +source-map-resolve@^0.5.0: + version "0.5.1" + resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.1.tgz#7ad0f593f2281598e854df80f19aae4b92d7a11a" + dependencies: + atob "^2.0.0" + decode-uri-component "^0.2.0" + resolve-url "^0.2.1" + source-map-url "^0.4.0" + urix "^0.1.0" + source-map-support@^0.4.15: version "0.4.18" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f" dependencies: source-map "^0.5.6" -source-map@^0.5.3, source-map@^0.5.6, source-map@^0.5.7, source-map@~0.5.1: +source-map-support@^0.5.0: + version "0.5.4" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.4.tgz#54456efa89caa9270af7cd624cc2f123e51fbae8" + dependencies: + source-map "^0.6.0" + +source-map-url@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" + +source-map@0.5.x, source-map@^0.5.3, source-map@^0.5.6, source-map@^0.5.7, source-map@~0.5.1: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" -source-map@~0.6.1: +source-map@^0.4.4: + version "0.4.4" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" + dependencies: + amdefine ">=0.0.4" + +source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" -spdx-correct@~1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-1.0.2.tgz#4b3073d933ff51f3912f03ac5519498a4150db40" +spdx-correct@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.0.0.tgz#05a5b4d7153a195bc92c3c425b69f3b2a9524c82" dependencies: - spdx-license-ids "^1.0.2" + spdx-expression-parse "^3.0.0" + spdx-license-ids "^3.0.0" -spdx-expression-parse@~1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz#9bdf2f20e1f40ed447fbe273266191fced51626c" +spdx-exceptions@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz#2c7ae61056c714a5b9b9b2b2af7d311ef5c78fe9" -spdx-license-ids@^1.0.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz#c9df7a3424594ade6bd11900d596696dc06bac57" +spdx-expression-parse@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0" + dependencies: + spdx-exceptions "^2.1.0" + spdx-license-ids "^3.0.0" + +spdx-license-ids@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz#7a7cd28470cc6d3a1cfe6d66886f6bc430d3ac87" + +split-string@^3.0.1, split-string@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" + dependencies: + extend-shallow "^3.0.0" + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" sshpk@^1.7.0: - version "1.13.1" - resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.13.1.tgz#512df6da6287144316dc4c18fe1cf1d940739be3" + version "1.14.1" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.14.1.tgz#130f5975eddad963f1d56f92b9ac6c51fa9f83eb" dependencies: asn1 "~0.2.3" assert-plus "^1.0.0" @@ -2379,6 +5421,27 @@ sshpk@^1.7.0: jsbn "~0.1.0" tweetnacl "~0.14.0" +ssri@^5.2.4: + version "5.3.0" + resolved "https://registry.yarnpkg.com/ssri/-/ssri-5.3.0.tgz#ba3872c9c6d33a0704a7d71ff045e5ec48999d06" + dependencies: + safe-buffer "^5.1.1" + +stack-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-1.0.1.tgz#d4f33ab54e8e38778b0ca5cfd3b3afb12db68620" + +static-extend@^0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" + dependencies: + define-property "^0.2.5" + object-copy "^0.1.0" + +stealthy-require@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b" + stream-browserify@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.1.tgz#66266ee5f9bdb9940a4e4514cafb43bb71e5c9db" @@ -2386,9 +5449,16 @@ stream-browserify@^2.0.1: inherits "~2.0.1" readable-stream "^2.0.2" +stream-each@^1.1.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/stream-each/-/stream-each-1.2.2.tgz#8e8c463f91da8991778765873fe4d960d8f616bd" + dependencies: + end-of-stream "^1.1.0" + stream-shift "^1.0.0" + stream-http@^2.7.2: - version "2.8.0" - resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.8.0.tgz#fd86546dac9b1c91aff8fc5d287b98fafb41bc10" + version "2.8.1" + resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.8.1.tgz#d0441be1a457a73a733a8a7b53570bebd9ef66a4" dependencies: builtin-status-codes "^3.0.0" inherits "^2.0.1" @@ -2396,6 +5466,31 @@ stream-http@^2.7.2: to-arraybuffer "^1.0.0" xtend "^4.0.0" +stream-shift@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.0.tgz#d5c752825e5367e786f78e18e445ea223a155952" + +stream-to-observable@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/stream-to-observable/-/stream-to-observable-0.2.0.tgz#59d6ea393d87c2c0ddac10aa0d561bc6ba6f0e10" + dependencies: + any-observable "^0.2.0" + +strict-uri-encode@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" + +string-length@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/string-length/-/string-length-2.0.0.tgz#d40dbb686a3ace960c1cffca562bf2c45f8363ed" + dependencies: + astral-regex "^1.0.0" + strip-ansi "^4.0.0" + +string-template@~0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/string-template/-/string-template-0.2.1.tgz#42932e598a352d01fc22ec3367d9d84eec6c9add" + string-width@^1.0.1, string-width@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" @@ -2404,20 +5499,30 @@ string-width@^1.0.1, string-width@^1.0.2: is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" -string-width@^2.0.0: +string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" dependencies: is-fullwidth-code-point "^2.0.0" strip-ansi "^4.0.0" -string_decoder@^1.0.0, string_decoder@~1.0.3: +string_decoder@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.0.tgz#384f322ee8a848e500effde99901bba849c5d403" + dependencies: + safe-buffer "~5.1.0" + +string_decoder@~0.10.x: + version "0.10.31" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + +string_decoder@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.3.tgz#0fc67d7c141825de94282dd536bec6b9bce860ab" dependencies: safe-buffer "~5.1.0" -stringstream@~0.0.4: +stringstream@~0.0.4, stringstream@~0.0.5: version "0.0.5" resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" @@ -2433,10 +5538,27 @@ strip-ansi@^4.0.0: dependencies: ansi-regex "^3.0.0" -strip-bom@^3.0.0: +strip-ansi@~0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-0.1.1.tgz#39e8a98d044d150660abe4a6808acf70bb7bc991" + +strip-bom-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-bom-stream/-/strip-bom-stream-2.0.0.tgz#f87db5ef2613f6968aa545abfe1ec728b6a829ca" + dependencies: + first-chunk-stream "^2.0.0" + strip-bom "^2.0.0" + +strip-bom@3.0.0, strip-bom@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" +strip-bom@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" + dependencies: + is-utf8 "^0.2.0" + strip-eof@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" @@ -2449,15 +5571,33 @@ supports-color@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" -supports-color@^4.2.1: - version "4.5.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-4.5.0.tgz#be7a0de484dec5c5cddf8b3d59125044912f635b" +supports-color@^3.1.2: + version "3.2.3" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6" + dependencies: + has-flag "^1.0.0" + +supports-color@^5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.3.0.tgz#5b24ac15db80fa927cf5227a4a33fd3c4c7676c0" dependencies: - has-flag "^2.0.0" + has-flag "^3.0.0" + +symbol-observable@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.0.1.tgz#8340fc4702c3122df5d22288f88283f513d3fdd4" + +symbol-observable@^0.2.2: + version "0.2.4" + resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-0.2.4.tgz#95a83db26186d6af7e7a18dbd9760a2f86d08f40" -tapable@^0.2.7: - version "0.2.8" - resolved "https://registry.yarnpkg.com/tapable/-/tapable-0.2.8.tgz#99372a5c999bf2df160afc0d74bed4f47948cd22" +symbol-tree@^3.2.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.2.tgz#ae27db38f660a7ae2e1c3b7d1bc290819b8519e6" + +tapable@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.0.0.tgz#cbb639d9002eed9c6b5975eb20598d7936f1f9f2" tar-pack@^3.4.0: version "3.4.1" @@ -2480,12 +5620,66 @@ tar@^2.2.1: fstream "^1.0.2" inherits "2" +temp@^0.8.1: + version "0.8.3" + resolved "https://registry.yarnpkg.com/temp/-/temp-0.8.3.tgz#e0c6bc4d26b903124410e4fed81103014dfc1f59" + dependencies: + os-tmpdir "^1.0.0" + rimraf "~2.2.6" + +test-exclude@^4.1.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-4.2.1.tgz#dfa222f03480bca69207ca728b37d74b45f724fa" + dependencies: + arrify "^1.0.1" + micromatch "^3.1.8" + object-assign "^4.1.0" + read-pkg-up "^1.0.1" + require-main-filename "^1.0.1" + +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + +textextensions@2: + version "2.2.0" + resolved "https://registry.yarnpkg.com/textextensions/-/textextensions-2.2.0.tgz#38ac676151285b658654581987a0ce1a4490d286" + +throat@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/throat/-/throat-4.1.0.tgz#89037cbc92c56ab18926e6ba4cbb200e15672a6a" + +through2@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.3.tgz#0004569b37c7c74ba39c43f3ced78d1ad94140be" + dependencies: + readable-stream "^2.1.5" + xtend "~4.0.1" + +through@^2.3.6: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + +timed-out@^4.0.0, timed-out@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" + timers-browserify@^2.0.4: version "2.0.6" resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.6.tgz#241e76927d9ca05f4d959819022f5b3664b64bae" dependencies: setimmediate "^1.0.4" +tmp@^0.0.33: + version "0.0.33" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + dependencies: + os-tmpdir "~1.0.2" + +tmpl@1.0.x: + version "1.0.4" + resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" + to-arraybuffer@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" @@ -2494,12 +5688,44 @@ to-fast-properties@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" -tough-cookie@~2.3.0: - version "2.3.3" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.3.tgz#0b618a5565b6dea90bf3425d04d55edc475a7561" +to-object-path@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" + dependencies: + kind-of "^3.0.2" + +to-regex-range@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" + dependencies: + is-number "^3.0.0" + repeat-string "^1.6.1" + +to-regex@^3.0.1, to-regex@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" + dependencies: + define-property "^2.0.2" + extend-shallow "^3.0.2" + regex-not "^1.0.2" + safe-regex "^1.1.0" + +toposort@^1.0.0: + version "1.0.6" + resolved "https://registry.yarnpkg.com/toposort/-/toposort-1.0.6.tgz#c31748e55d210effc00fdcdc7d6e68d7d7bb9cec" + +tough-cookie@>=2.3.3, tough-cookie@^2.3.3, tough-cookie@~2.3.0, tough-cookie@~2.3.3: + version "2.3.4" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.4.tgz#ec60cee38ac675063ffc97a5c18970578ee83655" dependencies: punycode "^1.4.1" +tr46@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09" + dependencies: + punycode "^2.1.0" + trim-right@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" @@ -2518,11 +5744,35 @@ tweetnacl@^0.14.3, tweetnacl@~0.14.0: version "0.14.5" resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" +type-check@~0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + dependencies: + prelude-ls "~1.1.2" + +typedarray@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + ua-parser-js@^0.7.9: version "0.7.17" resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.17.tgz#e9ec5f9498b9ec910e7ae3ac626a805c4d09ecac" -uglify-js@^2.8.29: +uglify-es@^3.3.4: + version "3.3.9" + resolved "https://registry.yarnpkg.com/uglify-es/-/uglify-es-3.3.9.tgz#0c1c4f0700bed8dbc124cdb304d2592ca203e677" + dependencies: + commander "~2.13.0" + source-map "~0.6.1" + +uglify-js@3.3.x: + version "3.3.16" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.3.16.tgz#23ba13efa27aa00885be7417819e8a9787f94028" + dependencies: + commander "~2.15.0" + source-map "~0.6.1" + +uglify-js@^2.6: version "2.8.29" resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.29.tgz#29c5733148057bb4e1f75df35b7a9cb72e6a59dd" dependencies: @@ -2535,18 +5785,103 @@ uglify-to-browserify@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7" -uglifyjs-webpack-plugin@^0.4.6: - version "0.4.6" - resolved "https://registry.yarnpkg.com/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-0.4.6.tgz#b951f4abb6bd617e66f63eb891498e391763e309" +uglifyjs-webpack-plugin@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-1.2.4.tgz#5eec941b2e9b8538be0a20fc6eda25b14c7c1043" dependencies: - source-map "^0.5.6" - uglify-js "^2.8.29" - webpack-sources "^1.0.1" + cacache "^10.0.4" + find-cache-dir "^1.0.0" + schema-utils "^0.4.5" + serialize-javascript "^1.4.0" + source-map "^0.6.1" + uglify-es "^3.3.4" + webpack-sources "^1.1.0" + worker-farm "^1.5.2" uid-number@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" +underscore@~1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.6.0.tgz#8b38b10cacdef63337b8b24e4ff86d45aea529a8" + +union-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4" + dependencies: + arr-union "^3.1.0" + get-value "^2.0.6" + is-extendable "^0.1.1" + set-value "^0.4.3" + +union@~0.4.3: + version "0.4.6" + resolved "https://registry.yarnpkg.com/union/-/union-0.4.6.tgz#198fbdaeba254e788b0efcb630bc11f24a2959e0" + dependencies: + qs "~2.3.3" + +unique-filename@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.0.tgz#d05f2fe4032560871f30e93cbe735eea201514f3" + dependencies: + unique-slug "^2.0.0" + +unique-slug@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.0.tgz#db6676e7c7cc0629878ff196097c78855ae9f4ab" + dependencies: + imurmurhash "^0.1.4" + +unset-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" + dependencies: + has-value "^0.3.1" + isobject "^3.0.0" + +untildify@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/untildify/-/untildify-3.0.2.tgz#7f1f302055b3fea0f3e81dc78eb36766cb65e3f1" + +upath@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/upath/-/upath-1.0.4.tgz#ee2321ba0a786c50973db043a50b7bcba822361d" + +upper-case@^1.1.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/upper-case/-/upper-case-1.1.3.tgz#f6b4501c2ec4cdd26ba78be7222961de77621598" + +uri-js@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-3.0.2.tgz#f90b858507f81dea4dcfbb3c4c3dbfa2b557faaa" + dependencies: + punycode "^2.1.0" + +urix@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" + +url-join@^2.0.2: + version "2.0.5" + resolved "https://registry.yarnpkg.com/url-join/-/url-join-2.0.5.tgz#5af22f18c052a000a48d7b82c5e9c2e2feeda728" + +url-parse-lax@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-1.0.0.tgz#7af8f303645e9bd79a272e7a14ac68bc0609da73" + dependencies: + prepend-http "^1.0.1" + +url-parse-lax@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c" + dependencies: + prepend-http "^2.0.0" + +url-to-options@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/url-to-options/-/url-to-options-1.0.1.tgz#1505a03a289a48cbd7a434efbaeec5055f5633a9" + url@^0.11.0: version "0.11.0" resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" @@ -2554,26 +5889,51 @@ url@^0.11.0: punycode "1.3.2" querystring "0.2.0" +use@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/use/-/use-3.1.0.tgz#14716bf03fdfefd03040aef58d8b4b85f3a7c544" + dependencies: + kind-of "^6.0.2" + util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" +util.promisify@1.0.0, util.promisify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.0.tgz#440f7165a459c9a16dc145eb8e72f35687097030" + dependencies: + define-properties "^1.1.2" + object.getownpropertydescriptors "^2.0.3" + util@0.10.3, util@^0.10.3: version "0.10.3" resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" dependencies: inherits "2.0.1" -uuid@^3.0.0: +utila@~0.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/utila/-/utila-0.3.3.tgz#d7e8e7d7e309107092b05f8d9688824d633a4226" + +utila@~0.4: + version "0.4.0" + resolved "https://registry.yarnpkg.com/utila/-/utila-0.4.0.tgz#8a16a05d445657a3aea5eecc5b12a4fa5379772c" + +uuid@^3.0.0, uuid@^3.1.0: version "3.2.1" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.2.1.tgz#12c528bb9d58d0b9265d9a2f6f0fe8be17ff1f14" +v8-compile-cache@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-1.1.2.tgz#8d32e4f16974654657e676e0e467a348e89b0dc4" + validate-npm-package-license@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz#2804babe712ad3379459acfbe24746ab2c303fbc" + version "3.0.3" + resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz#81643bcbef1bdfecd4623793dc4648948ba98338" dependencies: - spdx-correct "~1.0.0" - spdx-expression-parse "~1.0.0" + spdx-correct "^3.0.0" + spdx-expression-parse "^3.0.0" verror@1.10.0: version "1.10.0" @@ -2583,63 +5943,163 @@ verror@1.10.0: core-util-is "1.0.2" extsprintf "^1.2.0" +vinyl-file@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/vinyl-file/-/vinyl-file-2.0.0.tgz#a7ebf5ffbefda1b7d18d140fcb07b223efb6751a" + dependencies: + graceful-fs "^4.1.2" + pify "^2.3.0" + pinkie-promise "^2.0.0" + strip-bom "^2.0.0" + strip-bom-stream "^2.0.0" + vinyl "^1.1.0" + +vinyl@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-1.2.0.tgz#5c88036cf565e5df05558bfc911f8656df218884" + dependencies: + clone "^1.0.0" + clone-stats "^0.0.1" + replace-ext "0.0.1" + +vinyl@^2.0.1: + version "2.1.0" + resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-2.1.0.tgz#021f9c2cf951d6b939943c89eb5ee5add4fd924c" + dependencies: + clone "^2.1.1" + clone-buffer "^1.0.0" + clone-stats "^1.0.0" + cloneable-readable "^1.0.0" + remove-trailing-separator "^1.0.1" + replace-ext "^1.0.0" + vm-browserify@0.0.4: version "0.0.4" resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-0.0.4.tgz#5d7ea45bbef9e4a6ff65f95438e0a87c357d5a73" dependencies: indexof "0.0.1" -watchpack@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.4.0.tgz#4a1472bcbb952bd0a9bb4036801f954dfb39faac" +w3c-hr-time@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz#82ac2bff63d950ea9e3189a58a65625fedf19045" dependencies: - async "^2.1.2" - chokidar "^1.7.0" - graceful-fs "^4.1.2" + browser-process-hrtime "^0.1.2" + +walker@~1.0.5: + version "1.0.7" + resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb" + dependencies: + makeerror "1.0.x" + +watch@~0.18.0: + version "0.18.0" + resolved "https://registry.yarnpkg.com/watch/-/watch-0.18.0.tgz#28095476c6df7c90c963138990c0a5423eb4b986" + dependencies: + exec-sh "^0.2.0" + minimist "^1.2.0" -webpack-sources@^1.0.1: +watchpack@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.5.0.tgz#231e783af830a22f8966f65c4c4bacc814072eed" + dependencies: + chokidar "^2.0.2" + graceful-fs "^4.1.2" + neo-async "^2.5.0" + +webidl-conversions@^4.0.1, webidl-conversions@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" + +webpack-addons@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/webpack-addons/-/webpack-addons-1.1.5.tgz#2b178dfe873fb6e75e40a819fa5c26e4a9bc837a" + dependencies: + jscodeshift "^0.4.0" + +webpack-cli@^2.0.13: + version "2.0.13" + resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-2.0.13.tgz#6e2bd9ef91345344737217e22e29001ad8537518" + dependencies: + chalk "^2.3.2" + cross-spawn "^6.0.5" + diff "^3.5.0" + enhanced-resolve "^4.0.0" + glob-all "^3.1.0" + global-modules "^1.0.0" + got "^8.2.0" + inquirer "^5.1.0" + interpret "^1.0.4" + jscodeshift "^0.5.0" + listr "^0.13.0" + loader-utils "^1.1.0" + lodash "^4.17.5" + log-symbols "^2.2.0" + mkdirp "^0.5.1" + p-each-series "^1.0.0" + p-lazy "^1.0.0" + prettier "^1.5.3" + resolve-cwd "^2.0.0" + supports-color "^5.3.0" + v8-compile-cache "^1.1.2" + webpack-addons "^1.1.5" + yargs "^11.0.0" + yeoman-environment "^2.0.0" + yeoman-generator "^2.0.3" + +webpack-sources@^1.0.1, webpack-sources@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.1.0.tgz#a101ebae59d6507354d71d8013950a3a8b7a5a54" dependencies: source-list-map "^2.0.0" source-map "~0.6.1" -webpack@^3.11.0: - version "3.11.0" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-3.11.0.tgz#77da451b1d7b4b117adaf41a1a93b5742f24d894" +webpack@^4.4.1: + version "4.4.1" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.4.1.tgz#b0105789890c28bfce9f392623ef5850254328a4" dependencies: acorn "^5.0.0" - acorn-dynamic-import "^2.0.0" + acorn-dynamic-import "^3.0.0" ajv "^6.1.0" ajv-keywords "^3.1.0" - async "^2.1.2" - enhanced-resolve "^3.4.0" - escope "^3.6.0" - interpret "^1.0.0" - json-loader "^0.5.4" - json5 "^0.5.1" + chrome-trace-event "^0.1.1" + enhanced-resolve "^4.0.0" + eslint-scope "^3.7.1" loader-runner "^2.3.0" loader-utils "^1.1.0" memory-fs "~0.4.1" + micromatch "^3.1.8" mkdirp "~0.5.0" + neo-async "^2.5.0" node-libs-browser "^2.0.0" - source-map "^0.5.3" - supports-color "^4.2.1" - tapable "^0.2.7" - uglifyjs-webpack-plugin "^0.4.6" - watchpack "^1.4.0" + schema-utils "^0.4.2" + tapable "^1.0.0" + uglifyjs-webpack-plugin "^1.2.4" + watchpack "^1.5.0" webpack-sources "^1.0.1" - yargs "^8.0.2" + +whatwg-encoding@^1.0.1, whatwg-encoding@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.3.tgz#57c235bc8657e914d24e1a397d3c82daee0a6ba3" + dependencies: + iconv-lite "0.4.19" whatwg-fetch@>=0.10.0: version "2.0.3" resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz#9c84ec2dcf68187ff00bc64e1274b442176e1c84" +whatwg-url@^6.4.0: + version "6.4.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-6.4.0.tgz#08fdf2b9e872783a7a1f6216260a1d66cc722e08" + dependencies: + lodash.sortby "^4.7.0" + tr46 "^1.0.0" + webidl-conversions "^4.0.1" + which-module@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" -which@^1.2.9: +which@^1.2.12, which@^1.2.14, which@^1.2.9, which@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/which/-/which-1.3.0.tgz#ff04bdfc010ee547d780bec38e1ac1c2777d253a" dependencies: @@ -2659,6 +6119,20 @@ wordwrap@0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" +wordwrap@~0.0.2: + version "0.0.3" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" + +wordwrap@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" + +worker-farm@^1.5.2: + version "1.6.0" + resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.6.0.tgz#aecc405976fab5a95526180846f0dba288f3a4a0" + dependencies: + errno "~0.1.7" + wrap-ansi@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" @@ -2670,7 +6144,38 @@ wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" -xtend@^4.0.0: +write-file-atomic@^1.2.0: + version "1.3.4" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-1.3.4.tgz#f807a4f0b1d9e913ae7a48112e6cc3af1991b45f" + dependencies: + graceful-fs "^4.1.11" + imurmurhash "^0.1.4" + slide "^1.1.5" + +write-file-atomic@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.3.0.tgz#1ff61575c2e2a4e8e510d6fa4e243cce183999ab" + dependencies: + graceful-fs "^4.1.11" + imurmurhash "^0.1.4" + signal-exit "^3.0.2" + +ws@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-4.1.0.tgz#a979b5d7d4da68bf54efe0408967c324869a7289" + dependencies: + async-limiter "~1.0.0" + safe-buffer "~5.1.0" + +xml-char-classes@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/xml-char-classes/-/xml-char-classes-1.0.0.tgz#64657848a20ffc5df583a42ad8a277b4512bbc4d" + +xml-name-validator@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" + +xtend@^4.0.0, xtend@~4.0.0, xtend@~4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" @@ -2678,33 +6183,65 @@ y18n@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" +y18n@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" + yallist@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" -yargs-parser@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-7.0.0.tgz#8d0ac42f16ea55debd332caf4c4038b3e3f5dfd9" +yargs-parser@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-8.1.0.tgz#f1376a33b6629a5d063782944da732631e966950" dependencies: camelcase "^4.1.0" -yargs@^8.0.2: - version "8.0.2" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-8.0.2.tgz#6299a9055b1cefc969ff7e79c1d918dceb22c360" +yargs-parser@^9.0.2: + version "9.0.2" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-9.0.2.tgz#9ccf6a43460fe4ed40a9bb68f48d43b8a68cc077" dependencies: camelcase "^4.1.0" - cliui "^3.2.0" + +yargs@^10.0.3: + version "10.1.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-10.1.2.tgz#454d074c2b16a51a43e2fb7807e4f9de69ccb5c5" + dependencies: + cliui "^4.0.0" + decamelize "^1.1.1" + find-up "^2.1.0" + get-caller-file "^1.0.1" + os-locale "^2.0.0" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^2.0.0" + which-module "^2.0.0" + y18n "^3.2.1" + yargs-parser "^8.1.0" + +yargs@^11.0.0: + version "11.0.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-11.0.0.tgz#c052931006c5eee74610e5fc0354bedfd08a201b" + dependencies: + cliui "^4.0.0" decamelize "^1.1.1" + find-up "^2.1.0" get-caller-file "^1.0.1" os-locale "^2.0.0" - read-pkg-up "^2.0.0" require-directory "^2.1.1" require-main-filename "^1.0.1" set-blocking "^2.0.0" string-width "^2.0.0" which-module "^2.0.0" y18n "^3.2.1" - yargs-parser "^7.0.0" + yargs-parser "^9.0.2" + +yargs@~1.2.6: + version "1.2.6" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-1.2.6.tgz#9c7b4a82fd5d595b2bf17ab6dcc43135432fe34b" + dependencies: + minimist "^0.1.0" yargs@~3.10.0: version "3.10.0" @@ -2714,3 +6251,51 @@ yargs@~3.10.0: cliui "^2.1.0" decamelize "^1.0.0" window-size "0.1.0" + +yeoman-environment@^2.0.0, yeoman-environment@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/yeoman-environment/-/yeoman-environment-2.0.5.tgz#84f22bafa84088971fe99ea85f654a3a3dd2b693" + dependencies: + chalk "^2.1.0" + debug "^3.1.0" + diff "^3.3.1" + escape-string-regexp "^1.0.2" + globby "^6.1.0" + grouped-queue "^0.3.3" + inquirer "^3.3.0" + is-scoped "^1.0.0" + lodash "^4.17.4" + log-symbols "^2.1.0" + mem-fs "^1.1.0" + text-table "^0.2.0" + untildify "^3.0.2" + +yeoman-generator@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/yeoman-generator/-/yeoman-generator-2.0.3.tgz#19426ed22687ffe05d31526c3f1c2cf67ba768f3" + dependencies: + async "^2.6.0" + chalk "^2.3.0" + cli-table "^0.3.1" + cross-spawn "^5.1.0" + dargs "^5.1.0" + dateformat "^3.0.2" + debug "^3.1.0" + detect-conflict "^1.0.0" + error "^7.0.2" + find-up "^2.1.0" + github-username "^4.0.0" + istextorbinary "^2.1.0" + lodash "^4.17.4" + make-dir "^1.1.0" + mem-fs-editor "^3.0.2" + minimist "^1.2.0" + pretty-bytes "^4.0.2" + read-chunk "^2.1.0" + read-pkg-up "^3.0.0" + rimraf "^2.6.2" + run-async "^2.0.0" + shelljs "^0.8.0" + text-table "^0.2.0" + through2 "^2.0.0" + yeoman-environment "^2.0.5" From 71a8a56f72167daf584af7baee54ccd58ab9c7f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Wed, 4 Apr 2018 16:45:23 +0100 Subject: [PATCH 046/111] Ignores the .pnp directory Branch: ignore-pnp --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 809363f43e..faf5313b7c 100644 --- a/.gitignore +++ b/.gitignore @@ -22,4 +22,5 @@ test/fixtures/**/.fbkpm .idea .yarn-meta .pnp.js +.pnp /packages/lockfile/index.js From 85f3e6d0c2aece854ac47fe4931931d8af93d5e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Wed, 4 Apr 2018 16:47:41 +0100 Subject: [PATCH 047/111] Implements a blacklist that throws nicer errors when a package is required through a realpath'd path. Branch: location-blacklist --- src/util/generate-pnp-map-api.tpl.js | 20 ++++++++++++++++++++ src/util/generate-pnp-map.js | 23 +++++++++++++++++------ 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/src/util/generate-pnp-map-api.tpl.js b/src/util/generate-pnp-map-api.tpl.js index 00131a79a4..c8437382fc 100644 --- a/src/util/generate-pnp-map-api.tpl.js +++ b/src/util/generate-pnp-map-api.tpl.js @@ -13,10 +13,30 @@ const pathRegExp = /^(?!\.{0,2}(?:\/|$))((?:@[^\/]+\/)?[^\/]+)\/?(.*|)$/; const isDirRegExp = /[\\\/]$/; const topLevelLocator = {name: null, reference: null}; +const blacklistedLocator = {name: NaN, reference: NaN}; const moduleShims = new Map(); const moduleCache = new Map(); +/** + * Ensures that the returned locator isn't a blacklisted one. + */ + +// eslint-disable-next-line no-unused-vars +function blacklistCheck(locator) { + if (locator === blacklistedLocator) { + throw new Error( + [ + `A package has been resolved through a blacklisted path - this is usually caused by one of your tool calling`, + `"realpath" on the return value of "require.resolve". Since the returned values use symlinks to disambiguate`, + `peer dependencies, they must be passed untransformed to "require".`, + ].join(` `), + ); + } + + return locator; +} + $$SETUP_STATIC_TABLES(); /** diff --git a/src/util/generate-pnp-map.js b/src/util/generate-pnp-map.js index f293b746e4..4a9285c59e 100644 --- a/src/util/generate-pnp-map.js +++ b/src/util/generate-pnp-map.js @@ -24,7 +24,7 @@ type GeneratePnpMapOptions = {| workspaceLayout: ?WorkspaceLayout, |}; -function generateMaps(packageInformationStores: PackageInformationStores): string { +function generateMaps(packageInformationStores: PackageInformationStores, blacklistedLocations: Set): string { let code = ``; // Bake the information stores into our generated code @@ -55,6 +55,9 @@ function generateMaps(packageInformationStores: PackageInformationStores): strin // Also bake an inverse map that will allow us to find the package information based on the path code += `let locatorsByLocations = new Map([\n`; + for (const blacklistedLocation of blacklistedLocations) { + code += ` [${JSON.stringify(blacklistedLocation)}, blacklistedLocator],\n`; + } for (const [packageName, packageInformationStore] of packageInformationStores) { for (const [packageReference, {packageLocation}] of packageInformationStore) { if (packageName !== null) { @@ -99,7 +102,7 @@ function generateFindPackageLocator(packageInformationStores: PackageInformation code += `\n`; code += ` if (location.length >= ${length} && location[${length} - 1] === path.sep)\n`; code += ` if (match = locatorsByLocations.get(location.substr(0, ${length})))\n`; - code += ` return match;\n`; + code += ` return blacklistCheck(match);\n`; } code += `\n`; @@ -113,8 +116,9 @@ async function getPackageInformationStores( config: Config, seedPatterns: Array, {resolver, workspaceLayout}: GeneratePnpMapOptions, -): Promise { +): Promise<[PackageInformationStores, Set]> { const packageInformationStores: PackageInformationStores = new Map(); + const blacklistedLocations: Set = new Set(); const ensureTrailingSlash = (fsPath: string) => { return fsPath.replace(/[\\\/]?$/, path.sep); @@ -188,6 +192,10 @@ async function getPackageInformationStores( await fs.symlink(physicalLoc, virtualLoc); packageReference = `pnp:${hash}`; + + // We blacklist this path so that we can print a nicer error message if someone tries to require it (it usually + // means that they're using realpath on the return value of require.resolve) + blacklistedLocations.add(ensureTrailingSlash(physicalLoc)); } // Now that we have the final reference, we need to store it @@ -310,7 +318,7 @@ async function getPackageInformationStores( ]), ); - return packageInformationStores; + return [packageInformationStores, blacklistedLocations]; } export async function generatePnpMap( @@ -318,9 +326,12 @@ export async function generatePnpMap( seedPatterns: Array, {resolver, workspaceLayout}: GeneratePnpMapOptions, ): Promise { - const packageInformationStores = await getPackageInformationStores(config, seedPatterns, {resolver, workspaceLayout}); + const [packageInformationStores, blacklistedLocations] = await getPackageInformationStores(config, seedPatterns, { + resolver, + workspaceLayout, + }); const setupStaticTables = - generateMaps(packageInformationStores) + generateFindPackageLocator(packageInformationStores); + generateMaps(packageInformationStores, blacklistedLocations) + generateFindPackageLocator(packageInformationStores); return pnpApi.replace(/\$\$SETUP_STATIC_TABLES\(\);/, setupStaticTables); } From ebf93b3797199172dea75f8590f8a328cfcd1141 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Wed, 4 Apr 2018 16:53:00 +0100 Subject: [PATCH 048/111] Changes the order the locations are matched to package locators Branch: location-to-locator-match-order --- src/util/generate-pnp-map.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/util/generate-pnp-map.js b/src/util/generate-pnp-map.js index 4a9285c59e..7a59a1a38e 100644 --- a/src/util/generate-pnp-map.js +++ b/src/util/generate-pnp-map.js @@ -89,9 +89,10 @@ function generateFindPackageLocator(packageInformationStores: PackageInformation } } - // We sort the lengths by the number of time they are used, so that the more common ones are tested before the others + // We must try the larger lengths before the smaller ones, because smaller ones might also match the longest ones + // (for instance, /project/path will match /project/path/.pnp/global/node_modules/pnp-cf5f9c17b8f8db) const sortedLengths = Array.from(lengths.entries()).sort((a, b) => { - return b[1] - a[1]; + return b[0] - a[0]; }); // Generate a function that, given a file path, returns the associated package name From 406affa4202a036f243561634b6b62ba66a2eee8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Wed, 4 Apr 2018 16:54:08 +0100 Subject: [PATCH 049/111] Automatically adds packages as dependencies of themselves if possible Branch: implicit-self --- .../packages/self-require-trap-1.0.0/index.js | 10 ++++++ .../self-require-trap-1.0.0/package.json | 7 ++++ .../packages/self-require-trap-1.0.0/self.js | 1 + .../packages/self-require-trap-2.0.0/index.js | 10 ++++++ .../self-require-trap-2.0.0/package.json | 4 +++ .../packages/various-requires-1.0.0/self.js | 1 + .../pkg-tests/pkg-tests-specs/sources/pnp.js | 34 +++++++++++++++++++ src/util/generate-pnp-map.js | 6 ++++ 8 files changed, 73 insertions(+) create mode 100644 packages/pkg-tests/pkg-tests-fixtures/packages/self-require-trap-1.0.0/index.js create mode 100644 packages/pkg-tests/pkg-tests-fixtures/packages/self-require-trap-1.0.0/package.json create mode 100644 packages/pkg-tests/pkg-tests-fixtures/packages/self-require-trap-1.0.0/self.js create mode 100644 packages/pkg-tests/pkg-tests-fixtures/packages/self-require-trap-2.0.0/index.js create mode 100644 packages/pkg-tests/pkg-tests-fixtures/packages/self-require-trap-2.0.0/package.json create mode 100644 packages/pkg-tests/pkg-tests-fixtures/packages/various-requires-1.0.0/self.js diff --git a/packages/pkg-tests/pkg-tests-fixtures/packages/self-require-trap-1.0.0/index.js b/packages/pkg-tests/pkg-tests-fixtures/packages/self-require-trap-1.0.0/index.js new file mode 100644 index 0000000000..a6bf8f5865 --- /dev/null +++ b/packages/pkg-tests/pkg-tests-fixtures/packages/self-require-trap-1.0.0/index.js @@ -0,0 +1,10 @@ +/* @flow */ + +module.exports = require(`./package.json`); + +for (const key of [`dependencies`, `devDependencies`, `peerDependencies`]) { + for (const dep of Object.keys(module.exports[key] || {})) { + // $FlowFixMe The whole point of this file is to be dynamic + module.exports[key][dep] = require(dep); + } +} diff --git a/packages/pkg-tests/pkg-tests-fixtures/packages/self-require-trap-1.0.0/package.json b/packages/pkg-tests/pkg-tests-fixtures/packages/self-require-trap-1.0.0/package.json new file mode 100644 index 0000000000..b80acfc0e1 --- /dev/null +++ b/packages/pkg-tests/pkg-tests-fixtures/packages/self-require-trap-1.0.0/package.json @@ -0,0 +1,7 @@ +{ + "name": "self-require-trap", + "version": "1.0.0", + "dependencies": { + "self-require-trap": "2.0.0" + } +} diff --git a/packages/pkg-tests/pkg-tests-fixtures/packages/self-require-trap-1.0.0/self.js b/packages/pkg-tests/pkg-tests-fixtures/packages/self-require-trap-1.0.0/self.js new file mode 100644 index 0000000000..4b240ff44b --- /dev/null +++ b/packages/pkg-tests/pkg-tests-fixtures/packages/self-require-trap-1.0.0/self.js @@ -0,0 +1 @@ +module.exports = require('self-require-trap'); diff --git a/packages/pkg-tests/pkg-tests-fixtures/packages/self-require-trap-2.0.0/index.js b/packages/pkg-tests/pkg-tests-fixtures/packages/self-require-trap-2.0.0/index.js new file mode 100644 index 0000000000..a6bf8f5865 --- /dev/null +++ b/packages/pkg-tests/pkg-tests-fixtures/packages/self-require-trap-2.0.0/index.js @@ -0,0 +1,10 @@ +/* @flow */ + +module.exports = require(`./package.json`); + +for (const key of [`dependencies`, `devDependencies`, `peerDependencies`]) { + for (const dep of Object.keys(module.exports[key] || {})) { + // $FlowFixMe The whole point of this file is to be dynamic + module.exports[key][dep] = require(dep); + } +} diff --git a/packages/pkg-tests/pkg-tests-fixtures/packages/self-require-trap-2.0.0/package.json b/packages/pkg-tests/pkg-tests-fixtures/packages/self-require-trap-2.0.0/package.json new file mode 100644 index 0000000000..62b31dfeff --- /dev/null +++ b/packages/pkg-tests/pkg-tests-fixtures/packages/self-require-trap-2.0.0/package.json @@ -0,0 +1,4 @@ +{ + "name": "self-require-trap", + "version": "2.0.0" +} diff --git a/packages/pkg-tests/pkg-tests-fixtures/packages/various-requires-1.0.0/self.js b/packages/pkg-tests/pkg-tests-fixtures/packages/various-requires-1.0.0/self.js new file mode 100644 index 0000000000..c9733c6ca3 --- /dev/null +++ b/packages/pkg-tests/pkg-tests-fixtures/packages/various-requires-1.0.0/self.js @@ -0,0 +1 @@ +module.exports = require('various-requires'); diff --git a/packages/pkg-tests/pkg-tests-specs/sources/pnp.js b/packages/pkg-tests/pkg-tests-specs/sources/pnp.js index 69e3ed49ea..b716305c96 100644 --- a/packages/pkg-tests/pkg-tests-specs/sources/pnp.js +++ b/packages/pkg-tests/pkg-tests-specs/sources/pnp.js @@ -181,6 +181,40 @@ module.exports = makeTemporaryEnv => { ), ); + test( + `it should allow packages to require themselves`, + makeTemporaryEnv( + { + dependencies: {[`various-requires`]: `1.0.0`}, + }, + {plugNPlay: true}, + async ({path, run, source}) => { + await run(`install`); + + await expect(source(`require('various-requires/self') === require('various-requires')`)).resolves.toEqual( + true, + ); + }, + ), + ); + + test( + `it should not add the implicit self dependency if an explicit one already exists`, + makeTemporaryEnv( + { + dependencies: {[`self-require-trap`]: `1.0.0`}, + }, + {plugNPlay: true}, + async ({path, run, source}) => { + await run(`install`); + + await expect(source(`require('self-require-trap/self') !== require('self-require-trap')`)).resolves.toEqual( + true, + ); + }, + ), + ); + test( `it should run scripts using a Node version that auto-injects the hook`, makeTemporaryEnv( diff --git a/src/util/generate-pnp-map.js b/src/util/generate-pnp-map.js index 7a59a1a38e..363ace0e5e 100644 --- a/src/util/generate-pnp-map.js +++ b/src/util/generate-pnp-map.js @@ -263,6 +263,12 @@ async function getPackageInformationStores( packageInformation.packageDependencies.set(dependencyName, dependencyReference); } } + + // Finally, unless a package depends on a previous version of itself (that would be weird but correct...), we + // inject them an implicit dependency to themselves (so that they can require themselves) + if (!packageInformation.packageDependencies.has(packageName)) { + packageInformation.packageDependencies.set(packageName, packageReference); + } } return resolutions; From a58e77b1afa19c079484d1ef6a5dd803420ecea9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Wed, 4 Apr 2018 16:56:05 +0100 Subject: [PATCH 050/111] Updates the node resolution Branch: node-resolution-improvements --- .../pkg-tests/pkg-tests-specs/sources/pnp.js | 40 ++++++ src/util/generate-pnp-map-api.tpl.js | 121 +++++++++++------- 2 files changed, 118 insertions(+), 43 deletions(-) diff --git a/packages/pkg-tests/pkg-tests-specs/sources/pnp.js b/packages/pkg-tests/pkg-tests-specs/sources/pnp.js index b716305c96..20e0722468 100644 --- a/packages/pkg-tests/pkg-tests-specs/sources/pnp.js +++ b/packages/pkg-tests/pkg-tests-specs/sources/pnp.js @@ -370,6 +370,46 @@ module.exports = makeTemporaryEnv => { ); }); + test( + `it should load the index.js file when loading from a folder`, + makeTemporaryEnv({}, {plugNPlay: true}, async ({path, run, source}) => { + await run(`install`); + + const tmp = await createTemporaryFolder(); + + await writeFile(`${tmp}/folder/index.js`, `module.exports = 42;`); + + await expect(source(`require("${tmp}/folder")`)).resolves.toEqual(42); + }), + ); + + test( + `it should resolve the .js extension`, + makeTemporaryEnv({}, {plugNPlay: true}, async ({path, run, source}) => { + await run(`install`); + + const tmp = await createTemporaryFolder(); + + await writeFile(`${tmp}/file.js`, `module.exports = 42;`); + + await expect(source(`require("${tmp}/file")`)).resolves.toEqual(42); + }), + ); + + test( + `it should use the regular Node resolution when requiring files outside of the pnp install tree`, + makeTemporaryEnv({}, {plugNPlay: true}, async ({path, run, source}) => { + await run(`install`); + + const tmp = await createTemporaryFolder(); + + await writeFile(`${tmp}/node_modules/dep/index.js`, `module.exports = 42;`); + await writeFile(`${tmp}/index.js`, `require('dep')`); + + await source(`require("${tmp}/index.js")`); + }), + ); + test( `it should not setup pnp when calling a script outside of the install tree`, makeTemporaryEnv( diff --git a/src/util/generate-pnp-map-api.tpl.js b/src/util/generate-pnp-map-api.tpl.js index c8437382fc..c886474c94 100644 --- a/src/util/generate-pnp-map-api.tpl.js +++ b/src/util/generate-pnp-map-api.tpl.js @@ -8,6 +8,8 @@ const path = require('path'); const builtinModules = Module.builtinModules || Object.keys(process.binding('natives')); const originalLoader = Module._load; +const originalFindPath = Module._findPath; +const originalNodeModulePaths = Module._nodeModulePaths; const pathRegExp = /^(?!\.{0,2}(?:\/|$))((?:@[^\/]+\/)?[^\/]+)\/?(.*|)$/; const isDirRegExp = /[\\\/]$/; @@ -71,71 +73,98 @@ function getPackageInformationSafe(packageLocator) { } /** - * Returns the peer dependency resolutions about a package in a given location in the dependency tree in a safe way - * (will throw if they cannot be retrieved). + * Implements the node resolution for folder access and extension selection */ -function findPackageLocatorSafe(filesystemPath) { - const packageLocator = exports.findPackageLocator(filesystemPath); +function applyNodeExtensionResolution(filesystemPath) { + // We use this "infinite while" so that we can restart the process as long as we hit package folders + while (true) { + let stat; - if (!packageLocator) { - throw new Error(`Couldn't find an owner for path "${filesystemPath}"`); - } + try { + stat = fs.statSync(filesystemPath); + } catch (error) {} - return packageLocator; -} + // If the file exists and is a file, we can stop right there -/** - */ + if (stat && !stat.isDirectory()) { + return filesystemPath; + } -function applyNodeExtensionResolution(filesystemPath) { - // If the file exists and is a file, we can stop right there + // If the file is a directory, we must check if it contains a package.json with a "main" entry - let stat; + if (stat && stat.isDirectory()) { + let pkgJson; - try { - stat = fs.statSync(filesystemPath); - } catch (error) {} + try { + pkgJson = JSON.parse(fs.readFileSync(`${filesystemPath}/package.json`, 'utf-8')); + } catch (error) {} - if (stat && !stat.isDirectory()) { - return filesystemPath; - } + let nextFilesystemPath; - // Otherwise we check if we find a file that match one of the supported extensions + if (pkgJson && pkgJson.main) { + nextFilesystemPath = path.resolve(filesystemPath, pkgJson.main); + } - const extensions = Object.keys(Module._extensions); + // If the "main" field changed the path, we start again from this new location - const qualifiedFile = extensions - .map(extension => { - return `${filesystemPath}${extension}`; - }) - .find(candidateFile => { - return fs.existsSync(candidateFile); - }); + if (nextFilesystemPath && nextFilesystemPath !== filesystemPath) { + filesystemPath = nextFilesystemPath; + continue; + } + } - if (qualifiedFile) { - return qualifiedFile; - } + // Otherwise we check if we find a file that match one of the supported extensions - // Otherwise, we check if the path is a folder - in such a case, we try to use its index + const extensions = Object.keys(Module._extensions); - if (stat && stat.isDirectory()) { - const indexFile = extensions + const qualifiedFile = extensions .map(extension => { - return `${filesystemPath}/index${extension}`; + return `${filesystemPath}${extension}`; }) .find(candidateFile => { return fs.existsSync(candidateFile); }); - if (indexFile) { - return indexFile; + if (qualifiedFile) { + return qualifiedFile; + } + + // Otherwise, we check if the path is a folder - in such a case, we try to use its index + + if (stat && stat.isDirectory()) { + const indexFile = extensions + .map(extension => { + return `${filesystemPath}/index${extension}`; + }) + .find(candidateFile => { + return fs.existsSync(candidateFile); + }); + + if (indexFile) { + return indexFile; + } } + + // Otherwise there's nothing else we can do :( + + return null; } +} - // Otherwise there's nothing else we can do :( +/** + * Forward the resolution to the next resolver (usually the native one) + */ + +function callNativeResolution(request, issuer) { + if (issuer.endsWith('/')) { + issuer += 'internal.js'; + } + + const paths = originalNodeModulePaths.call(Module, issuer); + const result = originalFindPath.call(Module, request, paths, false); - return null; + return result; } /** @@ -196,7 +225,15 @@ exports.resolveRequest = function resolveRequest(request, issuer) { if (dependencyNameMatch) { const [, dependencyName, subPath] = dependencyNameMatch; - const issuerLocator = findPackageLocatorSafe(issuer); + const issuerLocator = exports.findPackageLocator(issuer); + + // If the issuer file doesn't seem to be owned by a package managed through pnp, then we resort to using the next + // resolution algorithm in the chain, usually the native Node resolution one + + if (!issuerLocator) { + return callNativeResolution(request, issuer); + } + const issuerInformation = getPackageInformationSafe(issuerLocator); // We obtain the dependency reference in regard to the package that request it @@ -256,8 +293,6 @@ exports.resolveRequest = function resolveRequest(request, issuer) { if (subPath) { filesystemPath = path.resolve(dependencyLocation, subPath); // slice(1) to strip the leading '/' - } else if (dependencyInformation.packageMainEntry) { - filesystemPath = path.resolve(dependencyLocation, dependencyInformation.packageMainEntry); } else { filesystemPath = dependencyLocation; } From 824798f007dbc903246530be55f7048b1ac2ff36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Fri, 6 Apr 2018 15:47:44 +0100 Subject: [PATCH 051/111] Ensures that binaries are set as executable in the cache Branch: chmod-bins --- src/fetchers/base-fetcher.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/fetchers/base-fetcher.js b/src/fetchers/base-fetcher.js index a4ad776ba6..ce8dca2fc8 100644 --- a/src/fetchers/base-fetcher.js +++ b/src/fetchers/base-fetcher.js @@ -71,6 +71,9 @@ export default class BaseFetcher { // calling the binary const src = pkg.bin[binName]; + // We ensure that the target is executable + await fs.chmod(`${this.dest}/${src}`, 0o755); + await makePortableProxyScript(src, dest, { proxyBasename: binName, pnpPackageName: pkg.name, From 67edc56bd538f8296c77417c3b8e2476ef376cf5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Wed, 11 Apr 2018 18:49:50 -0700 Subject: [PATCH 052/111] Disables integrity checks when running under pnp Branch: pnp-no-integrity --- src/cli/commands/install.js | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/cli/commands/install.js b/src/cli/commands/install.js index 9084d8ce02..7dbd815021 100644 --- a/src/cli/commands/install.js +++ b/src/cli/commands/install.js @@ -424,6 +424,10 @@ export class Install { } async bailout(patterns: Array, workspaceLayout: ?WorkspaceLayout): Promise { + // PNP is so fast that the integrity check isn't pertinent + if (this.config.plugnplayEnabled) { + return false; + } if (this.flags.skipIntegrityCheck || this.flags.force) { return false; } @@ -652,13 +656,15 @@ export class Install { // fin! // The second condition is to make sure lockfile can be updated when running `remove` command. - if ( - topLevelPatterns.length || - (await fs.exists(path.join(this.config.lockfileFolder, constants.LOCKFILE_FILENAME))) - ) { - await this.saveLockfileAndIntegrity(topLevelPatterns, workspaceLayout); - } else { - this.reporter.info(this.reporter.lang('notSavedLockfileNoDependencies')); + if (!this.config.plugnplayEnabled) { + if ( + topLevelPatterns.length || + (await fs.exists(path.join(this.config.lockfileFolder, constants.LOCKFILE_FILENAME))) + ) { + await this.saveLockfileAndIntegrity(topLevelPatterns, workspaceLayout); + } else { + this.reporter.info(this.reporter.lang('notSavedLockfileNoDependencies')); + } } this.maybeOutputUpdate(); this.config.requestManager.clearCache(); From b2256f4a93b6ae00a7a1c261db7e4a6da5e9a7a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Wed, 11 Apr 2018 18:50:13 -0700 Subject: [PATCH 053/111] Makes the .pnp.js file an actual executable that can be used as a resolution server Branch: pnp-executable --- src/cli/commands/install.js | 6 +++++- src/util/generate-pnp-map-api.tpl.js | 30 ++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/src/cli/commands/install.js b/src/cli/commands/install.js index 7dbd815021..d06caf8553 100644 --- a/src/cli/commands/install.js +++ b/src/cli/commands/install.js @@ -602,7 +602,11 @@ export class Install { resolver: this.resolver, workspaceLayout, }); - await fs.writeFile(`${this.config.lockfileFolder}/${constants.PNP_FILENAME}`, code); + + const pnpPath = `${this.config.lockfileFolder}/${constants.PNP_FILENAME}`; + + await fs.writeFile(pnpPath, code); + await fs.chmod(pnpPath, 0o755); }), ); } diff --git a/src/util/generate-pnp-map-api.tpl.js b/src/util/generate-pnp-map-api.tpl.js index c886474c94..bc4946ebdf 100644 --- a/src/util/generate-pnp-map-api.tpl.js +++ b/src/util/generate-pnp-map-api.tpl.js @@ -1,9 +1,12 @@ +#!/usr/bin/env node + /* eslint-disable max-len, flowtype/require-valid-file-annotation, flowtype/require-return-type */ /* global packageInformationStores, $$SETUP_STATIC_TABLES */ const fs = require('fs'); const Module = require('module'); const path = require('path'); +const StringDecoder = require('string_decoder'); const builtinModules = Module.builtinModules || Object.keys(process.binding('natives')); @@ -457,3 +460,30 @@ if (module.parent && module.parent.id === 'internal/preload') { exports.setupCompatibilityLayer(); } } + +if (process.mainModule === module) { + let buffer = ''; + let decoder = new StringDecoder.StringDecoder(); + + process.stdin.on('data', chunk => { + buffer += decoder.write(chunk); + + do { + const index = buffer.indexOf('\n'); + if (index === -1) { + break; + } + + const line = buffer.slice(0, index); + buffer = buffer.slice(index + 1); + + try { + const data = JSON.parse(line); + console.log(exports.resolveRequest(data[0], data[1])); + } catch (error) { + console.log(error.message); + continue; + } + } while (true); + }); +} From 155a2a99df4b29cf73ce49d110966f42bfe3035d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Mon, 16 Apr 2018 15:44:36 +0100 Subject: [PATCH 054/111] Removes pnp-env --- pnp-env/.babelrc | 11 - pnp-env/.gitignore | 4 - pnp-env/.yarnrc | 1 - pnp-env/jest.config.js | 4 - pnp-env/package.json | 23 - pnp-env/scripts/jest-resolver.js | 5 - pnp-env/scripts/webpack-resolver.js | 35 - pnp-env/sources/__tests__/fibonacci.js | 36 - pnp-env/sources/fibonacci.js | 22 - pnp-env/sources/index.js | 38 - pnp-env/webpack.config.js | 41 - pnp-env/yarn.lock | 6301 ------------------------ 12 files changed, 6521 deletions(-) delete mode 100644 pnp-env/.babelrc delete mode 100644 pnp-env/.gitignore delete mode 100644 pnp-env/.yarnrc delete mode 100644 pnp-env/jest.config.js delete mode 100644 pnp-env/package.json delete mode 100644 pnp-env/scripts/jest-resolver.js delete mode 100644 pnp-env/scripts/webpack-resolver.js delete mode 100644 pnp-env/sources/__tests__/fibonacci.js delete mode 100644 pnp-env/sources/fibonacci.js delete mode 100644 pnp-env/sources/index.js delete mode 100644 pnp-env/webpack.config.js delete mode 100644 pnp-env/yarn.lock diff --git a/pnp-env/.babelrc b/pnp-env/.babelrc deleted file mode 100644 index e40a7275b0..0000000000 --- a/pnp-env/.babelrc +++ /dev/null @@ -1,11 +0,0 @@ -{ - "presets": ["react", ["env", { - "targets": { - "browsers": ["last 2 versions"] - } - }]], - "plugins": [ - "transform-class-properties", - "transform-decorators-legacy" - ] -} diff --git a/pnp-env/.gitignore b/pnp-env/.gitignore deleted file mode 100644 index ede4892698..0000000000 --- a/pnp-env/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -dist -node_modules -yarn-error.log -.pnp* diff --git a/pnp-env/.yarnrc b/pnp-env/.yarnrc deleted file mode 100644 index 26211b285f..0000000000 --- a/pnp-env/.yarnrc +++ /dev/null @@ -1 +0,0 @@ -plugnplay-experimental true diff --git a/pnp-env/jest.config.js b/pnp-env/jest.config.js deleted file mode 100644 index 9553f3c51b..0000000000 --- a/pnp-env/jest.config.js +++ /dev/null @@ -1,4 +0,0 @@ -module.exports = { - transform: { [`^.+\\.js$`]: require.resolve('babel-jest') }, - resolver: './scripts/jest-resolver', -}; diff --git a/pnp-env/package.json b/pnp-env/package.json deleted file mode 100644 index da7a71a02b..0000000000 --- a/pnp-env/package.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "dependencies": { - "core-decorators": "^0.20.0", - "lodash": "^4.17.5", - "react": "^16.2.0", - "react-dom": "^16.2.0" - }, - "devDependencies": { - "babel-core": "^6.4.1", - "babel-jest": "^22.4.3", - "babel-loader": "^7.1.4", - "babel-plugin-transform-class-properties": "^6.24.1", - "babel-plugin-transform-decorators-legacy": "^1.3.4", - "babel-preset-env": "^1.6.1", - "babel-preset-react": "^6.24.1", - "html-webpack-plugin": "^3.1.0", - "http-server": "^0.11.1", - "jest": "^22.4.3", - "jest-environment-jsdom": "^22.4.3", - "webpack": "^4.4.1", - "webpack-cli": "^2.0.13" - } -} diff --git a/pnp-env/scripts/jest-resolver.js b/pnp-env/scripts/jest-resolver.js deleted file mode 100644 index a70dc9c755..0000000000 --- a/pnp-env/scripts/jest-resolver.js +++ /dev/null @@ -1,5 +0,0 @@ -let pnp = require('../.pnp.js'); - -module.exports = (request, {basedir}) => { - return pnp.resolveRequest(request, `${basedir}/`); -}; diff --git a/pnp-env/scripts/webpack-resolver.js b/pnp-env/scripts/webpack-resolver.js deleted file mode 100644 index 9745ed55bb..0000000000 --- a/pnp-env/scripts/webpack-resolver.js +++ /dev/null @@ -1,35 +0,0 @@ -const pnp = require(`../.pnp.js`); - -module.exports = { - apply: function(resolver) { - const resolvedHook = resolver.ensureHook(`resolved`); - resolver.getHook(`resolve`).tapAsync(`PnpResolver`, (request, resolveContext, callback) => { - if (request.context.issuer === undefined) { - return callback(); - } - - let issuer; - let resolution; - - if (!request.context.issuer) { - issuer = `${request.path}/`; - } else if (request.context.issuer.startsWith(`/`)) { - issuer = request.context.issuer; - } else { - throw new Error(`Cannot successfully resolve this dependency`); - } - - try { - resolution = pnp.resolveRequest(request.request, issuer); - } catch (error) { - // TODO This is not good! But the `debug` package tries to require `supports-color` without declaring it in its - // package.json, and Webpack accepts this because it`s in a try/catch, so we need to do it as well. - return callback(error); - } - - resolver.doResolve(resolvedHook, Object.assign({}, request, { - path: resolution, - }), null, resolveContext, callback); - }); - } -}; diff --git a/pnp-env/sources/__tests__/fibonacci.js b/pnp-env/sources/__tests__/fibonacci.js deleted file mode 100644 index 27bcf6a1c8..0000000000 --- a/pnp-env/sources/__tests__/fibonacci.js +++ /dev/null @@ -1,36 +0,0 @@ -import { fibonacci } from '../fibonacci'; - -describe(`fibonacci`, () => { - it(`should work for negative values`, () => { - expect(fibonacci(-10)).toEqual(-55); - expect(fibonacci(-9)).toEqual(34); - expect(fibonacci(-8)).toEqual(-21); - expect(fibonacci(-7)).toEqual(13); - expect(fibonacci(-6)).toEqual(-8); - expect(fibonacci(-5)).toEqual(5); - expect(fibonacci(-4)).toEqual(-3); - expect(fibonacci(-3)).toEqual(2); - expect(fibonacci(-2)).toEqual(-1); - expect(fibonacci(-1)).toEqual(1); - }); - - it(`should work for zero values`, () => { - expect(fibonacci(-0)).toEqual(0); - expect(fibonacci(+0)).toEqual(0); - }); - - it(`should work for positive values`, () => { - expect(fibonacci(+1)).toEqual(1); - expect(fibonacci(+2)).toEqual(1); - expect(fibonacci(+5)).toEqual(5); - expect(fibonacci(+10)).toEqual(55); - }); - - it(`should return -Infinity for -Infinity`, () => { - expect(fibonacci(-Infinity)).toEqual(-Infinity); - }); - - it(`should return +Infinity for +Infinity`, () => { - expect(fibonacci(+Infinity)).toEqual(+Infinity); - }); -}); diff --git a/pnp-env/sources/fibonacci.js b/pnp-env/sources/fibonacci.js deleted file mode 100644 index ca5bb4d07f..0000000000 --- a/pnp-env/sources/fibonacci.js +++ /dev/null @@ -1,22 +0,0 @@ -export function fibonacci(n) { - - if (n === -Infinity) - return -Infinity; - - if (n === +Infinity) - return +Infinity; - - if (n === 0) - return 0; - - let A = (1 + Math.sqrt(5)) / 2; - let B = (1 - Math.sqrt(5)) / 2; - - let res = Math.ceil((Math.pow(A, n) - Math.pow(B, n)) / Math.sqrt(5)); - - if (res <= 0) - res -= 1; - - return res; - -} diff --git a/pnp-env/sources/index.js b/pnp-env/sources/index.js deleted file mode 100644 index 63e4606380..0000000000 --- a/pnp-env/sources/index.js +++ /dev/null @@ -1,38 +0,0 @@ -import { autobind } from 'core-decorators'; -import React from 'react'; -import ReactDOM from 'react-dom'; - -import { fibonacci } from './fibonacci'; - -class Application extends React.PureComponent { - - state = { - n: `1`, - }; - - @autobind handleChange(e) { - - this.setState({ - n: e.target.value, - }); - - } - - render() { - - return
- - Everything is working just fine! And as a bonus, here's a fibonacci number calculator: - -
- - -
- -
; - - } - -} - -ReactDOM.render(, document.body); diff --git a/pnp-env/webpack.config.js b/pnp-env/webpack.config.js deleted file mode 100644 index 219dc6c0c5..0000000000 --- a/pnp-env/webpack.config.js +++ /dev/null @@ -1,41 +0,0 @@ -const HtmlWebpackPlugin = require(`html-webpack-plugin`); -const PnpWebpackPlugin = require(`./scripts/webpack-resolver`); - -module.exports = { - - mode: `production`, - - entry: { - [`app`]: `./sources/index.js`, - }, - - output: { - filename: `[name].js`, - }, - - module: { - rules: [{ - test: /\.js$/, - exclude: /node_modules/, - loader: require.resolve('babel-loader'), - options: {}, - }] - }, - - resolve: { - plugins: [ - PnpWebpackPlugin, - ] - }, - - resolveLoader: { - plugins: [ - PnpWebpackPlugin, - ] - }, - - plugins: [ - new HtmlWebpackPlugin() - ] - -}; diff --git a/pnp-env/yarn.lock b/pnp-env/yarn.lock deleted file mode 100644 index e60f8bfb3b..0000000000 --- a/pnp-env/yarn.lock +++ /dev/null @@ -1,6301 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@babel/code-frame@^7.0.0-beta.35": - version "7.0.0-beta.42" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0-beta.42.tgz#a9c83233fa7cd06b39dc77adbb908616ff4f1962" - dependencies: - "@babel/highlight" "7.0.0-beta.42" - -"@babel/highlight@7.0.0-beta.42": - version "7.0.0-beta.42" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.0.0-beta.42.tgz#a502a1c0d6f99b2b0e81d468a1b0c0e81e3f3623" - dependencies: - chalk "^2.0.0" - esutils "^2.0.2" - js-tokens "^3.0.0" - -"@sindresorhus/is@^0.7.0": - version "0.7.0" - resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.7.0.tgz#9a06f4f137ee84d7df0460c1fdb1135ffa6c50fd" - -abab@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/abab/-/abab-1.0.4.tgz#5faad9c2c07f60dd76770f71cf025b62a63cfd4e" - -abbrev@1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" - -acorn-dynamic-import@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/acorn-dynamic-import/-/acorn-dynamic-import-3.0.0.tgz#901ceee4c7faaef7e07ad2a47e890675da50a278" - dependencies: - acorn "^5.0.0" - -acorn-globals@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-4.1.0.tgz#ab716025dbe17c54d3ef81d32ece2b2d99fe2538" - dependencies: - acorn "^5.0.0" - -acorn@^5.0.0, acorn@^5.3.0: - version "5.5.3" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.5.3.tgz#f473dd47e0277a08e28e9bec5aeeb04751f0b8c9" - -ajv-keywords@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.1.0.tgz#ac2b27939c543e95d2c06e7f7f5c27be4aa543be" - -ajv@^4.9.1: - version "4.11.8" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536" - dependencies: - co "^4.6.0" - json-stable-stringify "^1.0.1" - -ajv@^5.1.0: - version "5.5.2" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965" - dependencies: - co "^4.6.0" - fast-deep-equal "^1.0.0" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.3.0" - -ajv@^6.1.0: - version "6.4.0" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.4.0.tgz#d3aff78e9277549771daf0164cff48482b754fc6" - dependencies: - fast-deep-equal "^1.0.0" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.3.0" - uri-js "^3.0.2" - -align-text@^0.1.1, align-text@^0.1.3: - version "0.1.4" - resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117" - dependencies: - kind-of "^3.0.2" - longest "^1.0.1" - repeat-string "^1.5.2" - -amdefine@>=0.0.4: - version "1.0.1" - resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" - -ansi-escapes@^1.0.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" - -ansi-escapes@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.1.0.tgz#f73207bb81207d75fd6c83f125af26eea378ca30" - -ansi-regex@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" - -ansi-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" - -ansi-styles@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" - -ansi-styles@^3.2.0, ansi-styles@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" - dependencies: - color-convert "^1.9.0" - -ansi-styles@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-1.0.0.tgz#cb102df1c56f5123eab8b67cd7b98027a0279178" - -any-observable@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/any-observable/-/any-observable-0.2.0.tgz#c67870058003579009083f54ac0abafb5c33d242" - -anymatch@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" - dependencies: - micromatch "^3.1.4" - normalize-path "^2.1.1" - -append-transform@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/append-transform/-/append-transform-0.4.0.tgz#d76ebf8ca94d276e247a36bad44a4b74ab611991" - dependencies: - default-require-extensions "^1.0.0" - -aproba@^1.0.3, aproba@^1.1.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" - -are-we-there-yet@~1.1.2: - version "1.1.4" - resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz#bb5dca382bb94f05e15194373d16fd3ba1ca110d" - dependencies: - delegates "^1.0.0" - readable-stream "^2.0.6" - -argparse@^1.0.7: - version "1.0.10" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" - dependencies: - sprintf-js "~1.0.2" - -arr-diff@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" - dependencies: - arr-flatten "^1.0.1" - -arr-diff@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" - -arr-flatten@^1.0.1, arr-flatten@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" - -arr-union@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" - -array-differ@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/array-differ/-/array-differ-1.0.0.tgz#eff52e3758249d33be402b8bb8e564bb2b5d4031" - -array-equal@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93" - -array-union@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" - dependencies: - array-uniq "^1.0.1" - -array-uniq@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" - -array-unique@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" - -array-unique@^0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" - -arrify@^1.0.0, arrify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" - -asap@~2.0.3: - version "2.0.6" - resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" - -asn1.js@^4.0.0: - version "4.10.1" - resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.10.1.tgz#b9c2bf5805f1e64aadeed6df3a2bfafb5a73f5a0" - dependencies: - bn.js "^4.0.0" - inherits "^2.0.1" - minimalistic-assert "^1.0.0" - -asn1@~0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" - -assert-plus@1.0.0, assert-plus@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" - -assert-plus@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234" - -assert@^1.1.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/assert/-/assert-1.4.1.tgz#99912d591836b5a6f5b345c0f07eefc08fc65d91" - dependencies: - util "0.10.3" - -assign-symbols@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" - -ast-types@0.10.1: - version "0.10.1" - resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.10.1.tgz#f52fca9715579a14f841d67d7f8d25432ab6a3dd" - -ast-types@0.11.3: - version "0.11.3" - resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.11.3.tgz#c20757fe72ee71278ea0ff3d87e5c2ca30d9edf8" - -astral-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" - -async-each@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" - -async-limiter@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8" - -async@^1.4.0, async@^1.5.0, async@^1.5.2: - version "1.5.2" - resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" - -async@^2.1.4, async@^2.6.0: - version "2.6.0" - resolved "https://registry.yarnpkg.com/async/-/async-2.6.0.tgz#61a29abb6fcc026fea77e56d1c6ec53a795951f4" - dependencies: - lodash "^4.14.0" - -asynckit@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" - -atob@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.0.tgz#ab2b150e51d7b122b9efc8d7340c06b6c41076bc" - -aws-sign2@~0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" - -aws-sign2@~0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" - -aws4@^1.2.1, aws4@^1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e" - -babel-code-frame@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" - dependencies: - chalk "^1.1.3" - esutils "^2.0.2" - js-tokens "^3.0.2" - -babel-core@^6.0.0, babel-core@^6.26.0, babel-core@^6.4.1: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.26.0.tgz#af32f78b31a6fcef119c87b0fd8d9753f03a0bb8" - dependencies: - babel-code-frame "^6.26.0" - babel-generator "^6.26.0" - babel-helpers "^6.24.1" - babel-messages "^6.23.0" - babel-register "^6.26.0" - babel-runtime "^6.26.0" - babel-template "^6.26.0" - babel-traverse "^6.26.0" - babel-types "^6.26.0" - babylon "^6.18.0" - convert-source-map "^1.5.0" - debug "^2.6.8" - json5 "^0.5.1" - lodash "^4.17.4" - minimatch "^3.0.4" - path-is-absolute "^1.0.1" - private "^0.1.7" - slash "^1.0.0" - source-map "^0.5.6" - -babel-generator@^6.18.0, babel-generator@^6.26.0: - version "6.26.1" - resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.26.1.tgz#1844408d3b8f0d35a404ea7ac180f087a601bd90" - dependencies: - babel-messages "^6.23.0" - babel-runtime "^6.26.0" - babel-types "^6.26.0" - detect-indent "^4.0.0" - jsesc "^1.3.0" - lodash "^4.17.4" - source-map "^0.5.7" - trim-right "^1.0.1" - -babel-helper-bindify-decorators@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-bindify-decorators/-/babel-helper-bindify-decorators-6.24.1.tgz#14c19e5f142d7b47f19a52431e52b1ccbc40a330" - dependencies: - babel-runtime "^6.22.0" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-helper-builder-binary-assignment-operator-visitor@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz#cce4517ada356f4220bcae8a02c2b346f9a56664" - dependencies: - babel-helper-explode-assignable-expression "^6.24.1" - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-helper-builder-react-jsx@^6.24.1: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-helper-builder-react-jsx/-/babel-helper-builder-react-jsx-6.26.0.tgz#39ff8313b75c8b65dceff1f31d383e0ff2a408a0" - dependencies: - babel-runtime "^6.26.0" - babel-types "^6.26.0" - esutils "^2.0.2" - -babel-helper-call-delegate@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz#ece6aacddc76e41c3461f88bfc575bd0daa2df8d" - dependencies: - babel-helper-hoist-variables "^6.24.1" - babel-runtime "^6.22.0" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-helper-define-map@^6.24.1: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz#a5f56dab41a25f97ecb498c7ebaca9819f95be5f" - dependencies: - babel-helper-function-name "^6.24.1" - babel-runtime "^6.26.0" - babel-types "^6.26.0" - lodash "^4.17.4" - -babel-helper-explode-assignable-expression@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz#f25b82cf7dc10433c55f70592d5746400ac22caa" - dependencies: - babel-runtime "^6.22.0" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-helper-explode-class@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-explode-class/-/babel-helper-explode-class-6.24.1.tgz#7dc2a3910dee007056e1e31d640ced3d54eaa9eb" - dependencies: - babel-helper-bindify-decorators "^6.24.1" - babel-runtime "^6.22.0" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-helper-function-name@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz#d3475b8c03ed98242a25b48351ab18399d3580a9" - dependencies: - babel-helper-get-function-arity "^6.24.1" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-helper-get-function-arity@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz#8f7782aa93407c41d3aa50908f89b031b1b6853d" - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-helper-hoist-variables@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz#1ecb27689c9d25513eadbc9914a73f5408be7a76" - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-helper-optimise-call-expression@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz#f7a13427ba9f73f8f4fa993c54a97882d1244257" - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-helper-regex@^6.24.1: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz#325c59f902f82f24b74faceed0363954f6495e72" - dependencies: - babel-runtime "^6.26.0" - babel-types "^6.26.0" - lodash "^4.17.4" - -babel-helper-remap-async-to-generator@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz#5ec581827ad723fecdd381f1c928390676e4551b" - dependencies: - babel-helper-function-name "^6.24.1" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-helper-replace-supers@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz#bf6dbfe43938d17369a213ca8a8bf74b6a90ab1a" - dependencies: - babel-helper-optimise-call-expression "^6.24.1" - babel-messages "^6.23.0" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-helpers@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.24.1.tgz#3471de9caec388e5c850e597e58a26ddf37602b2" - dependencies: - babel-runtime "^6.22.0" - babel-template "^6.24.1" - -babel-jest@^22.4.3: - version "22.4.3" - resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-22.4.3.tgz#4b7a0b6041691bbd422ab49b3b73654a49a6627a" - dependencies: - babel-plugin-istanbul "^4.1.5" - babel-preset-jest "^22.4.3" - -babel-loader@^7.1.4: - version "7.1.4" - resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-7.1.4.tgz#e3463938bd4e6d55d1c174c5485d406a188ed015" - dependencies: - find-cache-dir "^1.0.0" - loader-utils "^1.0.2" - mkdirp "^0.5.1" - -babel-messages@^6.23.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-check-es2015-constants@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz#35157b101426fd2ffd3da3f75c7d1e91835bbf8a" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-istanbul@^4.1.5: - version "4.1.5" - resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-4.1.5.tgz#6760cdd977f411d3e175bb064f2bc327d99b2b6e" - dependencies: - find-up "^2.1.0" - istanbul-lib-instrument "^1.7.5" - test-exclude "^4.1.1" - -babel-plugin-jest-hoist@^22.4.3: - version "22.4.3" - resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-22.4.3.tgz#7d8bcccadc2667f96a0dcc6afe1891875ee6c14a" - -babel-plugin-syntax-async-functions@^6.8.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95" - -babel-plugin-syntax-async-generators@^6.5.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-generators/-/babel-plugin-syntax-async-generators-6.13.0.tgz#6bc963ebb16eccbae6b92b596eb7f35c342a8b9a" - -babel-plugin-syntax-class-constructor-call@^6.18.0: - version "6.18.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-class-constructor-call/-/babel-plugin-syntax-class-constructor-call-6.18.0.tgz#9cb9d39fe43c8600bec8146456ddcbd4e1a76416" - -babel-plugin-syntax-class-properties@^6.8.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz#d7eb23b79a317f8543962c505b827c7d6cac27de" - -babel-plugin-syntax-decorators@^6.1.18, babel-plugin-syntax-decorators@^6.13.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-decorators/-/babel-plugin-syntax-decorators-6.13.0.tgz#312563b4dbde3cc806cee3e416cceeaddd11ac0b" - -babel-plugin-syntax-dynamic-import@^6.18.0: - version "6.18.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-dynamic-import/-/babel-plugin-syntax-dynamic-import-6.18.0.tgz#8d6a26229c83745a9982a441051572caa179b1da" - -babel-plugin-syntax-exponentiation-operator@^6.8.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de" - -babel-plugin-syntax-export-extensions@^6.8.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-export-extensions/-/babel-plugin-syntax-export-extensions-6.13.0.tgz#70a1484f0f9089a4e84ad44bac353c95b9b12721" - -babel-plugin-syntax-flow@^6.18.0: - version "6.18.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-flow/-/babel-plugin-syntax-flow-6.18.0.tgz#4c3ab20a2af26aa20cd25995c398c4eb70310c8d" - -babel-plugin-syntax-jsx@^6.3.13, babel-plugin-syntax-jsx@^6.8.0: - version "6.18.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz#0af32a9a6e13ca7a3fd5069e62d7b0f58d0d8946" - -babel-plugin-syntax-object-rest-spread@^6.13.0, babel-plugin-syntax-object-rest-spread@^6.8.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz#fd6536f2bce13836ffa3a5458c4903a597bb3bf5" - -babel-plugin-syntax-trailing-function-commas@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz#ba0360937f8d06e40180a43fe0d5616fff532cf3" - -babel-plugin-transform-async-generator-functions@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-generator-functions/-/babel-plugin-transform-async-generator-functions-6.24.1.tgz#f058900145fd3e9907a6ddf28da59f215258a5db" - dependencies: - babel-helper-remap-async-to-generator "^6.24.1" - babel-plugin-syntax-async-generators "^6.5.0" - babel-runtime "^6.22.0" - -babel-plugin-transform-async-to-generator@^6.22.0, babel-plugin-transform-async-to-generator@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz#6536e378aff6cb1d5517ac0e40eb3e9fc8d08761" - dependencies: - babel-helper-remap-async-to-generator "^6.24.1" - babel-plugin-syntax-async-functions "^6.8.0" - babel-runtime "^6.22.0" - -babel-plugin-transform-class-constructor-call@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-constructor-call/-/babel-plugin-transform-class-constructor-call-6.24.1.tgz#80dc285505ac067dcb8d6c65e2f6f11ab7765ef9" - dependencies: - babel-plugin-syntax-class-constructor-call "^6.18.0" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - -babel-plugin-transform-class-properties@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.24.1.tgz#6a79763ea61d33d36f37b611aa9def81a81b46ac" - dependencies: - babel-helper-function-name "^6.24.1" - babel-plugin-syntax-class-properties "^6.8.0" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - -babel-plugin-transform-decorators-legacy@^1.3.4: - version "1.3.4" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-decorators-legacy/-/babel-plugin-transform-decorators-legacy-1.3.4.tgz#741b58f6c5bce9e6027e0882d9c994f04f366925" - dependencies: - babel-plugin-syntax-decorators "^6.1.18" - babel-runtime "^6.2.0" - babel-template "^6.3.0" - -babel-plugin-transform-decorators@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-decorators/-/babel-plugin-transform-decorators-6.24.1.tgz#788013d8f8c6b5222bdf7b344390dfd77569e24d" - dependencies: - babel-helper-explode-class "^6.24.1" - babel-plugin-syntax-decorators "^6.13.0" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - babel-types "^6.24.1" - -babel-plugin-transform-es2015-arrow-functions@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz#452692cb711d5f79dc7f85e440ce41b9f244d221" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-block-scoped-functions@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz#bbc51b49f964d70cb8d8e0b94e820246ce3a6141" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-block-scoping@^6.23.0, babel-plugin-transform-es2015-block-scoping@^6.24.1: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz#d70f5299c1308d05c12f463813b0a09e73b1895f" - dependencies: - babel-runtime "^6.26.0" - babel-template "^6.26.0" - babel-traverse "^6.26.0" - babel-types "^6.26.0" - lodash "^4.17.4" - -babel-plugin-transform-es2015-classes@^6.23.0, babel-plugin-transform-es2015-classes@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz#5a4c58a50c9c9461e564b4b2a3bfabc97a2584db" - dependencies: - babel-helper-define-map "^6.24.1" - babel-helper-function-name "^6.24.1" - babel-helper-optimise-call-expression "^6.24.1" - babel-helper-replace-supers "^6.24.1" - babel-messages "^6.23.0" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-plugin-transform-es2015-computed-properties@^6.22.0, babel-plugin-transform-es2015-computed-properties@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz#6fe2a8d16895d5634f4cd999b6d3480a308159b3" - dependencies: - babel-runtime "^6.22.0" - babel-template "^6.24.1" - -babel-plugin-transform-es2015-destructuring@^6.22.0, babel-plugin-transform-es2015-destructuring@^6.23.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz#997bb1f1ab967f682d2b0876fe358d60e765c56d" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-duplicate-keys@^6.22.0, babel-plugin-transform-es2015-duplicate-keys@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz#73eb3d310ca969e3ef9ec91c53741a6f1576423e" - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-plugin-transform-es2015-for-of@^6.22.0, babel-plugin-transform-es2015-for-of@^6.23.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz#f47c95b2b613df1d3ecc2fdb7573623c75248691" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-function-name@^6.22.0, babel-plugin-transform-es2015-function-name@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz#834c89853bc36b1af0f3a4c5dbaa94fd8eacaa8b" - dependencies: - babel-helper-function-name "^6.24.1" - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-plugin-transform-es2015-literals@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz#4f54a02d6cd66cf915280019a31d31925377ca2e" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-modules-amd@^6.22.0, babel-plugin-transform-es2015-modules-amd@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz#3b3e54017239842d6d19c3011c4bd2f00a00d154" - dependencies: - babel-plugin-transform-es2015-modules-commonjs "^6.24.1" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - -babel-plugin-transform-es2015-modules-commonjs@^6.23.0, babel-plugin-transform-es2015-modules-commonjs@^6.24.1: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.0.tgz#0d8394029b7dc6abe1a97ef181e00758dd2e5d8a" - dependencies: - babel-plugin-transform-strict-mode "^6.24.1" - babel-runtime "^6.26.0" - babel-template "^6.26.0" - babel-types "^6.26.0" - -babel-plugin-transform-es2015-modules-systemjs@^6.23.0, babel-plugin-transform-es2015-modules-systemjs@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz#ff89a142b9119a906195f5f106ecf305d9407d23" - dependencies: - babel-helper-hoist-variables "^6.24.1" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - -babel-plugin-transform-es2015-modules-umd@^6.23.0, babel-plugin-transform-es2015-modules-umd@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz#ac997e6285cd18ed6176adb607d602344ad38468" - dependencies: - babel-plugin-transform-es2015-modules-amd "^6.24.1" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - -babel-plugin-transform-es2015-object-super@^6.22.0, babel-plugin-transform-es2015-object-super@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz#24cef69ae21cb83a7f8603dad021f572eb278f8d" - dependencies: - babel-helper-replace-supers "^6.24.1" - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-parameters@^6.23.0, babel-plugin-transform-es2015-parameters@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz#57ac351ab49caf14a97cd13b09f66fdf0a625f2b" - dependencies: - babel-helper-call-delegate "^6.24.1" - babel-helper-get-function-arity "^6.24.1" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-plugin-transform-es2015-shorthand-properties@^6.22.0, babel-plugin-transform-es2015-shorthand-properties@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz#24f875d6721c87661bbd99a4622e51f14de38aa0" - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-plugin-transform-es2015-spread@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz#d6d68a99f89aedc4536c81a542e8dd9f1746f8d1" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-sticky-regex@^6.22.0, babel-plugin-transform-es2015-sticky-regex@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz#00c1cdb1aca71112cdf0cf6126c2ed6b457ccdbc" - dependencies: - babel-helper-regex "^6.24.1" - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-plugin-transform-es2015-template-literals@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz#a84b3450f7e9f8f1f6839d6d687da84bb1236d8d" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-typeof-symbol@^6.22.0, babel-plugin-transform-es2015-typeof-symbol@^6.23.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz#dec09f1cddff94b52ac73d505c84df59dcceb372" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-unicode-regex@^6.22.0, babel-plugin-transform-es2015-unicode-regex@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz#d38b12f42ea7323f729387f18a7c5ae1faeb35e9" - dependencies: - babel-helper-regex "^6.24.1" - babel-runtime "^6.22.0" - regexpu-core "^2.0.0" - -babel-plugin-transform-exponentiation-operator@^6.22.0, babel-plugin-transform-exponentiation-operator@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz#2ab0c9c7f3098fa48907772bb813fe41e8de3a0e" - dependencies: - babel-helper-builder-binary-assignment-operator-visitor "^6.24.1" - babel-plugin-syntax-exponentiation-operator "^6.8.0" - babel-runtime "^6.22.0" - -babel-plugin-transform-export-extensions@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-export-extensions/-/babel-plugin-transform-export-extensions-6.22.0.tgz#53738b47e75e8218589eea946cbbd39109bbe653" - dependencies: - babel-plugin-syntax-export-extensions "^6.8.0" - babel-runtime "^6.22.0" - -babel-plugin-transform-flow-strip-types@^6.22.0, babel-plugin-transform-flow-strip-types@^6.8.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-flow-strip-types/-/babel-plugin-transform-flow-strip-types-6.22.0.tgz#84cb672935d43714fdc32bce84568d87441cf7cf" - dependencies: - babel-plugin-syntax-flow "^6.18.0" - babel-runtime "^6.22.0" - -babel-plugin-transform-object-rest-spread@^6.22.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz#0f36692d50fef6b7e2d4b3ac1478137a963b7b06" - dependencies: - babel-plugin-syntax-object-rest-spread "^6.8.0" - babel-runtime "^6.26.0" - -babel-plugin-transform-react-display-name@^6.23.0: - version "6.25.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-display-name/-/babel-plugin-transform-react-display-name-6.25.0.tgz#67e2bf1f1e9c93ab08db96792e05392bf2cc28d1" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-react-jsx-self@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-jsx-self/-/babel-plugin-transform-react-jsx-self-6.22.0.tgz#df6d80a9da2612a121e6ddd7558bcbecf06e636e" - dependencies: - babel-plugin-syntax-jsx "^6.8.0" - babel-runtime "^6.22.0" - -babel-plugin-transform-react-jsx-source@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-jsx-source/-/babel-plugin-transform-react-jsx-source-6.22.0.tgz#66ac12153f5cd2d17b3c19268f4bf0197f44ecd6" - dependencies: - babel-plugin-syntax-jsx "^6.8.0" - babel-runtime "^6.22.0" - -babel-plugin-transform-react-jsx@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-jsx/-/babel-plugin-transform-react-jsx-6.24.1.tgz#840a028e7df460dfc3a2d29f0c0d91f6376e66a3" - dependencies: - babel-helper-builder-react-jsx "^6.24.1" - babel-plugin-syntax-jsx "^6.8.0" - babel-runtime "^6.22.0" - -babel-plugin-transform-regenerator@^6.22.0, babel-plugin-transform-regenerator@^6.24.1: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz#e0703696fbde27f0a3efcacf8b4dca2f7b3a8f2f" - dependencies: - regenerator-transform "^0.10.0" - -babel-plugin-transform-strict-mode@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz#d5faf7aa578a65bbe591cf5edae04a0c67020758" - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-preset-env@^1.6.1: - version "1.6.1" - resolved "https://registry.yarnpkg.com/babel-preset-env/-/babel-preset-env-1.6.1.tgz#a18b564cc9b9afdf4aae57ae3c1b0d99188e6f48" - dependencies: - babel-plugin-check-es2015-constants "^6.22.0" - babel-plugin-syntax-trailing-function-commas "^6.22.0" - babel-plugin-transform-async-to-generator "^6.22.0" - babel-plugin-transform-es2015-arrow-functions "^6.22.0" - babel-plugin-transform-es2015-block-scoped-functions "^6.22.0" - babel-plugin-transform-es2015-block-scoping "^6.23.0" - babel-plugin-transform-es2015-classes "^6.23.0" - babel-plugin-transform-es2015-computed-properties "^6.22.0" - babel-plugin-transform-es2015-destructuring "^6.23.0" - babel-plugin-transform-es2015-duplicate-keys "^6.22.0" - babel-plugin-transform-es2015-for-of "^6.23.0" - babel-plugin-transform-es2015-function-name "^6.22.0" - babel-plugin-transform-es2015-literals "^6.22.0" - babel-plugin-transform-es2015-modules-amd "^6.22.0" - babel-plugin-transform-es2015-modules-commonjs "^6.23.0" - babel-plugin-transform-es2015-modules-systemjs "^6.23.0" - babel-plugin-transform-es2015-modules-umd "^6.23.0" - babel-plugin-transform-es2015-object-super "^6.22.0" - babel-plugin-transform-es2015-parameters "^6.23.0" - babel-plugin-transform-es2015-shorthand-properties "^6.22.0" - babel-plugin-transform-es2015-spread "^6.22.0" - babel-plugin-transform-es2015-sticky-regex "^6.22.0" - babel-plugin-transform-es2015-template-literals "^6.22.0" - babel-plugin-transform-es2015-typeof-symbol "^6.23.0" - babel-plugin-transform-es2015-unicode-regex "^6.22.0" - babel-plugin-transform-exponentiation-operator "^6.22.0" - babel-plugin-transform-regenerator "^6.22.0" - browserslist "^2.1.2" - invariant "^2.2.2" - semver "^5.3.0" - -babel-preset-es2015@^6.9.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-preset-es2015/-/babel-preset-es2015-6.24.1.tgz#d44050d6bc2c9feea702aaf38d727a0210538939" - dependencies: - babel-plugin-check-es2015-constants "^6.22.0" - babel-plugin-transform-es2015-arrow-functions "^6.22.0" - babel-plugin-transform-es2015-block-scoped-functions "^6.22.0" - babel-plugin-transform-es2015-block-scoping "^6.24.1" - babel-plugin-transform-es2015-classes "^6.24.1" - babel-plugin-transform-es2015-computed-properties "^6.24.1" - babel-plugin-transform-es2015-destructuring "^6.22.0" - babel-plugin-transform-es2015-duplicate-keys "^6.24.1" - babel-plugin-transform-es2015-for-of "^6.22.0" - babel-plugin-transform-es2015-function-name "^6.24.1" - babel-plugin-transform-es2015-literals "^6.22.0" - babel-plugin-transform-es2015-modules-amd "^6.24.1" - babel-plugin-transform-es2015-modules-commonjs "^6.24.1" - babel-plugin-transform-es2015-modules-systemjs "^6.24.1" - babel-plugin-transform-es2015-modules-umd "^6.24.1" - babel-plugin-transform-es2015-object-super "^6.24.1" - babel-plugin-transform-es2015-parameters "^6.24.1" - babel-plugin-transform-es2015-shorthand-properties "^6.24.1" - babel-plugin-transform-es2015-spread "^6.22.0" - babel-plugin-transform-es2015-sticky-regex "^6.24.1" - babel-plugin-transform-es2015-template-literals "^6.22.0" - babel-plugin-transform-es2015-typeof-symbol "^6.22.0" - babel-plugin-transform-es2015-unicode-regex "^6.24.1" - babel-plugin-transform-regenerator "^6.24.1" - -babel-preset-flow@^6.23.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-preset-flow/-/babel-preset-flow-6.23.0.tgz#e71218887085ae9a24b5be4169affb599816c49d" - dependencies: - babel-plugin-transform-flow-strip-types "^6.22.0" - -babel-preset-jest@^22.4.3: - version "22.4.3" - resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-22.4.3.tgz#e92eef9813b7026ab4ca675799f37419b5a44156" - dependencies: - babel-plugin-jest-hoist "^22.4.3" - babel-plugin-syntax-object-rest-spread "^6.13.0" - -babel-preset-react@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-preset-react/-/babel-preset-react-6.24.1.tgz#ba69dfaea45fc3ec639b6a4ecea6e17702c91380" - dependencies: - babel-plugin-syntax-jsx "^6.3.13" - babel-plugin-transform-react-display-name "^6.23.0" - babel-plugin-transform-react-jsx "^6.24.1" - babel-plugin-transform-react-jsx-self "^6.22.0" - babel-plugin-transform-react-jsx-source "^6.22.0" - babel-preset-flow "^6.23.0" - -babel-preset-stage-1@^6.5.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-preset-stage-1/-/babel-preset-stage-1-6.24.1.tgz#7692cd7dcd6849907e6ae4a0a85589cfb9e2bfb0" - dependencies: - babel-plugin-transform-class-constructor-call "^6.24.1" - babel-plugin-transform-export-extensions "^6.22.0" - babel-preset-stage-2 "^6.24.1" - -babel-preset-stage-2@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-preset-stage-2/-/babel-preset-stage-2-6.24.1.tgz#d9e2960fb3d71187f0e64eec62bc07767219bdc1" - dependencies: - babel-plugin-syntax-dynamic-import "^6.18.0" - babel-plugin-transform-class-properties "^6.24.1" - babel-plugin-transform-decorators "^6.24.1" - babel-preset-stage-3 "^6.24.1" - -babel-preset-stage-3@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-preset-stage-3/-/babel-preset-stage-3-6.24.1.tgz#836ada0a9e7a7fa37cb138fb9326f87934a48395" - dependencies: - babel-plugin-syntax-trailing-function-commas "^6.22.0" - babel-plugin-transform-async-generator-functions "^6.24.1" - babel-plugin-transform-async-to-generator "^6.24.1" - babel-plugin-transform-exponentiation-operator "^6.24.1" - babel-plugin-transform-object-rest-spread "^6.22.0" - -babel-register@^6.26.0, babel-register@^6.9.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.26.0.tgz#6ed021173e2fcb486d7acb45c6009a856f647071" - dependencies: - babel-core "^6.26.0" - babel-runtime "^6.26.0" - core-js "^2.5.0" - home-or-tmp "^2.0.0" - lodash "^4.17.4" - mkdirp "^0.5.1" - source-map-support "^0.4.15" - -babel-runtime@^6.18.0, babel-runtime@^6.2.0, babel-runtime@^6.22.0, babel-runtime@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" - dependencies: - core-js "^2.4.0" - regenerator-runtime "^0.11.0" - -babel-template@^6.16.0, babel-template@^6.24.1, babel-template@^6.26.0, babel-template@^6.3.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.26.0.tgz#de03e2d16396b069f46dd9fff8521fb1a0e35e02" - dependencies: - babel-runtime "^6.26.0" - babel-traverse "^6.26.0" - babel-types "^6.26.0" - babylon "^6.18.0" - lodash "^4.17.4" - -babel-traverse@^6.18.0, babel-traverse@^6.24.1, babel-traverse@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee" - dependencies: - babel-code-frame "^6.26.0" - babel-messages "^6.23.0" - babel-runtime "^6.26.0" - babel-types "^6.26.0" - babylon "^6.18.0" - debug "^2.6.8" - globals "^9.18.0" - invariant "^2.2.2" - lodash "^4.17.4" - -babel-types@^6.18.0, babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497" - dependencies: - babel-runtime "^6.26.0" - esutils "^2.0.2" - lodash "^4.17.4" - to-fast-properties "^1.0.3" - -babylon@^6.17.3, babylon@^6.18.0: - version "6.18.0" - resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" - -babylon@^7.0.0-beta.30: - version "7.0.0-beta.42" - resolved "https://registry.yarnpkg.com/babylon/-/babylon-7.0.0-beta.42.tgz#67cfabcd4f3ec82999d29031ccdea89d0ba99657" - -balanced-match@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" - -base64-js@^1.0.2: - version "1.2.3" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.3.tgz#fb13668233d9614cf5fb4bce95a9ba4096cdf801" - -base@^0.11.1: - version "0.11.2" - resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" - dependencies: - cache-base "^1.0.1" - class-utils "^0.3.5" - component-emitter "^1.2.1" - define-property "^1.0.0" - isobject "^3.0.1" - mixin-deep "^1.2.0" - pascalcase "^0.1.1" - -bcrypt-pbkdf@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d" - dependencies: - tweetnacl "^0.14.3" - -big.js@^3.1.3: - version "3.2.0" - resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.2.0.tgz#a5fc298b81b9e0dca2e458824784b65c52ba588e" - -binary-extensions@^1.0.0: - version "1.11.0" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.11.0.tgz#46aa1751fb6a2f93ee5e689bb1087d4b14c6c205" - -binaryextensions@2: - version "2.1.1" - resolved "https://registry.yarnpkg.com/binaryextensions/-/binaryextensions-2.1.1.tgz#3209a51ca4a4ad541a3b8d3d6a6d5b83a2485935" - -block-stream@*: - version "0.0.9" - resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" - dependencies: - inherits "~2.0.0" - -bluebird@^3.5.1: - version "3.5.1" - resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.1.tgz#d9551f9de98f1fcda1e683d17ee91a0602ee2eb9" - -bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0: - version "4.11.8" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" - -boolbase@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" - -boom@2.x.x: - version "2.10.1" - resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f" - dependencies: - hoek "2.x.x" - -boom@4.x.x: - version "4.3.1" - resolved "https://registry.yarnpkg.com/boom/-/boom-4.3.1.tgz#4f8a3005cb4a7e3889f749030fd25b96e01d2e31" - dependencies: - hoek "4.x.x" - -boom@5.x.x: - version "5.2.0" - resolved "https://registry.yarnpkg.com/boom/-/boom-5.2.0.tgz#5dd9da6ee3a5f302077436290cb717d3f4a54e02" - dependencies: - hoek "4.x.x" - -brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" - -braces@^1.8.2: - version "1.8.5" - resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" - dependencies: - expand-range "^1.8.1" - preserve "^0.2.0" - repeat-element "^1.1.2" - -braces@^2.3.0, braces@^2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.1.tgz#7086c913b4e5a08dbe37ac0ee6a2500c4ba691bb" - dependencies: - arr-flatten "^1.1.0" - array-unique "^0.3.2" - define-property "^1.0.0" - extend-shallow "^2.0.1" - fill-range "^4.0.0" - isobject "^3.0.1" - kind-of "^6.0.2" - repeat-element "^1.1.2" - snapdragon "^0.8.1" - snapdragon-node "^2.0.1" - split-string "^3.0.2" - to-regex "^3.0.1" - -brorand@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" - -browser-process-hrtime@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-0.1.2.tgz#425d68a58d3447f02a04aa894187fce8af8b7b8e" - -browser-resolve@^1.11.2: - version "1.11.2" - resolved "https://registry.yarnpkg.com/browser-resolve/-/browser-resolve-1.11.2.tgz#8ff09b0a2c421718a1051c260b32e48f442938ce" - dependencies: - resolve "1.1.7" - -browserify-aes@^1.0.0, browserify-aes@^1.0.4: - version "1.1.1" - resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.1.1.tgz#38b7ab55edb806ff2dcda1a7f1620773a477c49f" - dependencies: - buffer-xor "^1.0.3" - cipher-base "^1.0.0" - create-hash "^1.1.0" - evp_bytestokey "^1.0.3" - inherits "^2.0.1" - safe-buffer "^5.0.1" - -browserify-cipher@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.0.tgz#9988244874bf5ed4e28da95666dcd66ac8fc363a" - dependencies: - browserify-aes "^1.0.4" - browserify-des "^1.0.0" - evp_bytestokey "^1.0.0" - -browserify-des@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.0.tgz#daa277717470922ed2fe18594118a175439721dd" - dependencies: - cipher-base "^1.0.1" - des.js "^1.0.0" - inherits "^2.0.1" - -browserify-rsa@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.0.1.tgz#21e0abfaf6f2029cf2fafb133567a701d4135524" - dependencies: - bn.js "^4.1.0" - randombytes "^2.0.1" - -browserify-sign@^4.0.0: - version "4.0.4" - resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.0.4.tgz#aa4eb68e5d7b658baa6bf6a57e630cbd7a93d298" - dependencies: - bn.js "^4.1.1" - browserify-rsa "^4.0.0" - create-hash "^1.1.0" - create-hmac "^1.1.2" - elliptic "^6.0.0" - inherits "^2.0.1" - parse-asn1 "^5.0.0" - -browserify-zlib@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.2.0.tgz#2869459d9aa3be245fe8fe2ca1f46e2e7f54d73f" - dependencies: - pako "~1.0.5" - -browserslist@^2.1.2: - version "2.11.3" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-2.11.3.tgz#fe36167aed1bbcde4827ebfe71347a2cc70b99b2" - dependencies: - caniuse-lite "^1.0.30000792" - electron-to-chromium "^1.3.30" - -bser@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/bser/-/bser-2.0.0.tgz#9ac78d3ed5d915804fd87acb158bc797147a1719" - dependencies: - node-int64 "^0.4.0" - -buffer-from@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.0.0.tgz#4cb8832d23612589b0406e9e2956c17f06fdf531" - -buffer-xor@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" - -buffer@^4.3.0: - version "4.9.1" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298" - dependencies: - base64-js "^1.0.2" - ieee754 "^1.1.4" - isarray "^1.0.0" - -builtin-modules@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" - -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" - -cacache@^10.0.4: - version "10.0.4" - resolved "https://registry.yarnpkg.com/cacache/-/cacache-10.0.4.tgz#6452367999eff9d4188aefd9a14e9d7c6a263460" - dependencies: - bluebird "^3.5.1" - chownr "^1.0.1" - glob "^7.1.2" - graceful-fs "^4.1.11" - lru-cache "^4.1.1" - mississippi "^2.0.0" - mkdirp "^0.5.1" - move-concurrently "^1.0.1" - promise-inflight "^1.0.1" - rimraf "^2.6.2" - ssri "^5.2.4" - unique-filename "^1.1.0" - y18n "^4.0.0" - -cache-base@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" - dependencies: - collection-visit "^1.0.0" - component-emitter "^1.2.1" - get-value "^2.0.6" - has-value "^1.0.0" - isobject "^3.0.1" - set-value "^2.0.0" - to-object-path "^0.3.0" - union-value "^1.0.0" - unset-value "^1.0.0" - -cacheable-request@^2.1.1: - version "2.1.4" - resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-2.1.4.tgz#0d808801b6342ad33c91df9d0b44dc09b91e5c3d" - dependencies: - clone-response "1.0.2" - get-stream "3.0.0" - http-cache-semantics "3.8.1" - keyv "3.0.0" - lowercase-keys "1.0.0" - normalize-url "2.0.1" - responselike "1.0.2" - -callsites@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50" - -camel-case@3.0.x: - version "3.0.0" - resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-3.0.0.tgz#ca3c3688a4e9cf3a4cda777dc4dcbc713249cf73" - dependencies: - no-case "^2.2.0" - upper-case "^1.1.1" - -camelcase@^1.0.2: - version "1.2.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39" - -camelcase@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" - -caniuse-lite@^1.0.30000792: - version "1.0.30000821" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000821.tgz#0f3223f1e048ed96451c56ca6cf197058c42cb93" - -caseless@~0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" - -center-align@^0.1.1: - version "0.1.3" - resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad" - dependencies: - align-text "^0.1.3" - lazy-cache "^1.0.3" - -chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" - dependencies: - ansi-styles "^2.2.1" - escape-string-regexp "^1.0.2" - has-ansi "^2.0.0" - strip-ansi "^3.0.0" - supports-color "^2.0.0" - -chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.3.2.tgz#250dc96b07491bfd601e648d66ddf5f60c7a5c65" - dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" - -chalk@~0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-0.4.0.tgz#5199a3ddcd0c1efe23bc08c1b027b06176e0c64f" - dependencies: - ansi-styles "~1.0.0" - has-color "~0.1.0" - strip-ansi "~0.1.0" - -chardet@^0.4.0: - version "0.4.2" - resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.4.2.tgz#b5473b33dc97c424e5d98dc87d55d4d8a29c8bf2" - -chokidar@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.0.3.tgz#dcbd4f6cbb2a55b4799ba8a840ac527e5f4b1176" - dependencies: - anymatch "^2.0.0" - async-each "^1.0.0" - braces "^2.3.0" - glob-parent "^3.1.0" - inherits "^2.0.1" - is-binary-path "^1.0.0" - is-glob "^4.0.0" - normalize-path "^2.1.1" - path-is-absolute "^1.0.0" - readdirp "^2.0.0" - upath "^1.0.0" - optionalDependencies: - fsevents "^1.1.2" - -chownr@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.0.1.tgz#e2a75042a9551908bebd25b8523d5f9769d79181" - -chrome-trace-event@^0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-0.1.2.tgz#90f36885d5345a50621332f0717b595883d5d982" - -ci-info@^1.0.0: - version "1.1.3" - resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.1.3.tgz#710193264bb05c77b8c90d02f5aaf22216a667b2" - -cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" - dependencies: - inherits "^2.0.1" - safe-buffer "^5.0.1" - -class-utils@^0.3.5: - version "0.3.6" - resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" - dependencies: - arr-union "^3.1.0" - define-property "^0.2.5" - isobject "^3.0.0" - static-extend "^0.1.1" - -clean-css@4.1.x: - version "4.1.11" - resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.1.11.tgz#2ecdf145aba38f54740f26cefd0ff3e03e125d6a" - dependencies: - source-map "0.5.x" - -cli-cursor@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987" - dependencies: - restore-cursor "^1.0.1" - -cli-cursor@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" - dependencies: - restore-cursor "^2.0.0" - -cli-spinners@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-0.1.2.tgz#bb764d88e185fb9e1e6a2a1f19772318f605e31c" - -cli-table@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/cli-table/-/cli-table-0.3.1.tgz#f53b05266a8b1a0b934b3d0821e6e2dc5914ae23" - dependencies: - colors "1.0.3" - -cli-truncate@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-0.2.1.tgz#9f15cfbb0705005369216c626ac7d05ab90dd574" - dependencies: - slice-ansi "0.0.4" - string-width "^1.0.1" - -cli-width@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" - -cliui@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1" - dependencies: - center-align "^0.1.1" - right-align "^0.1.1" - wordwrap "0.0.2" - -cliui@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-4.0.0.tgz#743d4650e05f36d1ed2575b59638d87322bfbbcc" - dependencies: - string-width "^2.1.1" - strip-ansi "^4.0.0" - wrap-ansi "^2.0.0" - -clone-buffer@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/clone-buffer/-/clone-buffer-1.0.0.tgz#e3e25b207ac4e701af721e2cb5a16792cac3dc58" - -clone-response@1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b" - dependencies: - mimic-response "^1.0.0" - -clone-stats@^0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/clone-stats/-/clone-stats-0.0.1.tgz#b88f94a82cf38b8791d58046ea4029ad88ca99d1" - -clone-stats@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/clone-stats/-/clone-stats-1.0.0.tgz#b3782dff8bb5474e18b9b6bf0fdfe782f8777680" - -clone@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" - -clone@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f" - -cloneable-readable@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/cloneable-readable/-/cloneable-readable-1.1.2.tgz#d591dee4a8f8bc15da43ce97dceeba13d43e2a65" - dependencies: - inherits "^2.0.1" - process-nextick-args "^2.0.0" - readable-stream "^2.3.5" - -co@^4.6.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" - -code-point-at@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" - -collection-visit@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" - dependencies: - map-visit "^1.0.0" - object-visit "^1.0.0" - -color-convert@^1.9.0: - version "1.9.1" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.1.tgz#c1261107aeb2f294ebffec9ed9ecad529a6097ed" - dependencies: - color-name "^1.1.1" - -color-name@^1.1.1: - version "1.1.3" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" - -colors@1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" - -colors@^1.1.2: - version "1.2.1" - resolved "https://registry.yarnpkg.com/colors/-/colors-1.2.1.tgz#f4a3d302976aaf042356ba1ade3b1a2c62d9d794" - -combined-stream@1.0.6, combined-stream@^1.0.5, combined-stream@~1.0.5: - version "1.0.6" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.6.tgz#723e7df6e801ac5613113a7e445a9b69cb632818" - dependencies: - delayed-stream "~1.0.0" - -commander@2.15.x, commander@~2.15.0: - version "2.15.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f" - -commander@~2.13.0: - version "2.13.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.13.0.tgz#6964bca67685df7c1f1430c584f07d7597885b9c" - -commondir@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" - -compare-versions@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-3.1.0.tgz#43310256a5c555aaed4193c04d8f154cf9c6efd5" - -component-emitter@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" - -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - -concat-stream@^1.5.0: - version "1.6.2" - resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" - dependencies: - buffer-from "^1.0.0" - inherits "^2.0.3" - readable-stream "^2.2.2" - typedarray "^0.0.6" - -console-browserify@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10" - dependencies: - date-now "^0.1.4" - -console-control-strings@^1.0.0, console-control-strings@~1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" - -constants-browserify@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" - -content-type-parser@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/content-type-parser/-/content-type-parser-1.0.2.tgz#caabe80623e63638b2502fd4c7f12ff4ce2352e7" - -convert-source-map@^1.4.0, convert-source-map@^1.5.0: - version "1.5.1" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.1.tgz#b8278097b9bc229365de5c62cf5fcaed8b5599e5" - -copy-concurrently@^1.0.0: - version "1.0.5" - resolved "https://registry.yarnpkg.com/copy-concurrently/-/copy-concurrently-1.0.5.tgz#92297398cae34937fcafd6ec8139c18051f0b5e0" - dependencies: - aproba "^1.1.1" - fs-write-stream-atomic "^1.0.8" - iferr "^0.1.5" - mkdirp "^0.5.1" - rimraf "^2.5.4" - run-queue "^1.0.0" - -copy-descriptor@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" - -core-decorators@^0.20.0: - version "0.20.0" - resolved "https://registry.yarnpkg.com/core-decorators/-/core-decorators-0.20.0.tgz#605896624053af8c28efbe735c25a301a61c65c5" - -core-js@^1.0.0: - version "1.2.7" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" - -core-js@^2.4.0, core-js@^2.4.1, core-js@^2.5.0: - version "2.5.4" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.4.tgz#f2c8bf181f2a80b92f360121429ce63a2f0aeae0" - -core-util-is@1.0.2, core-util-is@~1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" - -corser@~2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/corser/-/corser-2.0.1.tgz#8eda252ecaab5840dcd975ceb90d9370c819ff87" - -create-ecdh@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.0.tgz#888c723596cdf7612f6498233eebd7a35301737d" - dependencies: - bn.js "^4.1.0" - elliptic "^6.0.0" - -create-hash@^1.1.0, create-hash@^1.1.2: - version "1.1.3" - resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.1.3.tgz#606042ac8b9262750f483caddab0f5819172d8fd" - dependencies: - cipher-base "^1.0.1" - inherits "^2.0.1" - ripemd160 "^2.0.0" - sha.js "^2.4.0" - -create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4: - version "1.1.6" - resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.6.tgz#acb9e221a4e17bdb076e90657c42b93e3726cf06" - dependencies: - cipher-base "^1.0.3" - create-hash "^1.1.0" - inherits "^2.0.1" - ripemd160 "^2.0.0" - safe-buffer "^5.0.1" - sha.js "^2.4.8" - -cross-spawn@^5.0.1, cross-spawn@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" - dependencies: - lru-cache "^4.0.1" - shebang-command "^1.2.0" - which "^1.2.9" - -cross-spawn@^6.0.5: - version "6.0.5" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" - dependencies: - nice-try "^1.0.4" - path-key "^2.0.1" - semver "^5.5.0" - shebang-command "^1.2.0" - which "^1.2.9" - -cryptiles@2.x.x: - version "2.0.5" - resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8" - dependencies: - boom "2.x.x" - -cryptiles@3.x.x: - version "3.1.2" - resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-3.1.2.tgz#a89fbb220f5ce25ec56e8c4aa8a4fd7b5b0d29fe" - dependencies: - boom "5.x.x" - -crypto-browserify@^3.11.0: - version "3.12.0" - resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" - dependencies: - browserify-cipher "^1.0.0" - browserify-sign "^4.0.0" - create-ecdh "^4.0.0" - create-hash "^1.1.0" - create-hmac "^1.1.0" - diffie-hellman "^5.0.0" - inherits "^2.0.1" - pbkdf2 "^3.0.3" - public-encrypt "^4.0.0" - randombytes "^2.0.0" - randomfill "^1.0.3" - -css-select@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/css-select/-/css-select-1.2.0.tgz#2b3a110539c5355f1cd8d314623e870b121ec858" - dependencies: - boolbase "~1.0.0" - css-what "2.1" - domutils "1.5.1" - nth-check "~1.0.1" - -css-what@2.1: - version "2.1.0" - resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.0.tgz#9467d032c38cfaefb9f2d79501253062f87fa1bd" - -cssom@0.3.x, "cssom@>= 0.3.2 < 0.4.0": - version "0.3.2" - resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.2.tgz#b8036170c79f07a90ff2f16e22284027a243848b" - -"cssstyle@>= 0.2.37 < 0.3.0": - version "0.2.37" - resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-0.2.37.tgz#541097234cb2513c83ceed3acddc27ff27987d54" - dependencies: - cssom "0.3.x" - -cyclist@~0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-0.2.2.tgz#1b33792e11e914a2fd6d6ed6447464444e5fa640" - -dargs@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/dargs/-/dargs-5.1.0.tgz#ec7ea50c78564cd36c9d5ec18f66329fade27829" - -dashdash@^1.12.0: - version "1.14.1" - resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" - dependencies: - assert-plus "^1.0.0" - -date-fns@^1.27.2: - version "1.29.0" - resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.29.0.tgz#12e609cdcb935127311d04d33334e2960a2a54e6" - -date-now@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b" - -dateformat@^3.0.2: - version "3.0.3" - resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae" - -debug@^2.2.0, debug@^2.3.3, debug@^2.6.8: - version "2.6.9" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" - dependencies: - ms "2.0.0" - -debug@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" - dependencies: - ms "2.0.0" - -decamelize@^1.0.0, decamelize@^1.1.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" - -decode-uri-component@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" - -decompress-response@^3.2.0, decompress-response@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" - dependencies: - mimic-response "^1.0.0" - -deep-extend@^0.4.0, deep-extend@~0.4.0: - version "0.4.2" - resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.2.tgz#48b699c27e334bf89f10892be432f6e4c7d34a7f" - -deep-is@~0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" - -default-require-extensions@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/default-require-extensions/-/default-require-extensions-1.0.0.tgz#f37ea15d3e13ffd9b437d33e1a75b5fb97874cb8" - dependencies: - strip-bom "^2.0.0" - -define-properties@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.2.tgz#83a73f2fea569898fb737193c8f873caf6d45c94" - dependencies: - foreach "^2.0.5" - object-keys "^1.0.8" - -define-property@^0.2.5: - version "0.2.5" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" - dependencies: - is-descriptor "^0.1.0" - -define-property@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" - dependencies: - is-descriptor "^1.0.0" - -define-property@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" - dependencies: - is-descriptor "^1.0.2" - isobject "^3.0.1" - -delayed-stream@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" - -delegates@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" - -des.js@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.0.tgz#c074d2e2aa6a8a9a07dbd61f9a15c2cd83ec8ecc" - dependencies: - inherits "^2.0.1" - minimalistic-assert "^1.0.0" - -detect-conflict@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/detect-conflict/-/detect-conflict-1.0.1.tgz#088657a66a961c05019db7c4230883b1c6b4176e" - -detect-indent@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" - dependencies: - repeating "^2.0.0" - -detect-libc@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" - -detect-newline@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-2.1.0.tgz#f41f1c10be4b00e87b5f13da680759f2c5bfd3e2" - -diff@^3.2.0, diff@^3.3.1, diff@^3.5.0: - version "3.5.0" - resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" - -diffie-hellman@^5.0.0: - version "5.0.2" - resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.2.tgz#b5835739270cfe26acf632099fded2a07f209e5e" - dependencies: - bn.js "^4.1.0" - miller-rabin "^4.0.0" - randombytes "^2.0.0" - -dom-converter@~0.1: - version "0.1.4" - resolved "https://registry.yarnpkg.com/dom-converter/-/dom-converter-0.1.4.tgz#a45ef5727b890c9bffe6d7c876e7b19cb0e17f3b" - dependencies: - utila "~0.3" - -dom-serializer@0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.0.tgz#073c697546ce0780ce23be4a28e293e40bc30c82" - dependencies: - domelementtype "~1.1.1" - entities "~1.1.1" - -domain-browser@^1.1.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda" - -domelementtype@1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.0.tgz#b17aed82e8ab59e52dd9c19b1756e0fc187204c2" - -domelementtype@~1.1.1: - version "1.1.3" - resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.1.3.tgz#bd28773e2642881aec51544924299c5cd822185b" - -domexception@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/domexception/-/domexception-1.0.1.tgz#937442644ca6a31261ef36e3ec677fe805582c90" - dependencies: - webidl-conversions "^4.0.2" - -domhandler@2.1: - version "2.1.0" - resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.1.0.tgz#d2646f5e57f6c3bab11cf6cb05d3c0acf7412594" - dependencies: - domelementtype "1" - -domutils@1.1: - version "1.1.6" - resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.1.6.tgz#bddc3de099b9a2efacc51c623f28f416ecc57485" - dependencies: - domelementtype "1" - -domutils@1.5.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.5.1.tgz#dcd8488a26f563d61079e48c9f7b7e32373682cf" - dependencies: - dom-serializer "0" - domelementtype "1" - -duplexer3@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" - -duplexify@^3.4.2, duplexify@^3.5.3: - version "3.5.4" - resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.5.4.tgz#4bb46c1796eabebeec4ca9a2e66b808cb7a3d8b4" - dependencies: - end-of-stream "^1.0.0" - inherits "^2.0.1" - readable-stream "^2.0.0" - stream-shift "^1.0.0" - -ecc-jsbn@~0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505" - dependencies: - jsbn "~0.1.0" - -ecstatic@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/ecstatic/-/ecstatic-3.2.0.tgz#1b1aee1ca7c6b99cfb5cf6c9b26b481b90c4409f" - dependencies: - he "^1.1.1" - mime "^1.4.1" - minimist "^1.1.0" - url-join "^2.0.2" - -editions@^1.3.3: - version "1.3.4" - resolved "https://registry.yarnpkg.com/editions/-/editions-1.3.4.tgz#3662cb592347c3168eb8e498a0ff73271d67f50b" - -ejs@^2.3.1: - version "2.5.8" - resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.5.8.tgz#2ab6954619f225e6193b7ac5f7c39c48fefe4380" - -electron-to-chromium@^1.3.30: - version "1.3.41" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.41.tgz#7e33643e00cd85edfd17e04194f6d00e73737235" - -elegant-spinner@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/elegant-spinner/-/elegant-spinner-1.0.1.tgz#db043521c95d7e303fd8f345bedc3349cfb0729e" - -elliptic@^6.0.0: - version "6.4.0" - resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.4.0.tgz#cac9af8762c85836187003c8dfe193e5e2eae5df" - dependencies: - bn.js "^4.4.0" - brorand "^1.0.1" - hash.js "^1.0.0" - hmac-drbg "^1.0.0" - inherits "^2.0.1" - minimalistic-assert "^1.0.0" - minimalistic-crypto-utils "^1.0.0" - -emojis-list@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" - -encoding@^0.1.11: - version "0.1.12" - resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" - dependencies: - iconv-lite "~0.4.13" - -end-of-stream@^1.0.0, end-of-stream@^1.1.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43" - dependencies: - once "^1.4.0" - -enhanced-resolve@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.0.0.tgz#e34a6eaa790f62fccd71d93959f56b2b432db10a" - dependencies: - graceful-fs "^4.1.2" - memory-fs "^0.4.0" - tapable "^1.0.0" - -entities@~1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0" - -errno@^0.1.3, errno@~0.1.7: - version "0.1.7" - resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618" - dependencies: - prr "~1.0.1" - -error-ex@^1.2.0, error-ex@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.1.tgz#f855a86ce61adc4e8621c3cda21e7a7612c3a8dc" - dependencies: - is-arrayish "^0.2.1" - -error@^7.0.2: - version "7.0.2" - resolved "https://registry.yarnpkg.com/error/-/error-7.0.2.tgz#a5f75fff4d9926126ddac0ea5dc38e689153cb02" - dependencies: - string-template "~0.2.1" - xtend "~4.0.0" - -es-abstract@^1.5.1: - version "1.11.0" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.11.0.tgz#cce87d518f0496893b1a30cd8461835535480681" - dependencies: - es-to-primitive "^1.1.1" - function-bind "^1.1.1" - has "^1.0.1" - is-callable "^1.1.3" - is-regex "^1.0.4" - -es-to-primitive@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.1.1.tgz#45355248a88979034b6792e19bb81f2b7975dd0d" - dependencies: - is-callable "^1.1.1" - is-date-object "^1.0.1" - is-symbol "^1.0.1" - -escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - -escodegen@^1.9.0: - version "1.9.1" - resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.9.1.tgz#dbae17ef96c8e4bedb1356f4504fa4cc2f7cb7e2" - dependencies: - esprima "^3.1.3" - estraverse "^4.2.0" - esutils "^2.0.2" - optionator "^0.8.1" - optionalDependencies: - source-map "~0.6.1" - -eslint-scope@^3.7.1: - version "3.7.1" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-3.7.1.tgz#3d63c3edfda02e06e01a452ad88caacc7cdcb6e8" - dependencies: - esrecurse "^4.1.0" - estraverse "^4.1.1" - -esprima@^3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633" - -esprima@^4.0.0, esprima@~4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804" - -esrecurse@^4.1.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf" - dependencies: - estraverse "^4.1.0" - -estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" - -esutils@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" - -eventemitter3@1.x.x: - version "1.2.0" - resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-1.2.0.tgz#1c86991d816ad1e504750e73874224ecf3bec508" - -events@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" - -evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" - dependencies: - md5.js "^1.3.4" - safe-buffer "^5.1.1" - -exec-sh@^0.2.0: - version "0.2.1" - resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.2.1.tgz#163b98a6e89e6b65b47c2a28d215bc1f63989c38" - dependencies: - merge "^1.1.3" - -execa@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777" - dependencies: - cross-spawn "^5.0.1" - get-stream "^3.0.0" - is-stream "^1.1.0" - npm-run-path "^2.0.0" - p-finally "^1.0.0" - signal-exit "^3.0.0" - strip-eof "^1.0.0" - -exit-hook@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8" - -exit@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" - -expand-brackets@^0.1.4: - version "0.1.5" - resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" - dependencies: - is-posix-bracket "^0.1.0" - -expand-brackets@^2.1.4: - version "2.1.4" - resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" - dependencies: - debug "^2.3.3" - define-property "^0.2.5" - extend-shallow "^2.0.1" - posix-character-classes "^0.1.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - -expand-range@^1.8.1: - version "1.8.2" - resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" - dependencies: - fill-range "^2.1.0" - -expand-tilde@^2.0.0, expand-tilde@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-2.0.2.tgz#97e801aa052df02454de46b02bf621642cdc8502" - dependencies: - homedir-polyfill "^1.0.1" - -expect@^22.4.3: - version "22.4.3" - resolved "https://registry.yarnpkg.com/expect/-/expect-22.4.3.tgz#d5a29d0a0e1fb2153557caef2674d4547e914674" - dependencies: - ansi-styles "^3.2.0" - jest-diff "^22.4.3" - jest-get-type "^22.4.3" - jest-matcher-utils "^22.4.3" - jest-message-util "^22.4.3" - jest-regex-util "^22.4.3" - -extend-shallow@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" - dependencies: - is-extendable "^0.1.0" - -extend-shallow@^3.0.0, extend-shallow@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" - dependencies: - assign-symbols "^1.0.0" - is-extendable "^1.0.1" - -extend@~3.0.0, extend@~3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" - -external-editor@^2.0.4, external-editor@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.1.0.tgz#3d026a21b7f95b5726387d4200ac160d372c3b48" - dependencies: - chardet "^0.4.0" - iconv-lite "^0.4.17" - tmp "^0.0.33" - -extglob@^0.3.1: - version "0.3.2" - resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" - dependencies: - is-extglob "^1.0.0" - -extglob@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" - dependencies: - array-unique "^0.3.2" - define-property "^1.0.0" - expand-brackets "^2.1.4" - extend-shallow "^2.0.1" - fragment-cache "^0.2.1" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - -extsprintf@1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" - -extsprintf@^1.2.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" - -fast-deep-equal@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614" - -fast-json-stable-stringify@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" - -fast-levenshtein@~2.0.4: - version "2.0.6" - resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" - -fb-watchman@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.0.tgz#54e9abf7dfa2f26cd9b1636c588c1afc05de5d58" - dependencies: - bser "^2.0.0" - -fbjs@^0.8.16: - version "0.8.16" - resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.16.tgz#5e67432f550dc41b572bf55847b8aca64e5337db" - dependencies: - core-js "^1.0.0" - isomorphic-fetch "^2.1.1" - loose-envify "^1.0.0" - object-assign "^4.1.0" - promise "^7.1.1" - setimmediate "^1.0.5" - ua-parser-js "^0.7.9" - -figures@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" - dependencies: - escape-string-regexp "^1.0.5" - object-assign "^4.1.0" - -figures@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" - dependencies: - escape-string-regexp "^1.0.5" - -filename-regex@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" - -fileset@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/fileset/-/fileset-2.0.3.tgz#8e7548a96d3cc2327ee5e674168723a333bba2a0" - dependencies: - glob "^7.0.3" - minimatch "^3.0.3" - -fill-range@^2.1.0: - version "2.2.3" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723" - dependencies: - is-number "^2.1.0" - isobject "^2.0.0" - randomatic "^1.1.3" - repeat-element "^1.1.2" - repeat-string "^1.5.2" - -fill-range@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" - dependencies: - extend-shallow "^2.0.1" - is-number "^3.0.0" - repeat-string "^1.6.1" - to-regex-range "^2.1.0" - -find-cache-dir@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-1.0.0.tgz#9288e3e9e3cc3748717d39eade17cf71fc30ee6f" - dependencies: - commondir "^1.0.1" - make-dir "^1.0.0" - pkg-dir "^2.0.0" - -find-up@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" - dependencies: - path-exists "^2.0.0" - pinkie-promise "^2.0.0" - -find-up@^2.0.0, find-up@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" - dependencies: - locate-path "^2.0.0" - -first-chunk-stream@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/first-chunk-stream/-/first-chunk-stream-2.0.0.tgz#1bdecdb8e083c0664b91945581577a43a9f31d70" - dependencies: - readable-stream "^2.0.2" - -flow-parser@^0.*: - version "0.69.0" - resolved "https://registry.yarnpkg.com/flow-parser/-/flow-parser-0.69.0.tgz#378b5128d6d0b554a8b2f16a4ca3e1ab9649f00e" - -flush-write-stream@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.0.3.tgz#c5d586ef38af6097650b49bc41b55fabb19f35bd" - dependencies: - inherits "^2.0.1" - readable-stream "^2.0.4" - -for-in@^1.0.1, for-in@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" - -for-own@^0.1.4: - version "0.1.5" - resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce" - dependencies: - for-in "^1.0.1" - -foreach@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" - -forever-agent@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" - -form-data@~2.1.1: - version "2.1.4" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.4.tgz#33c183acf193276ecaa98143a69e94bfee1750d1" - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.5" - mime-types "^2.1.12" - -form-data@~2.3.1: - version "2.3.2" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.2.tgz#4970498be604c20c005d4f5c23aecd21d6b49099" - dependencies: - asynckit "^0.4.0" - combined-stream "1.0.6" - mime-types "^2.1.12" - -fragment-cache@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" - dependencies: - map-cache "^0.2.2" - -from2@^2.1.0, from2@^2.1.1: - version "2.3.0" - resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" - dependencies: - inherits "^2.0.1" - readable-stream "^2.0.0" - -fs-write-stream-atomic@^1.0.8: - version "1.0.10" - resolved "https://registry.yarnpkg.com/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz#b47df53493ef911df75731e70a9ded0189db40c9" - dependencies: - graceful-fs "^4.1.2" - iferr "^0.1.5" - imurmurhash "^0.1.4" - readable-stream "1 || 2" - -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - -fsevents@^1.1.1, fsevents@^1.1.2: - version "1.1.3" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.1.3.tgz#11f82318f5fe7bb2cd22965a108e9306208216d8" - dependencies: - nan "^2.3.0" - node-pre-gyp "^0.6.39" - -fstream-ignore@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/fstream-ignore/-/fstream-ignore-1.0.5.tgz#9c31dae34767018fe1d249b24dada67d092da105" - dependencies: - fstream "^1.0.0" - inherits "2" - minimatch "^3.0.0" - -fstream@^1.0.0, fstream@^1.0.10, fstream@^1.0.2: - version "1.0.11" - resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171" - dependencies: - graceful-fs "^4.1.2" - inherits "~2.0.0" - mkdirp ">=0.5 0" - rimraf "2" - -function-bind@^1.0.2, function-bind@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" - -gauge@~2.7.3: - version "2.7.4" - resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" - dependencies: - aproba "^1.0.3" - console-control-strings "^1.0.0" - has-unicode "^2.0.0" - object-assign "^4.1.0" - signal-exit "^3.0.0" - string-width "^1.0.1" - strip-ansi "^3.0.1" - wide-align "^1.1.0" - -get-caller-file@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5" - -get-stream@3.0.0, get-stream@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" - -get-value@^2.0.3, get-value@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" - -getpass@^0.1.1: - version "0.1.7" - resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" - dependencies: - assert-plus "^1.0.0" - -gh-got@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/gh-got/-/gh-got-6.0.0.tgz#d74353004c6ec466647520a10bd46f7299d268d0" - dependencies: - got "^7.0.0" - is-plain-obj "^1.1.0" - -github-username@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/github-username/-/github-username-4.1.0.tgz#cbe280041883206da4212ae9e4b5f169c30bf417" - dependencies: - gh-got "^6.0.0" - -glob-all@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/glob-all/-/glob-all-3.1.0.tgz#8913ddfb5ee1ac7812656241b03d5217c64b02ab" - dependencies: - glob "^7.0.5" - yargs "~1.2.6" - -glob-base@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" - dependencies: - glob-parent "^2.0.0" - is-glob "^2.0.0" - -glob-parent@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" - dependencies: - is-glob "^2.0.0" - -glob-parent@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" - dependencies: - is-glob "^3.1.0" - path-dirname "^1.0.0" - -glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.1, glob@^7.1.2: - version "7.1.2" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - -global-modules@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-1.0.0.tgz#6d770f0eb523ac78164d72b5e71a8877265cc3ea" - dependencies: - global-prefix "^1.0.1" - is-windows "^1.0.1" - resolve-dir "^1.0.0" - -global-prefix@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-1.0.2.tgz#dbf743c6c14992593c655568cb66ed32c0122ebe" - dependencies: - expand-tilde "^2.0.2" - homedir-polyfill "^1.0.1" - ini "^1.3.4" - is-windows "^1.0.1" - which "^1.2.14" - -globals@^9.18.0: - version "9.18.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" - -globby@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/globby/-/globby-6.1.0.tgz#f5a6d70e8395e21c858fb0489d64df02424d506c" - dependencies: - array-union "^1.0.1" - glob "^7.0.3" - object-assign "^4.0.1" - pify "^2.0.0" - pinkie-promise "^2.0.0" - -got@^7.0.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/got/-/got-7.1.0.tgz#05450fd84094e6bbea56f451a43a9c289166385a" - dependencies: - decompress-response "^3.2.0" - duplexer3 "^0.1.4" - get-stream "^3.0.0" - is-plain-obj "^1.1.0" - is-retry-allowed "^1.0.0" - is-stream "^1.0.0" - isurl "^1.0.0-alpha5" - lowercase-keys "^1.0.0" - p-cancelable "^0.3.0" - p-timeout "^1.1.1" - safe-buffer "^5.0.1" - timed-out "^4.0.0" - url-parse-lax "^1.0.0" - url-to-options "^1.0.1" - -got@^8.2.0: - version "8.3.0" - resolved "https://registry.yarnpkg.com/got/-/got-8.3.0.tgz#6ba26e75f8a6cc4c6b3eb1fe7ce4fec7abac8533" - dependencies: - "@sindresorhus/is" "^0.7.0" - cacheable-request "^2.1.1" - decompress-response "^3.3.0" - duplexer3 "^0.1.4" - get-stream "^3.0.0" - into-stream "^3.1.0" - is-retry-allowed "^1.1.0" - isurl "^1.0.0-alpha5" - lowercase-keys "^1.0.0" - mimic-response "^1.0.0" - p-cancelable "^0.4.0" - p-timeout "^2.0.1" - pify "^3.0.0" - safe-buffer "^5.1.1" - timed-out "^4.0.1" - url-parse-lax "^3.0.0" - url-to-options "^1.0.1" - -graceful-fs@^4.1.11, graceful-fs@^4.1.2: - version "4.1.11" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" - -grouped-queue@^0.3.3: - version "0.3.3" - resolved "https://registry.yarnpkg.com/grouped-queue/-/grouped-queue-0.3.3.tgz#c167d2a5319c5a0e0964ef6a25b7c2df8996c85c" - dependencies: - lodash "^4.17.2" - -growly@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" - -handlebars@^4.0.3: - version "4.0.11" - resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.11.tgz#630a35dfe0294bc281edae6ffc5d329fc7982dcc" - dependencies: - async "^1.4.0" - optimist "^0.6.1" - source-map "^0.4.4" - optionalDependencies: - uglify-js "^2.6" - -har-schema@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-1.0.5.tgz#d263135f43307c02c602afc8fe95970c0151369e" - -har-schema@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" - -har-validator@~4.2.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-4.2.1.tgz#33481d0f1bbff600dd203d75812a6a5fba002e2a" - dependencies: - ajv "^4.9.1" - har-schema "^1.0.5" - -har-validator@~5.0.3: - version "5.0.3" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.0.3.tgz#ba402c266194f15956ef15e0fcf242993f6a7dfd" - dependencies: - ajv "^5.1.0" - har-schema "^2.0.0" - -has-ansi@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" - dependencies: - ansi-regex "^2.0.0" - -has-color@~0.1.0: - version "0.1.7" - resolved "https://registry.yarnpkg.com/has-color/-/has-color-0.1.7.tgz#67144a5260c34fc3cca677d041daf52fe7b78b2f" - -has-flag@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa" - -has-flag@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" - -has-symbol-support-x@^1.4.1: - version "1.4.2" - resolved "https://registry.yarnpkg.com/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz#1409f98bc00247da45da67cee0a36f282ff26455" - -has-to-string-tag-x@^1.2.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz#a045ab383d7b4b2012a00148ab0aa5f290044d4d" - dependencies: - has-symbol-support-x "^1.4.1" - -has-unicode@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" - -has-value@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" - dependencies: - get-value "^2.0.3" - has-values "^0.1.4" - isobject "^2.0.0" - -has-value@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" - dependencies: - get-value "^2.0.6" - has-values "^1.0.0" - isobject "^3.0.0" - -has-values@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" - -has-values@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" - dependencies: - is-number "^3.0.0" - kind-of "^4.0.0" - -has@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/has/-/has-1.0.1.tgz#8461733f538b0837c9361e39a9ab9e9704dc2f28" - dependencies: - function-bind "^1.0.2" - -hash-base@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-2.0.2.tgz#66ea1d856db4e8a5470cadf6fce23ae5244ef2e1" - dependencies: - inherits "^2.0.1" - -hash-base@^3.0.0: - version "3.0.4" - resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.0.4.tgz#5fc8686847ecd73499403319a6b0a3f3f6ae4918" - dependencies: - inherits "^2.0.1" - safe-buffer "^5.0.1" - -hash.js@^1.0.0, hash.js@^1.0.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.3.tgz#340dedbe6290187151c1ea1d777a3448935df846" - dependencies: - inherits "^2.0.3" - minimalistic-assert "^1.0.0" - -hawk@3.1.3, hawk@~3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" - dependencies: - boom "2.x.x" - cryptiles "2.x.x" - hoek "2.x.x" - sntp "1.x.x" - -hawk@~6.0.2: - version "6.0.2" - resolved "https://registry.yarnpkg.com/hawk/-/hawk-6.0.2.tgz#af4d914eb065f9b5ce4d9d11c1cb2126eecc3038" - dependencies: - boom "4.x.x" - cryptiles "3.x.x" - hoek "4.x.x" - sntp "2.x.x" - -he@1.1.x, he@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd" - -hmac-drbg@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" - dependencies: - hash.js "^1.0.3" - minimalistic-assert "^1.0.0" - minimalistic-crypto-utils "^1.0.1" - -hoek@2.x.x: - version "2.16.3" - resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" - -hoek@4.x.x: - version "4.2.1" - resolved "https://registry.yarnpkg.com/hoek/-/hoek-4.2.1.tgz#9634502aa12c445dd5a7c5734b572bb8738aacbb" - -home-or-tmp@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" - dependencies: - os-homedir "^1.0.0" - os-tmpdir "^1.0.1" - -homedir-polyfill@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz#4c2bbc8a758998feebf5ed68580f76d46768b4bc" - dependencies: - parse-passwd "^1.0.0" - -hosted-git-info@^2.1.4: - version "2.6.0" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.6.0.tgz#23235b29ab230c576aab0d4f13fc046b0b038222" - -html-encoding-sniffer@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz#e70d84b94da53aa375e11fe3a351be6642ca46f8" - dependencies: - whatwg-encoding "^1.0.1" - -html-minifier@^3.2.3: - version "3.5.12" - resolved "https://registry.yarnpkg.com/html-minifier/-/html-minifier-3.5.12.tgz#6bfad4d0327f5b8d2b62f5854654ac3703b9b031" - dependencies: - camel-case "3.0.x" - clean-css "4.1.x" - commander "2.15.x" - he "1.1.x" - ncname "1.0.x" - param-case "2.1.x" - relateurl "0.2.x" - uglify-js "3.3.x" - -html-webpack-plugin@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-3.1.0.tgz#6e02baaedb1e906310917f03239c793a75af2885" - dependencies: - html-minifier "^3.2.3" - loader-utils "^0.2.16" - lodash "^4.17.3" - pretty-error "^2.0.2" - tapable "^1.0.0" - toposort "^1.0.0" - util.promisify "1.0.0" - -htmlparser2@~3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.3.0.tgz#cc70d05a59f6542e43f0e685c982e14c924a9efe" - dependencies: - domelementtype "1" - domhandler "2.1" - domutils "1.1" - readable-stream "1.0" - -http-cache-semantics@3.8.1: - version "3.8.1" - resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz#39b0e16add9b605bf0a9ef3d9daaf4843b4cacd2" - -http-proxy@^1.8.1: - version "1.16.2" - resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.16.2.tgz#06dff292952bf64dbe8471fa9df73066d4f37742" - dependencies: - eventemitter3 "1.x.x" - requires-port "1.x.x" - -http-server@^0.11.1: - version "0.11.1" - resolved "https://registry.yarnpkg.com/http-server/-/http-server-0.11.1.tgz#2302a56a6ffef7f9abea0147d838a5e9b6b6a79b" - dependencies: - colors "1.0.3" - corser "~2.0.0" - ecstatic "^3.0.0" - http-proxy "^1.8.1" - opener "~1.4.0" - optimist "0.6.x" - portfinder "^1.0.13" - union "~0.4.3" - -http-signature@~1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf" - dependencies: - assert-plus "^0.2.0" - jsprim "^1.2.2" - sshpk "^1.7.0" - -http-signature@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" - dependencies: - assert-plus "^1.0.0" - jsprim "^1.2.2" - sshpk "^1.7.0" - -https-browserify@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" - -iconv-lite@0.4.19, iconv-lite@^0.4.17, iconv-lite@~0.4.13: - version "0.4.19" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" - -ieee754@^1.1.4: - version "1.1.11" - resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.11.tgz#c16384ffe00f5b7835824e67b6f2bd44a5229455" - -iferr@^0.1.5: - version "0.1.5" - resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501" - -import-local@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/import-local/-/import-local-1.0.0.tgz#5e4ffdc03f4fe6c009c6729beb29631c2f8227bc" - dependencies: - pkg-dir "^2.0.0" - resolve-cwd "^2.0.0" - -imurmurhash@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" - -indent-string@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80" - dependencies: - repeating "^2.0.0" - -indent-string@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-3.2.0.tgz#4a5fd6d27cc332f37e5419a504dbb837105c9289" - -indexof@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" - -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - dependencies: - once "^1.3.0" - wrappy "1" - -inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" - -inherits@2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" - -ini@^1.3.4, ini@~1.3.0: - version "1.3.5" - resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" - -inquirer@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.3.0.tgz#9dd2f2ad765dcab1ff0443b491442a20ba227dc9" - dependencies: - ansi-escapes "^3.0.0" - chalk "^2.0.0" - cli-cursor "^2.1.0" - cli-width "^2.0.0" - external-editor "^2.0.4" - figures "^2.0.0" - lodash "^4.3.0" - mute-stream "0.0.7" - run-async "^2.2.0" - rx-lite "^4.0.8" - rx-lite-aggregates "^4.0.8" - string-width "^2.1.0" - strip-ansi "^4.0.0" - through "^2.3.6" - -inquirer@^5.1.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-5.2.0.tgz#db350c2b73daca77ff1243962e9f22f099685726" - dependencies: - ansi-escapes "^3.0.0" - chalk "^2.0.0" - cli-cursor "^2.1.0" - cli-width "^2.0.0" - external-editor "^2.1.0" - figures "^2.0.0" - lodash "^4.3.0" - mute-stream "0.0.7" - run-async "^2.2.0" - rxjs "^5.5.2" - string-width "^2.1.0" - strip-ansi "^4.0.0" - through "^2.3.6" - -interpret@^1.0.0, interpret@^1.0.4: - version "1.1.0" - resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.1.0.tgz#7ed1b1410c6a0e0f78cf95d3b8440c63f78b8614" - -into-stream@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/into-stream/-/into-stream-3.1.0.tgz#96fb0a936c12babd6ff1752a17d05616abd094c6" - dependencies: - from2 "^2.1.1" - p-is-promise "^1.1.0" - -invariant@^2.2.2: - version "2.2.4" - resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" - dependencies: - loose-envify "^1.0.0" - -invert-kv@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" - -is-accessor-descriptor@^0.1.6: - version "0.1.6" - resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" - dependencies: - kind-of "^3.0.2" - -is-accessor-descriptor@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" - dependencies: - kind-of "^6.0.0" - -is-arrayish@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" - -is-binary-path@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" - dependencies: - binary-extensions "^1.0.0" - -is-buffer@^1.1.5: - version "1.1.6" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" - -is-builtin-module@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe" - dependencies: - builtin-modules "^1.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" - -is-ci@^1.0.10: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-1.1.0.tgz#247e4162e7860cebbdaf30b774d6b0ac7dcfe7a5" - dependencies: - ci-info "^1.0.0" - -is-data-descriptor@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" - dependencies: - kind-of "^3.0.2" - -is-data-descriptor@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" - dependencies: - kind-of "^6.0.0" - -is-date-object@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16" - -is-descriptor@^0.1.0: - version "0.1.6" - resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" - dependencies: - is-accessor-descriptor "^0.1.6" - is-data-descriptor "^0.1.4" - kind-of "^5.0.0" - -is-descriptor@^1.0.0, is-descriptor@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" - dependencies: - is-accessor-descriptor "^1.0.0" - is-data-descriptor "^1.0.0" - kind-of "^6.0.2" - -is-dotfile@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" - -is-equal-shallow@^0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" - dependencies: - is-primitive "^2.0.0" - -is-extendable@^0.1.0, is-extendable@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" - -is-extendable@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" - dependencies: - is-plain-object "^2.0.4" - -is-extglob@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" - -is-extglob@^2.1.0, is-extglob@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" - -is-finite@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" - dependencies: - number-is-nan "^1.0.0" - -is-fullwidth-code-point@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" - dependencies: - number-is-nan "^1.0.0" - -is-fullwidth-code-point@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" - -is-generator-fn@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-1.0.0.tgz#969d49e1bb3329f6bb7f09089be26578b2ddd46a" - -is-glob@^2.0.0, is-glob@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" - dependencies: - is-extglob "^1.0.0" - -is-glob@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" - dependencies: - is-extglob "^2.1.0" - -is-glob@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.0.tgz#9521c76845cc2610a85203ddf080a958c2ffabc0" - dependencies: - is-extglob "^2.1.1" - -is-number@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" - dependencies: - kind-of "^3.0.2" - -is-number@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" - dependencies: - kind-of "^3.0.2" - -is-number@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff" - -is-object@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-object/-/is-object-1.0.1.tgz#8952688c5ec2ffd6b03ecc85e769e02903083470" - -is-observable@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/is-observable/-/is-observable-0.2.0.tgz#b361311d83c6e5d726cabf5e250b0237106f5ae2" - dependencies: - symbol-observable "^0.2.2" - -is-odd@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-odd/-/is-odd-2.0.0.tgz#7646624671fd7ea558ccd9a2795182f2958f1b24" - dependencies: - is-number "^4.0.0" - -is-plain-obj@^1.0.0, is-plain-obj@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" - -is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" - dependencies: - isobject "^3.0.1" - -is-posix-bracket@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" - -is-primitive@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" - -is-promise@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" - -is-regex@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" - dependencies: - has "^1.0.1" - -is-retry-allowed@^1.0.0, is-retry-allowed@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz#11a060568b67339444033d0125a61a20d564fb34" - -is-scoped@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-scoped/-/is-scoped-1.0.0.tgz#449ca98299e713038256289ecb2b540dc437cb30" - dependencies: - scoped-regex "^1.0.0" - -is-stream@^1.0.0, is-stream@^1.0.1, is-stream@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" - -is-symbol@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.1.tgz#3cc59f00025194b6ab2e38dbae6689256b660572" - -is-typedarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" - -is-utf8@^0.2.0: - version "0.2.1" - resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" - -is-windows@^1.0.1, is-windows@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" - -isarray@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" - -isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" - -isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - -isobject@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" - dependencies: - isarray "1.0.0" - -isobject@^3.0.0, isobject@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" - -isomorphic-fetch@^2.1.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9" - dependencies: - node-fetch "^1.0.1" - whatwg-fetch ">=0.10.0" - -isstream@~0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" - -istanbul-api@^1.1.14: - version "1.3.1" - resolved "https://registry.yarnpkg.com/istanbul-api/-/istanbul-api-1.3.1.tgz#4c3b05d18c0016d1022e079b98dc82c40f488954" - dependencies: - async "^2.1.4" - compare-versions "^3.1.0" - fileset "^2.0.2" - istanbul-lib-coverage "^1.2.0" - istanbul-lib-hook "^1.2.0" - istanbul-lib-instrument "^1.10.1" - istanbul-lib-report "^1.1.4" - istanbul-lib-source-maps "^1.2.4" - istanbul-reports "^1.3.0" - js-yaml "^3.7.0" - mkdirp "^0.5.1" - once "^1.4.0" - -istanbul-lib-coverage@^1.1.1, istanbul-lib-coverage@^1.1.2, istanbul-lib-coverage@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-1.2.0.tgz#f7d8f2e42b97e37fe796114cb0f9d68b5e3a4341" - -istanbul-lib-hook@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-hook/-/istanbul-lib-hook-1.2.0.tgz#ae556fd5a41a6e8efa0b1002b1e416dfeaf9816c" - dependencies: - append-transform "^0.4.0" - -istanbul-lib-instrument@^1.10.1, istanbul-lib-instrument@^1.7.5, istanbul-lib-instrument@^1.8.0: - version "1.10.1" - resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-1.10.1.tgz#724b4b6caceba8692d3f1f9d0727e279c401af7b" - dependencies: - babel-generator "^6.18.0" - babel-template "^6.16.0" - babel-traverse "^6.18.0" - babel-types "^6.18.0" - babylon "^6.18.0" - istanbul-lib-coverage "^1.2.0" - semver "^5.3.0" - -istanbul-lib-report@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-1.1.4.tgz#e886cdf505c4ebbd8e099e4396a90d0a28e2acb5" - dependencies: - istanbul-lib-coverage "^1.2.0" - mkdirp "^0.5.1" - path-parse "^1.0.5" - supports-color "^3.1.2" - -istanbul-lib-source-maps@^1.2.1: - version "1.2.3" - resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.2.3.tgz#20fb54b14e14b3fb6edb6aca3571fd2143db44e6" - dependencies: - debug "^3.1.0" - istanbul-lib-coverage "^1.1.2" - mkdirp "^0.5.1" - rimraf "^2.6.1" - source-map "^0.5.3" - -istanbul-lib-source-maps@^1.2.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.2.4.tgz#cc7ccad61629f4efff8e2f78adb8c522c9976ec7" - dependencies: - debug "^3.1.0" - istanbul-lib-coverage "^1.2.0" - mkdirp "^0.5.1" - rimraf "^2.6.1" - source-map "^0.5.3" - -istanbul-reports@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-1.3.0.tgz#2f322e81e1d9520767597dca3c20a0cce89a3554" - dependencies: - handlebars "^4.0.3" - -istextorbinary@^2.1.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/istextorbinary/-/istextorbinary-2.2.1.tgz#a5231a08ef6dd22b268d0895084cf8d58b5bec53" - dependencies: - binaryextensions "2" - editions "^1.3.3" - textextensions "2" - -isurl@^1.0.0-alpha5: - version "1.0.0" - resolved "https://registry.yarnpkg.com/isurl/-/isurl-1.0.0.tgz#b27f4f49f3cdaa3ea44a0a5b7f3462e6edc39d67" - dependencies: - has-to-string-tag-x "^1.2.0" - is-object "^1.0.1" - -jest-changed-files@^22.4.3: - version "22.4.3" - resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-22.4.3.tgz#8882181e022c38bd46a2e4d18d44d19d90a90fb2" - dependencies: - throat "^4.0.0" - -jest-cli@^22.4.3: - version "22.4.3" - resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-22.4.3.tgz#bf16c4a5fb7edc3fa5b9bb7819e34139e88a72c7" - dependencies: - ansi-escapes "^3.0.0" - chalk "^2.0.1" - exit "^0.1.2" - glob "^7.1.2" - graceful-fs "^4.1.11" - import-local "^1.0.0" - is-ci "^1.0.10" - istanbul-api "^1.1.14" - istanbul-lib-coverage "^1.1.1" - istanbul-lib-instrument "^1.8.0" - istanbul-lib-source-maps "^1.2.1" - jest-changed-files "^22.4.3" - jest-config "^22.4.3" - jest-environment-jsdom "^22.4.3" - jest-get-type "^22.4.3" - jest-haste-map "^22.4.3" - jest-message-util "^22.4.3" - jest-regex-util "^22.4.3" - jest-resolve-dependencies "^22.4.3" - jest-runner "^22.4.3" - jest-runtime "^22.4.3" - jest-snapshot "^22.4.3" - jest-util "^22.4.3" - jest-validate "^22.4.3" - jest-worker "^22.4.3" - micromatch "^2.3.11" - node-notifier "^5.2.1" - realpath-native "^1.0.0" - rimraf "^2.5.4" - slash "^1.0.0" - string-length "^2.0.0" - strip-ansi "^4.0.0" - which "^1.2.12" - yargs "^10.0.3" - -jest-config@^22.4.3: - version "22.4.3" - resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-22.4.3.tgz#0e9d57db267839ea31309119b41dc2fa31b76403" - dependencies: - chalk "^2.0.1" - glob "^7.1.1" - jest-environment-jsdom "^22.4.3" - jest-environment-node "^22.4.3" - jest-get-type "^22.4.3" - jest-jasmine2 "^22.4.3" - jest-regex-util "^22.4.3" - jest-resolve "^22.4.3" - jest-util "^22.4.3" - jest-validate "^22.4.3" - pretty-format "^22.4.3" - -jest-diff@^22.4.3: - version "22.4.3" - resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-22.4.3.tgz#e18cc3feff0aeef159d02310f2686d4065378030" - dependencies: - chalk "^2.0.1" - diff "^3.2.0" - jest-get-type "^22.4.3" - pretty-format "^22.4.3" - -jest-docblock@^22.4.3: - version "22.4.3" - resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-22.4.3.tgz#50886f132b42b280c903c592373bb6e93bb68b19" - dependencies: - detect-newline "^2.1.0" - -jest-environment-jsdom@^22.4.3: - version "22.4.3" - resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-22.4.3.tgz#d67daa4155e33516aecdd35afd82d4abf0fa8a1e" - dependencies: - jest-mock "^22.4.3" - jest-util "^22.4.3" - jsdom "^11.5.1" - -jest-environment-node@^22.4.3: - version "22.4.3" - resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-22.4.3.tgz#54c4eaa374c83dd52a9da8759be14ebe1d0b9129" - dependencies: - jest-mock "^22.4.3" - jest-util "^22.4.3" - -jest-get-type@^22.4.3: - version "22.4.3" - resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-22.4.3.tgz#e3a8504d8479342dd4420236b322869f18900ce4" - -jest-haste-map@^22.4.3: - version "22.4.3" - resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-22.4.3.tgz#25842fa2ba350200767ac27f658d58b9d5c2e20b" - dependencies: - fb-watchman "^2.0.0" - graceful-fs "^4.1.11" - jest-docblock "^22.4.3" - jest-serializer "^22.4.3" - jest-worker "^22.4.3" - micromatch "^2.3.11" - sane "^2.0.0" - -jest-jasmine2@^22.4.3: - version "22.4.3" - resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-22.4.3.tgz#4daf64cd14c793da9db34a7c7b8dcfe52a745965" - dependencies: - chalk "^2.0.1" - co "^4.6.0" - expect "^22.4.3" - graceful-fs "^4.1.11" - is-generator-fn "^1.0.0" - jest-diff "^22.4.3" - jest-matcher-utils "^22.4.3" - jest-message-util "^22.4.3" - jest-snapshot "^22.4.3" - jest-util "^22.4.3" - source-map-support "^0.5.0" - -jest-leak-detector@^22.4.3: - version "22.4.3" - resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-22.4.3.tgz#2b7b263103afae8c52b6b91241a2de40117e5b35" - dependencies: - pretty-format "^22.4.3" - -jest-matcher-utils@^22.4.3: - version "22.4.3" - resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-22.4.3.tgz#4632fe428ebc73ebc194d3c7b65d37b161f710ff" - dependencies: - chalk "^2.0.1" - jest-get-type "^22.4.3" - pretty-format "^22.4.3" - -jest-message-util@^22.4.3: - version "22.4.3" - resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-22.4.3.tgz#cf3d38aafe4befddbfc455e57d65d5239e399eb7" - dependencies: - "@babel/code-frame" "^7.0.0-beta.35" - chalk "^2.0.1" - micromatch "^2.3.11" - slash "^1.0.0" - stack-utils "^1.0.1" - -jest-mock@^22.4.3: - version "22.4.3" - resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-22.4.3.tgz#f63ba2f07a1511772cdc7979733397df770aabc7" - -jest-regex-util@^22.4.3: - version "22.4.3" - resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-22.4.3.tgz#a826eb191cdf22502198c5401a1fc04de9cef5af" - -jest-resolve-dependencies@^22.4.3: - version "22.4.3" - resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-22.4.3.tgz#e2256a5a846732dc3969cb72f3c9ad7725a8195e" - dependencies: - jest-regex-util "^22.4.3" - -jest-resolve@^22.4.3: - version "22.4.3" - resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-22.4.3.tgz#0ce9d438c8438229aa9b916968ec6b05c1abb4ea" - dependencies: - browser-resolve "^1.11.2" - chalk "^2.0.1" - -jest-runner@^22.4.3: - version "22.4.3" - resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-22.4.3.tgz#298ddd6a22b992c64401b4667702b325e50610c3" - dependencies: - exit "^0.1.2" - jest-config "^22.4.3" - jest-docblock "^22.4.3" - jest-haste-map "^22.4.3" - jest-jasmine2 "^22.4.3" - jest-leak-detector "^22.4.3" - jest-message-util "^22.4.3" - jest-runtime "^22.4.3" - jest-util "^22.4.3" - jest-worker "^22.4.3" - throat "^4.0.0" - -jest-runtime@^22.4.3: - version "22.4.3" - resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-22.4.3.tgz#b69926c34b851b920f666c93e86ba2912087e3d0" - dependencies: - babel-core "^6.0.0" - babel-jest "^22.4.3" - babel-plugin-istanbul "^4.1.5" - chalk "^2.0.1" - convert-source-map "^1.4.0" - exit "^0.1.2" - graceful-fs "^4.1.11" - jest-config "^22.4.3" - jest-haste-map "^22.4.3" - jest-regex-util "^22.4.3" - jest-resolve "^22.4.3" - jest-util "^22.4.3" - jest-validate "^22.4.3" - json-stable-stringify "^1.0.1" - micromatch "^2.3.11" - realpath-native "^1.0.0" - slash "^1.0.0" - strip-bom "3.0.0" - write-file-atomic "^2.1.0" - yargs "^10.0.3" - -jest-serializer@^22.4.3: - version "22.4.3" - resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-22.4.3.tgz#a679b81a7f111e4766235f4f0c46d230ee0f7436" - -jest-snapshot@^22.4.3: - version "22.4.3" - resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-22.4.3.tgz#b5c9b42846ffb9faccb76b841315ba67887362d2" - dependencies: - chalk "^2.0.1" - jest-diff "^22.4.3" - jest-matcher-utils "^22.4.3" - mkdirp "^0.5.1" - natural-compare "^1.4.0" - pretty-format "^22.4.3" - -jest-util@^22.4.3: - version "22.4.3" - resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-22.4.3.tgz#c70fec8eec487c37b10b0809dc064a7ecf6aafac" - dependencies: - callsites "^2.0.0" - chalk "^2.0.1" - graceful-fs "^4.1.11" - is-ci "^1.0.10" - jest-message-util "^22.4.3" - mkdirp "^0.5.1" - source-map "^0.6.0" - -jest-validate@^22.4.3: - version "22.4.3" - resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-22.4.3.tgz#0780954a5a7daaeec8d3c10834b9280865976b30" - dependencies: - chalk "^2.0.1" - jest-config "^22.4.3" - jest-get-type "^22.4.3" - leven "^2.1.0" - pretty-format "^22.4.3" - -jest-worker@^22.4.3: - version "22.4.3" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-22.4.3.tgz#5c421417cba1c0abf64bf56bd5fb7968d79dd40b" - dependencies: - merge-stream "^1.0.1" - -jest@^22.4.3: - version "22.4.3" - resolved "https://registry.yarnpkg.com/jest/-/jest-22.4.3.tgz#2261f4b117dc46d9a4a1a673d2150958dee92f16" - dependencies: - import-local "^1.0.0" - jest-cli "^22.4.3" - -js-tokens@^3.0.0, js-tokens@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" - -js-yaml@^3.7.0: - version "3.11.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.11.0.tgz#597c1a8bd57152f26d622ce4117851a51f5ebaef" - dependencies: - argparse "^1.0.7" - esprima "^4.0.0" - -jsbn@~0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" - -jscodeshift@^0.4.0: - version "0.4.1" - resolved "https://registry.yarnpkg.com/jscodeshift/-/jscodeshift-0.4.1.tgz#da91a1c2eccfa03a3387a21d39948e251ced444a" - dependencies: - async "^1.5.0" - babel-plugin-transform-flow-strip-types "^6.8.0" - babel-preset-es2015 "^6.9.0" - babel-preset-stage-1 "^6.5.0" - babel-register "^6.9.0" - babylon "^6.17.3" - colors "^1.1.2" - flow-parser "^0.*" - lodash "^4.13.1" - micromatch "^2.3.7" - node-dir "0.1.8" - nomnom "^1.8.1" - recast "^0.12.5" - temp "^0.8.1" - write-file-atomic "^1.2.0" - -jscodeshift@^0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/jscodeshift/-/jscodeshift-0.5.0.tgz#bdb7b6cc20dd62c16aa728c3fa2d2fe66ca7c748" - dependencies: - babel-plugin-transform-flow-strip-types "^6.8.0" - babel-preset-es2015 "^6.9.0" - babel-preset-stage-1 "^6.5.0" - babel-register "^6.9.0" - babylon "^7.0.0-beta.30" - colors "^1.1.2" - flow-parser "^0.*" - lodash "^4.13.1" - micromatch "^2.3.7" - neo-async "^2.5.0" - node-dir "0.1.8" - nomnom "^1.8.1" - recast "^0.14.1" - temp "^0.8.1" - write-file-atomic "^1.2.0" - -jsdom@^11.5.1: - version "11.6.2" - resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-11.6.2.tgz#25d1ef332d48adf77fc5221fe2619967923f16bb" - dependencies: - abab "^1.0.4" - acorn "^5.3.0" - acorn-globals "^4.1.0" - array-equal "^1.0.0" - browser-process-hrtime "^0.1.2" - content-type-parser "^1.0.2" - cssom ">= 0.3.2 < 0.4.0" - cssstyle ">= 0.2.37 < 0.3.0" - domexception "^1.0.0" - escodegen "^1.9.0" - html-encoding-sniffer "^1.0.2" - left-pad "^1.2.0" - nwmatcher "^1.4.3" - parse5 "4.0.0" - pn "^1.1.0" - request "^2.83.0" - request-promise-native "^1.0.5" - sax "^1.2.4" - symbol-tree "^3.2.2" - tough-cookie "^2.3.3" - w3c-hr-time "^1.0.1" - webidl-conversions "^4.0.2" - whatwg-encoding "^1.0.3" - whatwg-url "^6.4.0" - ws "^4.0.0" - xml-name-validator "^3.0.0" - -jsesc@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" - -jsesc@~0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" - -json-buffer@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" - -json-parse-better-errors@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.1.tgz#50183cd1b2d25275de069e9e71b467ac9eab973a" - -json-schema-traverse@^0.3.0: - version "0.3.1" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340" - -json-schema@0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" - -json-stable-stringify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" - dependencies: - jsonify "~0.0.0" - -json-stringify-safe@~5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" - -json5@^0.5.0, json5@^0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" - -jsonify@~0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" - -jsprim@^1.2.2: - version "1.4.1" - resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" - dependencies: - assert-plus "1.0.0" - extsprintf "1.3.0" - json-schema "0.2.3" - verror "1.10.0" - -keyv@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.0.0.tgz#44923ba39e68b12a7cec7df6c3268c031f2ef373" - dependencies: - json-buffer "3.0.0" - -kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: - version "3.2.2" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" - dependencies: - is-buffer "^1.1.5" - -kind-of@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" - dependencies: - is-buffer "^1.1.5" - -kind-of@^5.0.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" - -kind-of@^6.0.0, kind-of@^6.0.2: - version "6.0.2" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051" - -lazy-cache@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e" - -lcid@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" - dependencies: - invert-kv "^1.0.0" - -left-pad@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/left-pad/-/left-pad-1.2.0.tgz#d30a73c6b8201d8f7d8e7956ba9616087a68e0ee" - -leven@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/leven/-/leven-2.1.0.tgz#c2e7a9f772094dee9d34202ae8acce4687875580" - -levn@~0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" - dependencies: - prelude-ls "~1.1.2" - type-check "~0.3.2" - -listr-silent-renderer@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/listr-silent-renderer/-/listr-silent-renderer-1.1.1.tgz#924b5a3757153770bf1a8e3fbf74b8bbf3f9242e" - -listr-update-renderer@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/listr-update-renderer/-/listr-update-renderer-0.4.0.tgz#344d980da2ca2e8b145ba305908f32ae3f4cc8a7" - dependencies: - chalk "^1.1.3" - cli-truncate "^0.2.1" - elegant-spinner "^1.0.1" - figures "^1.7.0" - indent-string "^3.0.0" - log-symbols "^1.0.2" - log-update "^1.0.2" - strip-ansi "^3.0.1" - -listr-verbose-renderer@^0.4.0: - version "0.4.1" - resolved "https://registry.yarnpkg.com/listr-verbose-renderer/-/listr-verbose-renderer-0.4.1.tgz#8206f4cf6d52ddc5827e5fd14989e0e965933a35" - dependencies: - chalk "^1.1.3" - cli-cursor "^1.0.2" - date-fns "^1.27.2" - figures "^1.7.0" - -listr@^0.13.0: - version "0.13.0" - resolved "https://registry.yarnpkg.com/listr/-/listr-0.13.0.tgz#20bb0ba30bae660ee84cc0503df4be3d5623887d" - dependencies: - chalk "^1.1.3" - cli-truncate "^0.2.1" - figures "^1.7.0" - indent-string "^2.1.0" - is-observable "^0.2.0" - is-promise "^2.1.0" - is-stream "^1.1.0" - listr-silent-renderer "^1.1.1" - listr-update-renderer "^0.4.0" - listr-verbose-renderer "^0.4.0" - log-symbols "^1.0.2" - log-update "^1.0.2" - ora "^0.2.3" - p-map "^1.1.1" - rxjs "^5.4.2" - stream-to-observable "^0.2.0" - strip-ansi "^3.0.1" - -load-json-file@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" - dependencies: - graceful-fs "^4.1.2" - parse-json "^2.2.0" - pify "^2.0.0" - pinkie-promise "^2.0.0" - strip-bom "^2.0.0" - -load-json-file@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b" - dependencies: - graceful-fs "^4.1.2" - parse-json "^4.0.0" - pify "^3.0.0" - strip-bom "^3.0.0" - -loader-runner@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.3.0.tgz#f482aea82d543e07921700d5a46ef26fdac6b8a2" - -loader-utils@^0.2.16: - version "0.2.17" - resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-0.2.17.tgz#f86e6374d43205a6e6c60e9196f17c0299bfb348" - dependencies: - big.js "^3.1.3" - emojis-list "^2.0.0" - json5 "^0.5.0" - object-assign "^4.0.1" - -loader-utils@^1.0.2, loader-utils@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.1.0.tgz#c98aef488bcceda2ffb5e2de646d6a754429f5cd" - dependencies: - big.js "^3.1.3" - emojis-list "^2.0.0" - json5 "^0.5.0" - -locate-path@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" - dependencies: - p-locate "^2.0.0" - path-exists "^3.0.0" - -lodash.sortby@^4.7.0: - version "4.7.0" - resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" - -lodash@^4.13.1, lodash@^4.14.0, lodash@^4.17.2, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.3.0: - version "4.17.5" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.5.tgz#99a92d65c0272debe8c96b6057bc8fbfa3bed511" - -log-symbols@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-1.0.2.tgz#376ff7b58ea3086a0f09facc74617eca501e1a18" - dependencies: - chalk "^1.0.0" - -log-symbols@^2.1.0, log-symbols@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a" - dependencies: - chalk "^2.0.1" - -log-update@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/log-update/-/log-update-1.0.2.tgz#19929f64c4093d2d2e7075a1dad8af59c296b8d1" - dependencies: - ansi-escapes "^1.0.0" - cli-cursor "^1.0.2" - -longest@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" - -loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848" - dependencies: - js-tokens "^3.0.0" - -lower-case@^1.1.1: - version "1.1.4" - resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-1.1.4.tgz#9a2cabd1b9e8e0ae993a4bf7d5875c39c42e8eac" - -lowercase-keys@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.0.tgz#4e3366b39e7f5457e35f1324bdf6f88d0bfc7306" - -lowercase-keys@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" - -lru-cache@^4.0.1, lru-cache@^4.1.1: - version "4.1.2" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.2.tgz#45234b2e6e2f2b33da125624c4664929a0224c3f" - dependencies: - pseudomap "^1.0.2" - yallist "^2.1.2" - -make-dir@^1.0.0, make-dir@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.2.0.tgz#6d6a49eead4aae296c53bbf3a1a008bd6c89469b" - dependencies: - pify "^3.0.0" - -makeerror@1.0.x: - version "1.0.11" - resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c" - dependencies: - tmpl "1.0.x" - -map-cache@^0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" - -map-visit@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" - dependencies: - object-visit "^1.0.0" - -md5.js@^1.3.4: - version "1.3.4" - resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.4.tgz#e9bdbde94a20a5ac18b04340fc5764d5b09d901d" - dependencies: - hash-base "^3.0.0" - inherits "^2.0.1" - -mem-fs-editor@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/mem-fs-editor/-/mem-fs-editor-3.0.2.tgz#dd0a6eaf2bb8a6b37740067aa549eb530105af9f" - dependencies: - commondir "^1.0.1" - deep-extend "^0.4.0" - ejs "^2.3.1" - glob "^7.0.3" - globby "^6.1.0" - mkdirp "^0.5.0" - multimatch "^2.0.0" - rimraf "^2.2.8" - through2 "^2.0.0" - vinyl "^2.0.1" - -mem-fs@^1.1.0: - version "1.1.3" - resolved "https://registry.yarnpkg.com/mem-fs/-/mem-fs-1.1.3.tgz#b8ae8d2e3fcb6f5d3f9165c12d4551a065d989cc" - dependencies: - through2 "^2.0.0" - vinyl "^1.1.0" - vinyl-file "^2.0.0" - -mem@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/mem/-/mem-1.1.0.tgz#5edd52b485ca1d900fe64895505399a0dfa45f76" - dependencies: - mimic-fn "^1.0.0" - -memory-fs@^0.4.0, memory-fs@~0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552" - dependencies: - errno "^0.1.3" - readable-stream "^2.0.1" - -merge-stream@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-1.0.1.tgz#4041202d508a342ba00174008df0c251b8c135e1" - dependencies: - readable-stream "^2.0.1" - -merge@^1.1.3: - version "1.2.0" - resolved "https://registry.yarnpkg.com/merge/-/merge-1.2.0.tgz#7531e39d4949c281a66b8c5a6e0265e8b05894da" - -micromatch@^2.3.11, micromatch@^2.3.7: - version "2.3.11" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" - dependencies: - arr-diff "^2.0.0" - array-unique "^0.2.1" - braces "^1.8.2" - expand-brackets "^0.1.4" - extglob "^0.3.1" - filename-regex "^2.0.0" - is-extglob "^1.0.0" - is-glob "^2.0.1" - kind-of "^3.0.2" - normalize-path "^2.0.1" - object.omit "^2.0.0" - parse-glob "^3.0.4" - regex-cache "^0.4.2" - -micromatch@^3.1.4, micromatch@^3.1.8: - version "3.1.10" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" - dependencies: - arr-diff "^4.0.0" - array-unique "^0.3.2" - braces "^2.3.1" - define-property "^2.0.2" - extend-shallow "^3.0.2" - extglob "^2.0.4" - fragment-cache "^0.2.1" - kind-of "^6.0.2" - nanomatch "^1.2.9" - object.pick "^1.3.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.2" - -miller-rabin@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" - dependencies: - bn.js "^4.0.0" - brorand "^1.0.1" - -mime-db@~1.33.0: - version "1.33.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.33.0.tgz#a3492050a5cb9b63450541e39d9788d2272783db" - -mime-types@^2.1.12, mime-types@~2.1.17, mime-types@~2.1.7: - version "2.1.18" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.18.tgz#6f323f60a83d11146f831ff11fd66e2fe5503bb8" - dependencies: - mime-db "~1.33.0" - -mime@^1.4.1: - version "1.6.0" - resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" - -mimic-fn@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" - -mimic-response@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.0.tgz#df3d3652a73fded6b9b0b24146e6fd052353458e" - -minimalistic-assert@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz#702be2dda6b37f4836bcb3f5db56641b64a1d3d3" - -minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" - -minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - dependencies: - brace-expansion "^1.1.7" - -minimist@0.0.8: - version "0.0.8" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" - -minimist@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.1.0.tgz#99df657a52574c21c9057497df742790b2b4c0de" - -minimist@^1.1.0, minimist@^1.1.1, minimist@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" - -minimist@~0.0.1: - version "0.0.10" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" - -mississippi@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-2.0.0.tgz#3442a508fafc28500486feea99409676e4ee5a6f" - dependencies: - concat-stream "^1.5.0" - duplexify "^3.4.2" - end-of-stream "^1.1.0" - flush-write-stream "^1.0.0" - from2 "^2.1.0" - parallel-transform "^1.1.0" - pump "^2.0.1" - pumpify "^1.3.3" - stream-each "^1.1.0" - through2 "^2.0.0" - -mixin-deep@^1.2.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.1.tgz#a49e7268dce1a0d9698e45326c5626df3543d0fe" - dependencies: - for-in "^1.0.2" - is-extendable "^1.0.1" - -mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0: - version "0.5.1" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" - dependencies: - minimist "0.0.8" - -move-concurrently@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92" - dependencies: - aproba "^1.1.1" - copy-concurrently "^1.0.0" - fs-write-stream-atomic "^1.0.8" - mkdirp "^0.5.1" - rimraf "^2.5.4" - run-queue "^1.0.3" - -ms@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" - -multimatch@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/multimatch/-/multimatch-2.1.0.tgz#9c7906a22fb4c02919e2f5f75161b4cdbd4b2a2b" - dependencies: - array-differ "^1.0.0" - array-union "^1.0.1" - arrify "^1.0.0" - minimatch "^3.0.0" - -mute-stream@0.0.7: - version "0.0.7" - resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" - -nan@^2.3.0: - version "2.10.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.10.0.tgz#96d0cd610ebd58d4b4de9cc0c6828cda99c7548f" - -nanomatch@^1.2.9: - version "1.2.9" - resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.9.tgz#879f7150cb2dab7a471259066c104eee6e0fa7c2" - dependencies: - arr-diff "^4.0.0" - array-unique "^0.3.2" - define-property "^2.0.2" - extend-shallow "^3.0.2" - fragment-cache "^0.2.1" - is-odd "^2.0.0" - is-windows "^1.0.2" - kind-of "^6.0.2" - object.pick "^1.3.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - -natural-compare@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" - -ncname@1.0.x: - version "1.0.0" - resolved "https://registry.yarnpkg.com/ncname/-/ncname-1.0.0.tgz#5b57ad18b1ca092864ef62b0b1ed8194f383b71c" - dependencies: - xml-char-classes "^1.0.0" - -neo-async@^2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.5.0.tgz#76b1c823130cca26acfbaccc8fbaf0a2fa33b18f" - -nice-try@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.4.tgz#d93962f6c52f2c1558c0fbda6d512819f1efe1c4" - -no-case@^2.2.0: - version "2.3.2" - resolved "https://registry.yarnpkg.com/no-case/-/no-case-2.3.2.tgz#60b813396be39b3f1288a4c1ed5d1e7d28b464ac" - dependencies: - lower-case "^1.1.1" - -node-dir@0.1.8: - version "0.1.8" - resolved "https://registry.yarnpkg.com/node-dir/-/node-dir-0.1.8.tgz#55fb8deb699070707fb67f91a460f0448294c77d" - -node-fetch@^1.0.1: - version "1.7.3" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef" - dependencies: - encoding "^0.1.11" - is-stream "^1.0.1" - -node-int64@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" - -node-libs-browser@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.1.0.tgz#5f94263d404f6e44767d726901fff05478d600df" - dependencies: - assert "^1.1.1" - browserify-zlib "^0.2.0" - buffer "^4.3.0" - console-browserify "^1.1.0" - constants-browserify "^1.0.0" - crypto-browserify "^3.11.0" - domain-browser "^1.1.1" - events "^1.0.0" - https-browserify "^1.0.0" - os-browserify "^0.3.0" - path-browserify "0.0.0" - process "^0.11.10" - punycode "^1.2.4" - querystring-es3 "^0.2.0" - readable-stream "^2.3.3" - stream-browserify "^2.0.1" - stream-http "^2.7.2" - string_decoder "^1.0.0" - timers-browserify "^2.0.4" - tty-browserify "0.0.0" - url "^0.11.0" - util "^0.10.3" - vm-browserify "0.0.4" - -node-notifier@^5.2.1: - version "5.2.1" - resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-5.2.1.tgz#fa313dd08f5517db0e2502e5758d664ac69f9dea" - dependencies: - growly "^1.3.0" - semver "^5.4.1" - shellwords "^0.1.1" - which "^1.3.0" - -node-pre-gyp@^0.6.39: - version "0.6.39" - resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.39.tgz#c00e96860b23c0e1420ac7befc5044e1d78d8649" - dependencies: - detect-libc "^1.0.2" - hawk "3.1.3" - mkdirp "^0.5.1" - nopt "^4.0.1" - npmlog "^4.0.2" - rc "^1.1.7" - request "2.81.0" - rimraf "^2.6.1" - semver "^5.3.0" - tar "^2.2.1" - tar-pack "^3.4.0" - -nomnom@^1.8.1: - version "1.8.1" - resolved "https://registry.yarnpkg.com/nomnom/-/nomnom-1.8.1.tgz#2151f722472ba79e50a76fc125bb8c8f2e4dc2a7" - dependencies: - chalk "~0.4.0" - underscore "~1.6.0" - -nopt@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" - dependencies: - abbrev "1" - osenv "^0.1.4" - -normalize-package-data@^2.3.2: - version "2.4.0" - resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.4.0.tgz#12f95a307d58352075a04907b84ac8be98ac012f" - dependencies: - hosted-git-info "^2.1.4" - is-builtin-module "^1.0.0" - semver "2 || 3 || 4 || 5" - validate-npm-package-license "^3.0.1" - -normalize-path@^2.0.1, normalize-path@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" - dependencies: - remove-trailing-separator "^1.0.1" - -normalize-url@2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-2.0.1.tgz#835a9da1551fa26f70e92329069a23aa6574d7e6" - dependencies: - prepend-http "^2.0.0" - query-string "^5.0.1" - sort-keys "^2.0.0" - -npm-run-path@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" - dependencies: - path-key "^2.0.0" - -npmlog@^4.0.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" - dependencies: - are-we-there-yet "~1.1.2" - console-control-strings "~1.1.0" - gauge "~2.7.3" - set-blocking "~2.0.0" - -nth-check@~1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-1.0.1.tgz#9929acdf628fc2c41098deab82ac580cf149aae4" - dependencies: - boolbase "~1.0.0" - -number-is-nan@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" - -nwmatcher@^1.4.3: - version "1.4.4" - resolved "https://registry.yarnpkg.com/nwmatcher/-/nwmatcher-1.4.4.tgz#2285631f34a95f0d0395cd900c96ed39b58f346e" - -oauth-sign@~0.8.1, oauth-sign@~0.8.2: - version "0.8.2" - resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" - -object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - -object-copy@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" - dependencies: - copy-descriptor "^0.1.0" - define-property "^0.2.5" - kind-of "^3.0.3" - -object-keys@^1.0.8: - version "1.0.11" - resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.11.tgz#c54601778ad560f1142ce0e01bcca8b56d13426d" - -object-visit@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" - dependencies: - isobject "^3.0.0" - -object.getownpropertydescriptors@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz#8758c846f5b407adab0f236e0986f14b051caa16" - dependencies: - define-properties "^1.1.2" - es-abstract "^1.5.1" - -object.omit@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" - dependencies: - for-own "^0.1.4" - is-extendable "^0.1.1" - -object.pick@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" - dependencies: - isobject "^3.0.1" - -once@^1.3.0, once@^1.3.1, once@^1.3.3, once@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - dependencies: - wrappy "1" - -onetime@^1.0.0: - version "1.1.0" - resolved "http://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" - -onetime@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" - dependencies: - mimic-fn "^1.0.0" - -opener@~1.4.0: - version "1.4.3" - resolved "https://registry.yarnpkg.com/opener/-/opener-1.4.3.tgz#5c6da2c5d7e5831e8ffa3964950f8d6674ac90b8" - -optimist@0.6.x, optimist@^0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" - dependencies: - minimist "~0.0.1" - wordwrap "~0.0.2" - -optionator@^0.8.1: - version "0.8.2" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" - dependencies: - deep-is "~0.1.3" - fast-levenshtein "~2.0.4" - levn "~0.3.0" - prelude-ls "~1.1.2" - type-check "~0.3.2" - wordwrap "~1.0.0" - -ora@^0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/ora/-/ora-0.2.3.tgz#37527d220adcd53c39b73571d754156d5db657a4" - dependencies: - chalk "^1.1.1" - cli-cursor "^1.0.2" - cli-spinners "^0.1.2" - object-assign "^4.0.1" - -os-browserify@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" - -os-homedir@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" - -os-locale@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-2.1.0.tgz#42bc2900a6b5b8bd17376c8e882b65afccf24bf2" - dependencies: - execa "^0.7.0" - lcid "^1.0.0" - mem "^1.1.0" - -os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" - -osenv@^0.1.4: - version "0.1.5" - resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" - dependencies: - os-homedir "^1.0.0" - os-tmpdir "^1.0.0" - -p-cancelable@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-0.3.0.tgz#b9e123800bcebb7ac13a479be195b507b98d30fa" - -p-cancelable@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-0.4.0.tgz#bcb41d35bf6097fc4367a065b6eb84b9b124eff0" - -p-each-series@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-each-series/-/p-each-series-1.0.0.tgz#930f3d12dd1f50e7434457a22cd6f04ac6ad7f71" - dependencies: - p-reduce "^1.0.0" - -p-finally@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" - -p-is-promise@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-1.1.0.tgz#9c9456989e9f6588017b0434d56097675c3da05e" - -p-lazy@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-lazy/-/p-lazy-1.0.0.tgz#ec53c802f2ee3ac28f166cc82d0b2b02de27a835" - -p-limit@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.2.0.tgz#0e92b6bedcb59f022c13d0f1949dc82d15909f1c" - dependencies: - p-try "^1.0.0" - -p-locate@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" - dependencies: - p-limit "^1.1.0" - -p-map@^1.1.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/p-map/-/p-map-1.2.0.tgz#e4e94f311eabbc8633a1e79908165fca26241b6b" - -p-reduce@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-reduce/-/p-reduce-1.0.0.tgz#18c2b0dd936a4690a529f8231f58a0fdb6a47dfa" - -p-timeout@^1.1.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-1.2.1.tgz#5eb3b353b7fce99f101a1038880bb054ebbea386" - dependencies: - p-finally "^1.0.0" - -p-timeout@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-2.0.1.tgz#d8dd1979595d2dc0139e1fe46b8b646cb3cdf038" - dependencies: - p-finally "^1.0.0" - -p-try@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" - -pako@~1.0.5: - version "1.0.6" - resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.6.tgz#0101211baa70c4bca4a0f63f2206e97b7dfaf258" - -parallel-transform@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/parallel-transform/-/parallel-transform-1.1.0.tgz#d410f065b05da23081fcd10f28854c29bda33b06" - dependencies: - cyclist "~0.2.2" - inherits "^2.0.3" - readable-stream "^2.1.5" - -param-case@2.1.x: - version "2.1.1" - resolved "https://registry.yarnpkg.com/param-case/-/param-case-2.1.1.tgz#df94fd8cf6531ecf75e6bef9a0858fbc72be2247" - dependencies: - no-case "^2.2.0" - -parse-asn1@^5.0.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.0.tgz#37c4f9b7ed3ab65c74817b5f2480937fbf97c712" - dependencies: - asn1.js "^4.0.0" - browserify-aes "^1.0.0" - create-hash "^1.1.0" - evp_bytestokey "^1.0.0" - pbkdf2 "^3.0.3" - -parse-glob@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" - dependencies: - glob-base "^0.3.0" - is-dotfile "^1.0.0" - is-extglob "^1.0.0" - is-glob "^2.0.0" - -parse-json@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" - dependencies: - error-ex "^1.2.0" - -parse-json@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" - dependencies: - error-ex "^1.3.1" - json-parse-better-errors "^1.0.1" - -parse-passwd@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" - -parse5@4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/parse5/-/parse5-4.0.0.tgz#6d78656e3da8d78b4ec0b906f7c08ef1dfe3f608" - -pascalcase@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" - -path-browserify@0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.0.tgz#a0b870729aae214005b7d5032ec2cbbb0fb4451a" - -path-dirname@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" - -path-exists@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" - dependencies: - pinkie-promise "^2.0.0" - -path-exists@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" - -path-is-absolute@^1.0.0, path-is-absolute@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - -path-key@^2.0.0, path-key@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" - -path-parse@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1" - -path-type@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" - dependencies: - graceful-fs "^4.1.2" - pify "^2.0.0" - pinkie-promise "^2.0.0" - -path-type@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" - dependencies: - pify "^3.0.0" - -pbkdf2@^3.0.3: - version "3.0.14" - resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.14.tgz#a35e13c64799b06ce15320f459c230e68e73bade" - dependencies: - create-hash "^1.1.2" - create-hmac "^1.1.4" - ripemd160 "^2.0.1" - safe-buffer "^5.0.1" - sha.js "^2.4.8" - -performance-now@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5" - -performance-now@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" - -pify@^2.0.0, pify@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" - -pify@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" - -pinkie-promise@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" - dependencies: - pinkie "^2.0.0" - -pinkie@^2.0.0: - version "2.0.4" - resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" - -pkg-dir@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b" - dependencies: - find-up "^2.1.0" - -pn@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/pn/-/pn-1.1.0.tgz#e2f4cef0e219f463c179ab37463e4e1ecdccbafb" - -portfinder@^1.0.13: - version "1.0.13" - resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.13.tgz#bb32ecd87c27104ae6ee44b5a3ccbf0ebb1aede9" - dependencies: - async "^1.5.2" - debug "^2.2.0" - mkdirp "0.5.x" - -posix-character-classes@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" - -prelude-ls@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" - -prepend-http@^1.0.1: - version "1.0.4" - resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" - -prepend-http@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" - -preserve@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" - -prettier@^1.5.3: - version "1.11.1" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.11.1.tgz#61e43fc4cd44e68f2b0dfc2c38cd4bb0fccdcc75" - -pretty-bytes@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-4.0.2.tgz#b2bf82e7350d65c6c33aa95aaa5a4f6327f61cd9" - -pretty-error@^2.0.2: - version "2.1.1" - resolved "https://registry.yarnpkg.com/pretty-error/-/pretty-error-2.1.1.tgz#5f4f87c8f91e5ae3f3ba87ab4cf5e03b1a17f1a3" - dependencies: - renderkid "^2.0.1" - utila "~0.4" - -pretty-format@^22.4.3: - version "22.4.3" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-22.4.3.tgz#f873d780839a9c02e9664c8a082e9ee79eaac16f" - dependencies: - ansi-regex "^3.0.0" - ansi-styles "^3.2.0" - -private@^0.1.6, private@^0.1.7, private@~0.1.5: - version "0.1.8" - resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" - -process-nextick-args@^2.0.0, process-nextick-args@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" - -process@^0.11.10: - version "0.11.10" - resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" - -promise-inflight@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" - -promise@^7.1.1: - version "7.3.1" - resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf" - dependencies: - asap "~2.0.3" - -prop-types@^15.6.0: - version "15.6.1" - resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.1.tgz#36644453564255ddda391191fb3a125cbdf654ca" - dependencies: - fbjs "^0.8.16" - loose-envify "^1.3.1" - object-assign "^4.1.1" - -prr@~1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" - -pseudomap@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" - -public-encrypt@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.0.tgz#39f699f3a46560dd5ebacbca693caf7c65c18cc6" - dependencies: - bn.js "^4.1.0" - browserify-rsa "^4.0.0" - create-hash "^1.1.0" - parse-asn1 "^5.0.0" - randombytes "^2.0.1" - -pump@^2.0.0, pump@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909" - dependencies: - end-of-stream "^1.1.0" - once "^1.3.1" - -pumpify@^1.3.3: - version "1.4.0" - resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-1.4.0.tgz#80b7c5df7e24153d03f0e7ac8a05a5d068bd07fb" - dependencies: - duplexify "^3.5.3" - inherits "^2.0.3" - pump "^2.0.0" - -punycode@1.3.2: - version "1.3.2" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" - -punycode@^1.2.4, punycode@^1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" - -punycode@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.0.tgz#5f863edc89b96db09074bad7947bf09056ca4e7d" - -qs@~2.3.3: - version "2.3.3" - resolved "https://registry.yarnpkg.com/qs/-/qs-2.3.3.tgz#e9e85adbe75da0bbe4c8e0476a086290f863b404" - -qs@~6.4.0: - version "6.4.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233" - -qs@~6.5.1: - version "6.5.1" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8" - -query-string@^5.0.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/query-string/-/query-string-5.1.1.tgz#a78c012b71c17e05f2e3fa2319dd330682efb3cb" - dependencies: - decode-uri-component "^0.2.0" - object-assign "^4.1.0" - strict-uri-encode "^1.0.0" - -querystring-es3@^0.2.0: - version "0.2.1" - resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" - -querystring@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" - -randomatic@^1.1.3: - version "1.1.7" - resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.7.tgz#c7abe9cc8b87c0baa876b19fde83fd464797e38c" - dependencies: - is-number "^3.0.0" - kind-of "^4.0.0" - -randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5: - version "2.0.6" - resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.0.6.tgz#d302c522948588848a8d300c932b44c24231da80" - dependencies: - safe-buffer "^5.1.0" - -randomfill@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458" - dependencies: - randombytes "^2.0.5" - safe-buffer "^5.1.0" - -rc@^1.1.7: - version "1.2.6" - resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.6.tgz#eb18989c6d4f4f162c399f79ddd29f3835568092" - dependencies: - deep-extend "~0.4.0" - ini "~1.3.0" - minimist "^1.2.0" - strip-json-comments "~2.0.1" - -react-dom@^16.2.0: - version "16.2.0" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.2.0.tgz#69003178601c0ca19b709b33a83369fe6124c044" - dependencies: - fbjs "^0.8.16" - loose-envify "^1.1.0" - object-assign "^4.1.1" - prop-types "^15.6.0" - -react@^16.2.0: - version "16.2.0" - resolved "https://registry.yarnpkg.com/react/-/react-16.2.0.tgz#a31bd2dab89bff65d42134fa187f24d054c273ba" - dependencies: - fbjs "^0.8.16" - loose-envify "^1.1.0" - object-assign "^4.1.1" - prop-types "^15.6.0" - -read-chunk@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/read-chunk/-/read-chunk-2.1.0.tgz#6a04c0928005ed9d42e1a6ac5600e19cbc7ff655" - dependencies: - pify "^3.0.0" - safe-buffer "^5.1.1" - -read-pkg-up@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" - dependencies: - find-up "^1.0.0" - read-pkg "^1.0.0" - -read-pkg-up@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-3.0.0.tgz#3ed496685dba0f8fe118d0691dc51f4a1ff96f07" - dependencies: - find-up "^2.0.0" - read-pkg "^3.0.0" - -read-pkg@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" - dependencies: - load-json-file "^1.0.0" - normalize-package-data "^2.3.2" - path-type "^1.0.0" - -read-pkg@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389" - dependencies: - load-json-file "^4.0.0" - normalize-package-data "^2.3.2" - path-type "^3.0.0" - -"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.5: - version "2.3.5" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.5.tgz#b4f85003a938cbb6ecbce2a124fb1012bd1a838d" - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.3" - isarray "~1.0.0" - process-nextick-args "~2.0.0" - safe-buffer "~5.1.1" - string_decoder "~1.0.3" - util-deprecate "~1.0.1" - -readable-stream@1.0: - version "1.0.34" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "0.0.1" - string_decoder "~0.10.x" - -readdirp@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78" - dependencies: - graceful-fs "^4.1.2" - minimatch "^3.0.2" - readable-stream "^2.0.2" - set-immediate-shim "^1.0.1" - -realpath-native@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/realpath-native/-/realpath-native-1.0.0.tgz#7885721a83b43bd5327609f0ddecb2482305fdf0" - dependencies: - util.promisify "^1.0.0" - -recast@^0.12.5: - version "0.12.9" - resolved "https://registry.yarnpkg.com/recast/-/recast-0.12.9.tgz#e8e52bdb9691af462ccbd7c15d5a5113647a15f1" - dependencies: - ast-types "0.10.1" - core-js "^2.4.1" - esprima "~4.0.0" - private "~0.1.5" - source-map "~0.6.1" - -recast@^0.14.1: - version "0.14.7" - resolved "https://registry.yarnpkg.com/recast/-/recast-0.14.7.tgz#4f1497c2b5826d42a66e8e3c9d80c512983ff61d" - dependencies: - ast-types "0.11.3" - esprima "~4.0.0" - private "~0.1.5" - source-map "~0.6.1" - -rechoir@^0.6.2: - version "0.6.2" - resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" - dependencies: - resolve "^1.1.6" - -regenerate@^1.2.1: - version "1.3.3" - resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.3.tgz#0c336d3980553d755c39b586ae3b20aa49c82b7f" - -regenerator-runtime@^0.11.0: - version "0.11.1" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" - -regenerator-transform@^0.10.0: - version "0.10.1" - resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.10.1.tgz#1e4996837231da8b7f3cf4114d71b5691a0680dd" - dependencies: - babel-runtime "^6.18.0" - babel-types "^6.19.0" - private "^0.1.6" - -regex-cache@^0.4.2: - version "0.4.4" - resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd" - dependencies: - is-equal-shallow "^0.1.3" - -regex-not@^1.0.0, regex-not@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" - dependencies: - extend-shallow "^3.0.2" - safe-regex "^1.1.0" - -regexpu-core@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240" - dependencies: - regenerate "^1.2.1" - regjsgen "^0.2.0" - regjsparser "^0.1.4" - -regjsgen@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7" - -regjsparser@^0.1.4: - version "0.1.5" - resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c" - dependencies: - jsesc "~0.5.0" - -relateurl@0.2.x: - version "0.2.7" - resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9" - -remove-trailing-separator@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" - -renderkid@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/renderkid/-/renderkid-2.0.1.tgz#898cabfc8bede4b7b91135a3ffd323e58c0db319" - dependencies: - css-select "^1.1.0" - dom-converter "~0.1" - htmlparser2 "~3.3.0" - strip-ansi "^3.0.0" - utila "~0.3" - -repeat-element@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" - -repeat-string@^1.5.2, repeat-string@^1.6.1: - version "1.6.1" - resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" - -repeating@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" - dependencies: - is-finite "^1.0.0" - -replace-ext@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-0.0.1.tgz#29bbd92078a739f0bcce2b4ee41e837953522924" - -replace-ext@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-1.0.0.tgz#de63128373fcbf7c3ccfa4de5a480c45a67958eb" - -request-promise-core@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/request-promise-core/-/request-promise-core-1.1.1.tgz#3eee00b2c5aa83239cfb04c5700da36f81cd08b6" - dependencies: - lodash "^4.13.1" - -request-promise-native@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/request-promise-native/-/request-promise-native-1.0.5.tgz#5281770f68e0c9719e5163fd3fab482215f4fda5" - dependencies: - request-promise-core "1.1.1" - stealthy-require "^1.1.0" - tough-cookie ">=2.3.3" - -request@2.81.0: - version "2.81.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0" - dependencies: - aws-sign2 "~0.6.0" - aws4 "^1.2.1" - caseless "~0.12.0" - combined-stream "~1.0.5" - extend "~3.0.0" - forever-agent "~0.6.1" - form-data "~2.1.1" - har-validator "~4.2.1" - hawk "~3.1.3" - http-signature "~1.1.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.7" - oauth-sign "~0.8.1" - performance-now "^0.2.0" - qs "~6.4.0" - safe-buffer "^5.0.1" - stringstream "~0.0.4" - tough-cookie "~2.3.0" - tunnel-agent "^0.6.0" - uuid "^3.0.0" - -request@^2.83.0: - version "2.85.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.85.0.tgz#5a03615a47c61420b3eb99b7dba204f83603e1fa" - dependencies: - aws-sign2 "~0.7.0" - aws4 "^1.6.0" - caseless "~0.12.0" - combined-stream "~1.0.5" - extend "~3.0.1" - forever-agent "~0.6.1" - form-data "~2.3.1" - har-validator "~5.0.3" - hawk "~6.0.2" - http-signature "~1.2.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.17" - oauth-sign "~0.8.2" - performance-now "^2.1.0" - qs "~6.5.1" - safe-buffer "^5.1.1" - stringstream "~0.0.5" - tough-cookie "~2.3.3" - tunnel-agent "^0.6.0" - uuid "^3.1.0" - -require-directory@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" - -require-main-filename@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" - -requires-port@1.x.x: - version "1.0.0" - resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" - -resolve-cwd@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a" - dependencies: - resolve-from "^3.0.0" - -resolve-dir@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-1.0.1.tgz#79a40644c362be82f26effe739c9bb5382046f43" - dependencies: - expand-tilde "^2.0.0" - global-modules "^1.0.0" - -resolve-from@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" - -resolve-url@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" - -resolve@1.1.7: - version "1.1.7" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" - -resolve@^1.1.6: - version "1.6.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.6.0.tgz#0fbd21278b27b4004481c395349e7aba60a9ff5c" - dependencies: - path-parse "^1.0.5" - -responselike@1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" - dependencies: - lowercase-keys "^1.0.0" - -restore-cursor@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541" - dependencies: - exit-hook "^1.0.0" - onetime "^1.0.0" - -restore-cursor@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" - dependencies: - onetime "^2.0.0" - signal-exit "^3.0.2" - -ret@~0.1.10: - version "0.1.15" - resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" - -right-align@^0.1.1: - version "0.1.3" - resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef" - dependencies: - align-text "^0.1.1" - -rimraf@2, rimraf@^2.2.8, rimraf@^2.5.1, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2: - version "2.6.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" - dependencies: - glob "^7.0.5" - -rimraf@~2.2.6: - version "2.2.8" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.2.8.tgz#e439be2aaee327321952730f99a8929e4fc50582" - -ripemd160@^2.0.0, ripemd160@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.1.tgz#0f4584295c53a3628af7e6d79aca21ce57d1c6e7" - dependencies: - hash-base "^2.0.0" - inherits "^2.0.1" - -run-async@^2.0.0, run-async@^2.2.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" - dependencies: - is-promise "^2.1.0" - -run-queue@^1.0.0, run-queue@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/run-queue/-/run-queue-1.0.3.tgz#e848396f057d223f24386924618e25694161ec47" - dependencies: - aproba "^1.1.1" - -rx-lite-aggregates@^4.0.8: - version "4.0.8" - resolved "https://registry.yarnpkg.com/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz#753b87a89a11c95467c4ac1626c4efc4e05c67be" - dependencies: - rx-lite "*" - -rx-lite@*, rx-lite@^4.0.8: - version "4.0.8" - resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-4.0.8.tgz#0b1e11af8bc44836f04a6407e92da42467b79444" - -rxjs@^5.4.2, rxjs@^5.5.2: - version "5.5.8" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-5.5.8.tgz#b2b0809a57614ad6254c03d7446dea0d83ca3791" - dependencies: - symbol-observable "1.0.1" - -safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" - -safe-regex@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" - dependencies: - ret "~0.1.10" - -sane@^2.0.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/sane/-/sane-2.5.0.tgz#6359cd676f5efd9988b264d8ce3b827dd6b27bec" - dependencies: - anymatch "^2.0.0" - exec-sh "^0.2.0" - fb-watchman "^2.0.0" - micromatch "^3.1.4" - minimist "^1.1.1" - walker "~1.0.5" - watch "~0.18.0" - optionalDependencies: - fsevents "^1.1.1" - -sax@^1.2.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" - -schema-utils@^0.4.2, schema-utils@^0.4.5: - version "0.4.5" - resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-0.4.5.tgz#21836f0608aac17b78f9e3e24daff14a5ca13a3e" - dependencies: - ajv "^6.1.0" - ajv-keywords "^3.1.0" - -scoped-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/scoped-regex/-/scoped-regex-1.0.0.tgz#a346bb1acd4207ae70bd7c0c7ca9e566b6baddb8" - -"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.4.1, semver@^5.5.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" - -serialize-javascript@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-1.4.0.tgz#7c958514db6ac2443a8abc062dc9f7886a7f6005" - -set-blocking@^2.0.0, set-blocking@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" - -set-immediate-shim@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" - -set-value@^0.4.3: - version "0.4.3" - resolved "https://registry.yarnpkg.com/set-value/-/set-value-0.4.3.tgz#7db08f9d3d22dc7f78e53af3c3bf4666ecdfccf1" - dependencies: - extend-shallow "^2.0.1" - is-extendable "^0.1.1" - is-plain-object "^2.0.1" - to-object-path "^0.3.0" - -set-value@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.0.tgz#71ae4a88f0feefbbf52d1ea604f3fb315ebb6274" - dependencies: - extend-shallow "^2.0.1" - is-extendable "^0.1.1" - is-plain-object "^2.0.3" - split-string "^3.0.1" - -setimmediate@^1.0.4, setimmediate@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" - -sha.js@^2.4.0, sha.js@^2.4.8: - version "2.4.11" - resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" - dependencies: - inherits "^2.0.1" - safe-buffer "^5.0.1" - -shebang-command@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" - dependencies: - shebang-regex "^1.0.0" - -shebang-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" - -shelljs@^0.8.0: - version "0.8.1" - resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.1.tgz#729e038c413a2254c4078b95ed46e0397154a9f1" - dependencies: - glob "^7.0.0" - interpret "^1.0.0" - rechoir "^0.6.2" - -shellwords@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" - -signal-exit@^3.0.0, signal-exit@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" - -slash@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" - -slice-ansi@0.0.4: - version "0.0.4" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35" - -slide@^1.1.5: - version "1.1.6" - resolved "https://registry.yarnpkg.com/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707" - -snapdragon-node@^2.0.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" - dependencies: - define-property "^1.0.0" - isobject "^3.0.0" - snapdragon-util "^3.0.1" - -snapdragon-util@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" - dependencies: - kind-of "^3.2.0" - -snapdragon@^0.8.1: - version "0.8.2" - resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" - dependencies: - base "^0.11.1" - debug "^2.2.0" - define-property "^0.2.5" - extend-shallow "^2.0.1" - map-cache "^0.2.2" - source-map "^0.5.6" - source-map-resolve "^0.5.0" - use "^3.1.0" - -sntp@1.x.x: - version "1.0.9" - resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198" - dependencies: - hoek "2.x.x" - -sntp@2.x.x: - version "2.1.0" - resolved "https://registry.yarnpkg.com/sntp/-/sntp-2.1.0.tgz#2c6cec14fedc2222739caf9b5c3d85d1cc5a2cc8" - dependencies: - hoek "4.x.x" - -sort-keys@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-2.0.0.tgz#658535584861ec97d730d6cf41822e1f56684128" - dependencies: - is-plain-obj "^1.0.0" - -source-list-map@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.0.tgz#aaa47403f7b245a92fbc97ea08f250d6087ed085" - -source-map-resolve@^0.5.0: - version "0.5.1" - resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.1.tgz#7ad0f593f2281598e854df80f19aae4b92d7a11a" - dependencies: - atob "^2.0.0" - decode-uri-component "^0.2.0" - resolve-url "^0.2.1" - source-map-url "^0.4.0" - urix "^0.1.0" - -source-map-support@^0.4.15: - version "0.4.18" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f" - dependencies: - source-map "^0.5.6" - -source-map-support@^0.5.0: - version "0.5.4" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.4.tgz#54456efa89caa9270af7cd624cc2f123e51fbae8" - dependencies: - source-map "^0.6.0" - -source-map-url@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" - -source-map@0.5.x, source-map@^0.5.3, source-map@^0.5.6, source-map@^0.5.7, source-map@~0.5.1: - version "0.5.7" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" - -source-map@^0.4.4: - version "0.4.4" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" - dependencies: - amdefine ">=0.0.4" - -source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" - -spdx-correct@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.0.0.tgz#05a5b4d7153a195bc92c3c425b69f3b2a9524c82" - dependencies: - spdx-expression-parse "^3.0.0" - spdx-license-ids "^3.0.0" - -spdx-exceptions@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz#2c7ae61056c714a5b9b9b2b2af7d311ef5c78fe9" - -spdx-expression-parse@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0" - dependencies: - spdx-exceptions "^2.1.0" - spdx-license-ids "^3.0.0" - -spdx-license-ids@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz#7a7cd28470cc6d3a1cfe6d66886f6bc430d3ac87" - -split-string@^3.0.1, split-string@^3.0.2: - version "3.1.0" - resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" - dependencies: - extend-shallow "^3.0.0" - -sprintf-js@~1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" - -sshpk@^1.7.0: - version "1.14.1" - resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.14.1.tgz#130f5975eddad963f1d56f92b9ac6c51fa9f83eb" - dependencies: - asn1 "~0.2.3" - assert-plus "^1.0.0" - dashdash "^1.12.0" - getpass "^0.1.1" - optionalDependencies: - bcrypt-pbkdf "^1.0.0" - ecc-jsbn "~0.1.1" - jsbn "~0.1.0" - tweetnacl "~0.14.0" - -ssri@^5.2.4: - version "5.3.0" - resolved "https://registry.yarnpkg.com/ssri/-/ssri-5.3.0.tgz#ba3872c9c6d33a0704a7d71ff045e5ec48999d06" - dependencies: - safe-buffer "^5.1.1" - -stack-utils@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-1.0.1.tgz#d4f33ab54e8e38778b0ca5cfd3b3afb12db68620" - -static-extend@^0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" - dependencies: - define-property "^0.2.5" - object-copy "^0.1.0" - -stealthy-require@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b" - -stream-browserify@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.1.tgz#66266ee5f9bdb9940a4e4514cafb43bb71e5c9db" - dependencies: - inherits "~2.0.1" - readable-stream "^2.0.2" - -stream-each@^1.1.0: - version "1.2.2" - resolved "https://registry.yarnpkg.com/stream-each/-/stream-each-1.2.2.tgz#8e8c463f91da8991778765873fe4d960d8f616bd" - dependencies: - end-of-stream "^1.1.0" - stream-shift "^1.0.0" - -stream-http@^2.7.2: - version "2.8.1" - resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.8.1.tgz#d0441be1a457a73a733a8a7b53570bebd9ef66a4" - dependencies: - builtin-status-codes "^3.0.0" - inherits "^2.0.1" - readable-stream "^2.3.3" - to-arraybuffer "^1.0.0" - xtend "^4.0.0" - -stream-shift@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.0.tgz#d5c752825e5367e786f78e18e445ea223a155952" - -stream-to-observable@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/stream-to-observable/-/stream-to-observable-0.2.0.tgz#59d6ea393d87c2c0ddac10aa0d561bc6ba6f0e10" - dependencies: - any-observable "^0.2.0" - -strict-uri-encode@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" - -string-length@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/string-length/-/string-length-2.0.0.tgz#d40dbb686a3ace960c1cffca562bf2c45f8363ed" - dependencies: - astral-regex "^1.0.0" - strip-ansi "^4.0.0" - -string-template@~0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/string-template/-/string-template-0.2.1.tgz#42932e598a352d01fc22ec3367d9d84eec6c9add" - -string-width@^1.0.1, string-width@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" - dependencies: - code-point-at "^1.0.0" - is-fullwidth-code-point "^1.0.0" - strip-ansi "^3.0.0" - -string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" - dependencies: - is-fullwidth-code-point "^2.0.0" - strip-ansi "^4.0.0" - -string_decoder@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.0.tgz#384f322ee8a848e500effde99901bba849c5d403" - dependencies: - safe-buffer "~5.1.0" - -string_decoder@~0.10.x: - version "0.10.31" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" - -string_decoder@~1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.3.tgz#0fc67d7c141825de94282dd536bec6b9bce860ab" - dependencies: - safe-buffer "~5.1.0" - -stringstream@~0.0.4, stringstream@~0.0.5: - version "0.0.5" - resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" - -strip-ansi@^3.0.0, strip-ansi@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" - dependencies: - ansi-regex "^2.0.0" - -strip-ansi@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" - dependencies: - ansi-regex "^3.0.0" - -strip-ansi@~0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-0.1.1.tgz#39e8a98d044d150660abe4a6808acf70bb7bc991" - -strip-bom-stream@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/strip-bom-stream/-/strip-bom-stream-2.0.0.tgz#f87db5ef2613f6968aa545abfe1ec728b6a829ca" - dependencies: - first-chunk-stream "^2.0.0" - strip-bom "^2.0.0" - -strip-bom@3.0.0, strip-bom@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" - -strip-bom@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" - dependencies: - is-utf8 "^0.2.0" - -strip-eof@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" - -strip-json-comments@~2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" - -supports-color@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" - -supports-color@^3.1.2: - version "3.2.3" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6" - dependencies: - has-flag "^1.0.0" - -supports-color@^5.3.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.3.0.tgz#5b24ac15db80fa927cf5227a4a33fd3c4c7676c0" - dependencies: - has-flag "^3.0.0" - -symbol-observable@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.0.1.tgz#8340fc4702c3122df5d22288f88283f513d3fdd4" - -symbol-observable@^0.2.2: - version "0.2.4" - resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-0.2.4.tgz#95a83db26186d6af7e7a18dbd9760a2f86d08f40" - -symbol-tree@^3.2.2: - version "3.2.2" - resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.2.tgz#ae27db38f660a7ae2e1c3b7d1bc290819b8519e6" - -tapable@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.0.0.tgz#cbb639d9002eed9c6b5975eb20598d7936f1f9f2" - -tar-pack@^3.4.0: - version "3.4.1" - resolved "https://registry.yarnpkg.com/tar-pack/-/tar-pack-3.4.1.tgz#e1dbc03a9b9d3ba07e896ad027317eb679a10a1f" - dependencies: - debug "^2.2.0" - fstream "^1.0.10" - fstream-ignore "^1.0.5" - once "^1.3.3" - readable-stream "^2.1.4" - rimraf "^2.5.1" - tar "^2.2.1" - uid-number "^0.0.6" - -tar@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1" - dependencies: - block-stream "*" - fstream "^1.0.2" - inherits "2" - -temp@^0.8.1: - version "0.8.3" - resolved "https://registry.yarnpkg.com/temp/-/temp-0.8.3.tgz#e0c6bc4d26b903124410e4fed81103014dfc1f59" - dependencies: - os-tmpdir "^1.0.0" - rimraf "~2.2.6" - -test-exclude@^4.1.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-4.2.1.tgz#dfa222f03480bca69207ca728b37d74b45f724fa" - dependencies: - arrify "^1.0.1" - micromatch "^3.1.8" - object-assign "^4.1.0" - read-pkg-up "^1.0.1" - require-main-filename "^1.0.1" - -text-table@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" - -textextensions@2: - version "2.2.0" - resolved "https://registry.yarnpkg.com/textextensions/-/textextensions-2.2.0.tgz#38ac676151285b658654581987a0ce1a4490d286" - -throat@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/throat/-/throat-4.1.0.tgz#89037cbc92c56ab18926e6ba4cbb200e15672a6a" - -through2@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.3.tgz#0004569b37c7c74ba39c43f3ced78d1ad94140be" - dependencies: - readable-stream "^2.1.5" - xtend "~4.0.1" - -through@^2.3.6: - version "2.3.8" - resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" - -timed-out@^4.0.0, timed-out@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" - -timers-browserify@^2.0.4: - version "2.0.6" - resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.6.tgz#241e76927d9ca05f4d959819022f5b3664b64bae" - dependencies: - setimmediate "^1.0.4" - -tmp@^0.0.33: - version "0.0.33" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" - dependencies: - os-tmpdir "~1.0.2" - -tmpl@1.0.x: - version "1.0.4" - resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" - -to-arraybuffer@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" - -to-fast-properties@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" - -to-object-path@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" - dependencies: - kind-of "^3.0.2" - -to-regex-range@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" - dependencies: - is-number "^3.0.0" - repeat-string "^1.6.1" - -to-regex@^3.0.1, to-regex@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" - dependencies: - define-property "^2.0.2" - extend-shallow "^3.0.2" - regex-not "^1.0.2" - safe-regex "^1.1.0" - -toposort@^1.0.0: - version "1.0.6" - resolved "https://registry.yarnpkg.com/toposort/-/toposort-1.0.6.tgz#c31748e55d210effc00fdcdc7d6e68d7d7bb9cec" - -tough-cookie@>=2.3.3, tough-cookie@^2.3.3, tough-cookie@~2.3.0, tough-cookie@~2.3.3: - version "2.3.4" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.4.tgz#ec60cee38ac675063ffc97a5c18970578ee83655" - dependencies: - punycode "^1.4.1" - -tr46@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09" - dependencies: - punycode "^2.1.0" - -trim-right@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" - -tty-browserify@0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" - -tunnel-agent@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" - dependencies: - safe-buffer "^5.0.1" - -tweetnacl@^0.14.3, tweetnacl@~0.14.0: - version "0.14.5" - resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" - -type-check@~0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" - dependencies: - prelude-ls "~1.1.2" - -typedarray@^0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" - -ua-parser-js@^0.7.9: - version "0.7.17" - resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.17.tgz#e9ec5f9498b9ec910e7ae3ac626a805c4d09ecac" - -uglify-es@^3.3.4: - version "3.3.9" - resolved "https://registry.yarnpkg.com/uglify-es/-/uglify-es-3.3.9.tgz#0c1c4f0700bed8dbc124cdb304d2592ca203e677" - dependencies: - commander "~2.13.0" - source-map "~0.6.1" - -uglify-js@3.3.x: - version "3.3.16" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.3.16.tgz#23ba13efa27aa00885be7417819e8a9787f94028" - dependencies: - commander "~2.15.0" - source-map "~0.6.1" - -uglify-js@^2.6: - version "2.8.29" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.29.tgz#29c5733148057bb4e1f75df35b7a9cb72e6a59dd" - dependencies: - source-map "~0.5.1" - yargs "~3.10.0" - optionalDependencies: - uglify-to-browserify "~1.0.0" - -uglify-to-browserify@~1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7" - -uglifyjs-webpack-plugin@^1.2.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-1.2.4.tgz#5eec941b2e9b8538be0a20fc6eda25b14c7c1043" - dependencies: - cacache "^10.0.4" - find-cache-dir "^1.0.0" - schema-utils "^0.4.5" - serialize-javascript "^1.4.0" - source-map "^0.6.1" - uglify-es "^3.3.4" - webpack-sources "^1.1.0" - worker-farm "^1.5.2" - -uid-number@^0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" - -underscore@~1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.6.0.tgz#8b38b10cacdef63337b8b24e4ff86d45aea529a8" - -union-value@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4" - dependencies: - arr-union "^3.1.0" - get-value "^2.0.6" - is-extendable "^0.1.1" - set-value "^0.4.3" - -union@~0.4.3: - version "0.4.6" - resolved "https://registry.yarnpkg.com/union/-/union-0.4.6.tgz#198fbdaeba254e788b0efcb630bc11f24a2959e0" - dependencies: - qs "~2.3.3" - -unique-filename@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.0.tgz#d05f2fe4032560871f30e93cbe735eea201514f3" - dependencies: - unique-slug "^2.0.0" - -unique-slug@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.0.tgz#db6676e7c7cc0629878ff196097c78855ae9f4ab" - dependencies: - imurmurhash "^0.1.4" - -unset-value@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" - dependencies: - has-value "^0.3.1" - isobject "^3.0.0" - -untildify@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/untildify/-/untildify-3.0.2.tgz#7f1f302055b3fea0f3e81dc78eb36766cb65e3f1" - -upath@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/upath/-/upath-1.0.4.tgz#ee2321ba0a786c50973db043a50b7bcba822361d" - -upper-case@^1.1.1: - version "1.1.3" - resolved "https://registry.yarnpkg.com/upper-case/-/upper-case-1.1.3.tgz#f6b4501c2ec4cdd26ba78be7222961de77621598" - -uri-js@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-3.0.2.tgz#f90b858507f81dea4dcfbb3c4c3dbfa2b557faaa" - dependencies: - punycode "^2.1.0" - -urix@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" - -url-join@^2.0.2: - version "2.0.5" - resolved "https://registry.yarnpkg.com/url-join/-/url-join-2.0.5.tgz#5af22f18c052a000a48d7b82c5e9c2e2feeda728" - -url-parse-lax@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-1.0.0.tgz#7af8f303645e9bd79a272e7a14ac68bc0609da73" - dependencies: - prepend-http "^1.0.1" - -url-parse-lax@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c" - dependencies: - prepend-http "^2.0.0" - -url-to-options@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/url-to-options/-/url-to-options-1.0.1.tgz#1505a03a289a48cbd7a434efbaeec5055f5633a9" - -url@^0.11.0: - version "0.11.0" - resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" - dependencies: - punycode "1.3.2" - querystring "0.2.0" - -use@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/use/-/use-3.1.0.tgz#14716bf03fdfefd03040aef58d8b4b85f3a7c544" - dependencies: - kind-of "^6.0.2" - -util-deprecate@~1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - -util.promisify@1.0.0, util.promisify@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.0.tgz#440f7165a459c9a16dc145eb8e72f35687097030" - dependencies: - define-properties "^1.1.2" - object.getownpropertydescriptors "^2.0.3" - -util@0.10.3, util@^0.10.3: - version "0.10.3" - resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" - dependencies: - inherits "2.0.1" - -utila@~0.3: - version "0.3.3" - resolved "https://registry.yarnpkg.com/utila/-/utila-0.3.3.tgz#d7e8e7d7e309107092b05f8d9688824d633a4226" - -utila@~0.4: - version "0.4.0" - resolved "https://registry.yarnpkg.com/utila/-/utila-0.4.0.tgz#8a16a05d445657a3aea5eecc5b12a4fa5379772c" - -uuid@^3.0.0, uuid@^3.1.0: - version "3.2.1" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.2.1.tgz#12c528bb9d58d0b9265d9a2f6f0fe8be17ff1f14" - -v8-compile-cache@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-1.1.2.tgz#8d32e4f16974654657e676e0e467a348e89b0dc4" - -validate-npm-package-license@^3.0.1: - version "3.0.3" - resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz#81643bcbef1bdfecd4623793dc4648948ba98338" - dependencies: - spdx-correct "^3.0.0" - spdx-expression-parse "^3.0.0" - -verror@1.10.0: - version "1.10.0" - resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" - dependencies: - assert-plus "^1.0.0" - core-util-is "1.0.2" - extsprintf "^1.2.0" - -vinyl-file@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/vinyl-file/-/vinyl-file-2.0.0.tgz#a7ebf5ffbefda1b7d18d140fcb07b223efb6751a" - dependencies: - graceful-fs "^4.1.2" - pify "^2.3.0" - pinkie-promise "^2.0.0" - strip-bom "^2.0.0" - strip-bom-stream "^2.0.0" - vinyl "^1.1.0" - -vinyl@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-1.2.0.tgz#5c88036cf565e5df05558bfc911f8656df218884" - dependencies: - clone "^1.0.0" - clone-stats "^0.0.1" - replace-ext "0.0.1" - -vinyl@^2.0.1: - version "2.1.0" - resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-2.1.0.tgz#021f9c2cf951d6b939943c89eb5ee5add4fd924c" - dependencies: - clone "^2.1.1" - clone-buffer "^1.0.0" - clone-stats "^1.0.0" - cloneable-readable "^1.0.0" - remove-trailing-separator "^1.0.1" - replace-ext "^1.0.0" - -vm-browserify@0.0.4: - version "0.0.4" - resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-0.0.4.tgz#5d7ea45bbef9e4a6ff65f95438e0a87c357d5a73" - dependencies: - indexof "0.0.1" - -w3c-hr-time@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz#82ac2bff63d950ea9e3189a58a65625fedf19045" - dependencies: - browser-process-hrtime "^0.1.2" - -walker@~1.0.5: - version "1.0.7" - resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb" - dependencies: - makeerror "1.0.x" - -watch@~0.18.0: - version "0.18.0" - resolved "https://registry.yarnpkg.com/watch/-/watch-0.18.0.tgz#28095476c6df7c90c963138990c0a5423eb4b986" - dependencies: - exec-sh "^0.2.0" - minimist "^1.2.0" - -watchpack@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.5.0.tgz#231e783af830a22f8966f65c4c4bacc814072eed" - dependencies: - chokidar "^2.0.2" - graceful-fs "^4.1.2" - neo-async "^2.5.0" - -webidl-conversions@^4.0.1, webidl-conversions@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" - -webpack-addons@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/webpack-addons/-/webpack-addons-1.1.5.tgz#2b178dfe873fb6e75e40a819fa5c26e4a9bc837a" - dependencies: - jscodeshift "^0.4.0" - -webpack-cli@^2.0.13: - version "2.0.13" - resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-2.0.13.tgz#6e2bd9ef91345344737217e22e29001ad8537518" - dependencies: - chalk "^2.3.2" - cross-spawn "^6.0.5" - diff "^3.5.0" - enhanced-resolve "^4.0.0" - glob-all "^3.1.0" - global-modules "^1.0.0" - got "^8.2.0" - inquirer "^5.1.0" - interpret "^1.0.4" - jscodeshift "^0.5.0" - listr "^0.13.0" - loader-utils "^1.1.0" - lodash "^4.17.5" - log-symbols "^2.2.0" - mkdirp "^0.5.1" - p-each-series "^1.0.0" - p-lazy "^1.0.0" - prettier "^1.5.3" - resolve-cwd "^2.0.0" - supports-color "^5.3.0" - v8-compile-cache "^1.1.2" - webpack-addons "^1.1.5" - yargs "^11.0.0" - yeoman-environment "^2.0.0" - yeoman-generator "^2.0.3" - -webpack-sources@^1.0.1, webpack-sources@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.1.0.tgz#a101ebae59d6507354d71d8013950a3a8b7a5a54" - dependencies: - source-list-map "^2.0.0" - source-map "~0.6.1" - -webpack@^4.4.1: - version "4.4.1" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.4.1.tgz#b0105789890c28bfce9f392623ef5850254328a4" - dependencies: - acorn "^5.0.0" - acorn-dynamic-import "^3.0.0" - ajv "^6.1.0" - ajv-keywords "^3.1.0" - chrome-trace-event "^0.1.1" - enhanced-resolve "^4.0.0" - eslint-scope "^3.7.1" - loader-runner "^2.3.0" - loader-utils "^1.1.0" - memory-fs "~0.4.1" - micromatch "^3.1.8" - mkdirp "~0.5.0" - neo-async "^2.5.0" - node-libs-browser "^2.0.0" - schema-utils "^0.4.2" - tapable "^1.0.0" - uglifyjs-webpack-plugin "^1.2.4" - watchpack "^1.5.0" - webpack-sources "^1.0.1" - -whatwg-encoding@^1.0.1, whatwg-encoding@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.3.tgz#57c235bc8657e914d24e1a397d3c82daee0a6ba3" - dependencies: - iconv-lite "0.4.19" - -whatwg-fetch@>=0.10.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz#9c84ec2dcf68187ff00bc64e1274b442176e1c84" - -whatwg-url@^6.4.0: - version "6.4.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-6.4.0.tgz#08fdf2b9e872783a7a1f6216260a1d66cc722e08" - dependencies: - lodash.sortby "^4.7.0" - tr46 "^1.0.0" - webidl-conversions "^4.0.1" - -which-module@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" - -which@^1.2.12, which@^1.2.14, which@^1.2.9, which@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/which/-/which-1.3.0.tgz#ff04bdfc010ee547d780bec38e1ac1c2777d253a" - dependencies: - isexe "^2.0.0" - -wide-align@^1.1.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.2.tgz#571e0f1b0604636ebc0dfc21b0339bbe31341710" - dependencies: - string-width "^1.0.2" - -window-size@0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" - -wordwrap@0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" - -wordwrap@~0.0.2: - version "0.0.3" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" - -wordwrap@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" - -worker-farm@^1.5.2: - version "1.6.0" - resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.6.0.tgz#aecc405976fab5a95526180846f0dba288f3a4a0" - dependencies: - errno "~0.1.7" - -wrap-ansi@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" - dependencies: - string-width "^1.0.1" - strip-ansi "^3.0.1" - -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - -write-file-atomic@^1.2.0: - version "1.3.4" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-1.3.4.tgz#f807a4f0b1d9e913ae7a48112e6cc3af1991b45f" - dependencies: - graceful-fs "^4.1.11" - imurmurhash "^0.1.4" - slide "^1.1.5" - -write-file-atomic@^2.1.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.3.0.tgz#1ff61575c2e2a4e8e510d6fa4e243cce183999ab" - dependencies: - graceful-fs "^4.1.11" - imurmurhash "^0.1.4" - signal-exit "^3.0.2" - -ws@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/ws/-/ws-4.1.0.tgz#a979b5d7d4da68bf54efe0408967c324869a7289" - dependencies: - async-limiter "~1.0.0" - safe-buffer "~5.1.0" - -xml-char-classes@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/xml-char-classes/-/xml-char-classes-1.0.0.tgz#64657848a20ffc5df583a42ad8a277b4512bbc4d" - -xml-name-validator@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" - -xtend@^4.0.0, xtend@~4.0.0, xtend@~4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" - -y18n@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" - -y18n@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" - -yallist@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" - -yargs-parser@^8.1.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-8.1.0.tgz#f1376a33b6629a5d063782944da732631e966950" - dependencies: - camelcase "^4.1.0" - -yargs-parser@^9.0.2: - version "9.0.2" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-9.0.2.tgz#9ccf6a43460fe4ed40a9bb68f48d43b8a68cc077" - dependencies: - camelcase "^4.1.0" - -yargs@^10.0.3: - version "10.1.2" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-10.1.2.tgz#454d074c2b16a51a43e2fb7807e4f9de69ccb5c5" - dependencies: - cliui "^4.0.0" - decamelize "^1.1.1" - find-up "^2.1.0" - get-caller-file "^1.0.1" - os-locale "^2.0.0" - require-directory "^2.1.1" - require-main-filename "^1.0.1" - set-blocking "^2.0.0" - string-width "^2.0.0" - which-module "^2.0.0" - y18n "^3.2.1" - yargs-parser "^8.1.0" - -yargs@^11.0.0: - version "11.0.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-11.0.0.tgz#c052931006c5eee74610e5fc0354bedfd08a201b" - dependencies: - cliui "^4.0.0" - decamelize "^1.1.1" - find-up "^2.1.0" - get-caller-file "^1.0.1" - os-locale "^2.0.0" - require-directory "^2.1.1" - require-main-filename "^1.0.1" - set-blocking "^2.0.0" - string-width "^2.0.0" - which-module "^2.0.0" - y18n "^3.2.1" - yargs-parser "^9.0.2" - -yargs@~1.2.6: - version "1.2.6" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-1.2.6.tgz#9c7b4a82fd5d595b2bf17ab6dcc43135432fe34b" - dependencies: - minimist "^0.1.0" - -yargs@~3.10.0: - version "3.10.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1" - dependencies: - camelcase "^1.0.2" - cliui "^2.1.0" - decamelize "^1.0.0" - window-size "0.1.0" - -yeoman-environment@^2.0.0, yeoman-environment@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/yeoman-environment/-/yeoman-environment-2.0.5.tgz#84f22bafa84088971fe99ea85f654a3a3dd2b693" - dependencies: - chalk "^2.1.0" - debug "^3.1.0" - diff "^3.3.1" - escape-string-regexp "^1.0.2" - globby "^6.1.0" - grouped-queue "^0.3.3" - inquirer "^3.3.0" - is-scoped "^1.0.0" - lodash "^4.17.4" - log-symbols "^2.1.0" - mem-fs "^1.1.0" - text-table "^0.2.0" - untildify "^3.0.2" - -yeoman-generator@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/yeoman-generator/-/yeoman-generator-2.0.3.tgz#19426ed22687ffe05d31526c3f1c2cf67ba768f3" - dependencies: - async "^2.6.0" - chalk "^2.3.0" - cli-table "^0.3.1" - cross-spawn "^5.1.0" - dargs "^5.1.0" - dateformat "^3.0.2" - debug "^3.1.0" - detect-conflict "^1.0.0" - error "^7.0.2" - find-up "^2.1.0" - github-username "^4.0.0" - istextorbinary "^2.1.0" - lodash "^4.17.4" - make-dir "^1.1.0" - mem-fs-editor "^3.0.2" - minimist "^1.2.0" - pretty-bytes "^4.0.2" - read-chunk "^2.1.0" - read-pkg-up "^3.0.0" - rimraf "^2.6.2" - run-async "^2.0.0" - shelljs "^0.8.0" - text-table "^0.2.0" - through2 "^2.0.0" - yeoman-environment "^2.0.5" From 7ce0c9830dc398fe50f1b13b983437051bc9aefa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Mon, 16 Apr 2018 18:27:52 +0100 Subject: [PATCH 055/111] Fixes a few tests --- __tests__/__snapshots__/index.js.snap | 7 ++++--- .../corrupted-meta-empty/.yarn-metadata.json | 0 .../corrupted-meta-not-existing/.gitkeep | 0 .../corrupted-meta-typo/.yarn-metadata.json | 0 .../node_modules}/good/.yarn-metadata.json | 0 src/fetchers/base-fetcher.js | 14 ++++++++------ src/util/generate-pnp-map-api.tpl.js | 7 +++---- 7 files changed, 15 insertions(+), 13 deletions(-) rename __tests__/fixtures/cache/corrupted/.yarn-cache/{v1 => v2/node_modules}/corrupted-meta-empty/.yarn-metadata.json (100%) rename __tests__/fixtures/cache/corrupted/.yarn-cache/{v1 => v2/node_modules}/corrupted-meta-not-existing/.gitkeep (100%) rename __tests__/fixtures/cache/corrupted/.yarn-cache/{v1 => v2/node_modules}/corrupted-meta-typo/.yarn-metadata.json (100%) rename __tests__/fixtures/cache/corrupted/.yarn-cache/{v1 => v2/node_modules}/good/.yarn-metadata.json (100%) diff --git a/__tests__/__snapshots__/index.js.snap b/__tests__/__snapshots__/index.js.snap index c7154dd81b..51b98600de 100644 --- a/__tests__/__snapshots__/index.js.snap +++ b/__tests__/__snapshots__/index.js.snap @@ -8,11 +8,12 @@ Array [ "[3/4] Linking dependencies...", "[4/4] Building fresh packages...", "success Saved lockfile.", - "success Saved 1 new dependency.", + "success Saved 2 new dependencies.", "info Direct dependencies", - "└─ lockfile@1.0.3", + "└─ lockfile@1.0.4", "info All dependencies", - "└─ lockfile@1.0.3", + "├─ lockfile@1.0.4", + "└─ signal-exit@3.0.2", ] `; diff --git a/__tests__/fixtures/cache/corrupted/.yarn-cache/v1/corrupted-meta-empty/.yarn-metadata.json b/__tests__/fixtures/cache/corrupted/.yarn-cache/v2/node_modules/corrupted-meta-empty/.yarn-metadata.json similarity index 100% rename from __tests__/fixtures/cache/corrupted/.yarn-cache/v1/corrupted-meta-empty/.yarn-metadata.json rename to __tests__/fixtures/cache/corrupted/.yarn-cache/v2/node_modules/corrupted-meta-empty/.yarn-metadata.json diff --git a/__tests__/fixtures/cache/corrupted/.yarn-cache/v1/corrupted-meta-not-existing/.gitkeep b/__tests__/fixtures/cache/corrupted/.yarn-cache/v2/node_modules/corrupted-meta-not-existing/.gitkeep similarity index 100% rename from __tests__/fixtures/cache/corrupted/.yarn-cache/v1/corrupted-meta-not-existing/.gitkeep rename to __tests__/fixtures/cache/corrupted/.yarn-cache/v2/node_modules/corrupted-meta-not-existing/.gitkeep diff --git a/__tests__/fixtures/cache/corrupted/.yarn-cache/v1/corrupted-meta-typo/.yarn-metadata.json b/__tests__/fixtures/cache/corrupted/.yarn-cache/v2/node_modules/corrupted-meta-typo/.yarn-metadata.json similarity index 100% rename from __tests__/fixtures/cache/corrupted/.yarn-cache/v1/corrupted-meta-typo/.yarn-metadata.json rename to __tests__/fixtures/cache/corrupted/.yarn-cache/v2/node_modules/corrupted-meta-typo/.yarn-metadata.json diff --git a/__tests__/fixtures/cache/corrupted/.yarn-cache/v1/good/.yarn-metadata.json b/__tests__/fixtures/cache/corrupted/.yarn-cache/v2/node_modules/good/.yarn-metadata.json similarity index 100% rename from __tests__/fixtures/cache/corrupted/.yarn-cache/v1/good/.yarn-metadata.json rename to __tests__/fixtures/cache/corrupted/.yarn-cache/v2/node_modules/good/.yarn-metadata.json diff --git a/src/fetchers/base-fetcher.js b/src/fetchers/base-fetcher.js index ce8dca2fc8..0e6503f17a 100644 --- a/src/fetchers/base-fetcher.js +++ b/src/fetchers/base-fetcher.js @@ -71,13 +71,15 @@ export default class BaseFetcher { // calling the binary const src = pkg.bin[binName]; - // We ensure that the target is executable - await fs.chmod(`${this.dest}/${src}`, 0o755); + if (await fs.exists(`${this.dest}/${src}`)) { + // We ensure that the target is executable + await fs.chmod(`${this.dest}/${src}`, 0o755); - await makePortableProxyScript(src, dest, { - proxyBasename: binName, - pnpPackageName: pkg.name, - }); + await makePortableProxyScript(src, dest, { + proxyBasename: binName, + pnpPackageName: pkg.name, + }); + } } } diff --git a/src/util/generate-pnp-map-api.tpl.js b/src/util/generate-pnp-map-api.tpl.js index bc4946ebdf..335a319b41 100644 --- a/src/util/generate-pnp-map-api.tpl.js +++ b/src/util/generate-pnp-map-api.tpl.js @@ -463,7 +463,7 @@ if (module.parent && module.parent.id === 'internal/preload') { if (process.mainModule === module) { let buffer = ''; - let decoder = new StringDecoder.StringDecoder(); + const decoder = new StringDecoder.StringDecoder(); process.stdin.on('data', chunk => { buffer += decoder.write(chunk); @@ -479,10 +479,9 @@ if (process.mainModule === module) { try { const data = JSON.parse(line); - console.log(exports.resolveRequest(data[0], data[1])); + process.stdout.write(`${exports.resolveRequest(data[0], data[1])}\n`); } catch (error) { - console.log(error.message); - continue; + process.stdout.write(`${error.message}\n`); } } while (true); }); From 1821693810abe9214bd4e05799b13eba9dc61c7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Mon, 30 Apr 2018 23:39:24 +0100 Subject: [PATCH 056/111] Fixes snapshots --- __tests__/__snapshots__/index.js.snap | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/__tests__/__snapshots__/index.js.snap b/__tests__/__snapshots__/index.js.snap index 51b98600de..c7154dd81b 100644 --- a/__tests__/__snapshots__/index.js.snap +++ b/__tests__/__snapshots__/index.js.snap @@ -8,12 +8,11 @@ Array [ "[3/4] Linking dependencies...", "[4/4] Building fresh packages...", "success Saved lockfile.", - "success Saved 2 new dependencies.", + "success Saved 1 new dependency.", "info Direct dependencies", - "└─ lockfile@1.0.4", + "└─ lockfile@1.0.3", "info All dependencies", - "├─ lockfile@1.0.4", - "└─ signal-exit@3.0.2", + "└─ lockfile@1.0.3", ] `; From be9641a8aafae0c111bf4023f371d81e2411aca1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Wed, 25 Apr 2018 01:07:31 +0100 Subject: [PATCH 057/111] Fixes the lockfile not being written when using pnp Branch: fix-lockfile --- src/cli/commands/install.js | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/src/cli/commands/install.js b/src/cli/commands/install.js index 67610d5e30..85eecbde8d 100644 --- a/src/cli/commands/install.js +++ b/src/cli/commands/install.js @@ -664,16 +664,15 @@ export class Install { // fin! // The second condition is to make sure lockfile can be updated when running `remove` command. - if (!this.config.plugnplayEnabled) { - if ( - topLevelPatterns.length || - (await fs.exists(path.join(this.config.lockfileFolder, constants.LOCKFILE_FILENAME))) - ) { - await this.saveLockfileAndIntegrity(topLevelPatterns, workspaceLayout); - } else { - this.reporter.info(this.reporter.lang('notSavedLockfileNoDependencies')); - } + if ( + topLevelPatterns.length || + (await fs.exists(path.join(this.config.lockfileFolder, constants.LOCKFILE_FILENAME))) + ) { + await this.saveLockfileAndIntegrity(topLevelPatterns, workspaceLayout); + } else { + this.reporter.info(this.reporter.lang('notSavedLockfileNoDependencies')); } + this.maybeOutputUpdate(); this.config.requestManager.clearCache(); return flattenedTopLevelPatterns; @@ -835,13 +834,15 @@ export class Install { } // write integrity hash - await this.integrityChecker.save( - patterns, - lockfileBasedOnResolver, - this.flags, - workspaceLayout, - this.scripts.getArtifacts(), - ); + if (!this.config.plugnplayEnabled) { + await this.integrityChecker.save( + patterns, + lockfileBasedOnResolver, + this.flags, + workspaceLayout, + this.scripts.getArtifacts(), + ); + } // --no-lockfile or --pure-lockfile or --frozen-lockfile flag if (this.flags.lockfile === false || this.flags.pureLockfile || this.flags.frozenLockfile) { From 7552c6b18dd0270202258dcfee645c51cca16186 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Wed, 25 Apr 2018 01:07:59 +0100 Subject: [PATCH 058/111] Fixes the `yarn node` command being incorrectly forwarded arguments Branch: fix-yarn-node --- src/cli/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cli/index.js b/src/cli/index.js index d5f8016572..e498b97a7a 100644 --- a/src/cli/index.js +++ b/src/cli/index.js @@ -173,7 +173,7 @@ export function main({ if (command === commands.run || command === commands.create) { endArgs = ['--', ...args.splice(1)]; } else { - endArgs = ['--', ...args]; + endArgs = ['--', ...args.splice(0)]; } } else { warnAboutRunDashDash = true; From 1cb1af877a96a4861225fb14d5ebdda1f2794fed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Wed, 25 Apr 2018 01:08:33 +0100 Subject: [PATCH 059/111] Uses symlinks instead of a script for bin indirection to allow calling them directly through Node Branch: bin-symlinks --- src/fetchers/base-fetcher.js | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/fetchers/base-fetcher.js b/src/fetchers/base-fetcher.js index 0e6503f17a..94b43fbea4 100644 --- a/src/fetchers/base-fetcher.js +++ b/src/fetchers/base-fetcher.js @@ -65,21 +65,19 @@ export default class BaseFetcher { if (pkg.bin) { for (const binName of Object.keys(pkg.bin)) { - const dest = `${this.dest}/.bin`; + const binDest = `${this.dest}/.bin`; // Using any sort of absolute path here would prevent makePortableProxyScript from preserving symlinks when // calling the binary - const src = pkg.bin[binName]; + const src = path.resolve(this.dest, pkg.bin[binName]); - if (await fs.exists(`${this.dest}/${src}`)) { + if (await fs.exists(src)) { // We ensure that the target is executable - await fs.chmod(`${this.dest}/${src}`, 0o755); - - await makePortableProxyScript(src, dest, { - proxyBasename: binName, - pnpPackageName: pkg.name, - }); + await fs.chmod(src, 0o755); } + + await fs.mkdirp(binDest); + await fs.symlink(src, `${binDest}/${binName}`); } } From bb2244a08c07000231afd464e5a85fb3f18467a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Wed, 25 Apr 2018 01:09:34 +0100 Subject: [PATCH 060/111] Adds a `yarn bin ` command that returns the path of the specified bin on the disk Branch: yarn-bin-name --- src/cli/commands/bin.js | 14 +++++++------ src/cli/commands/run.js | 46 +++++++++++++++++++++++++---------------- 2 files changed, 36 insertions(+), 24 deletions(-) diff --git a/src/cli/commands/bin.js b/src/cli/commands/bin.js index 3f1db7d1ff..c8f419f35c 100644 --- a/src/cli/commands/bin.js +++ b/src/cli/commands/bin.js @@ -3,8 +3,8 @@ import type {Reporter} from '../../reporters/index.js'; import type Config from '../../config.js'; import RegistryYarn from '../../resolvers/registries/yarn-resolver.js'; +import {getBinEntries} from './run.js'; -const fs = require('fs'); const path = require('path'); export function hasWrapper(commander: Object): boolean { @@ -15,18 +15,20 @@ export function setFlags(commander: Object) { commander.description('Displays the location of the yarn bin folder.'); } -export function run(config: Config, reporter: Reporter, flags: Object, args: Array): Promise { +export async function run(config: Config, reporter: Reporter, flags: Object, args: Array): Promise { const binFolder = path.join(config.cwd, config.registries[RegistryYarn.registry].folder, '.bin'); if (args.length === 0) { reporter.log(binFolder, {force: true}); } else { + const binEntries = await getBinEntries(config); + const binName = args[0]; - const finalPath = path.normalize(`${binFolder}/${binName}`); - if (fs.existsSync(finalPath)) { - reporter.log(finalPath, {force: true}); + const binPath = binEntries.get(binName); + + if (binPath) { + reporter.log(binPath, {force: true}); } else { reporter.error(reporter.lang('packageBinaryNotFound', binName)); } } - return Promise.resolve(); } diff --git a/src/cli/commands/run.js b/src/cli/commands/run.js index 2023e5b3a9..94eb92ac69 100644 --- a/src/cli/commands/run.js +++ b/src/cli/commands/run.js @@ -24,18 +24,10 @@ function toObject(input: Map): Object { return output; } -export function setFlags(commander: Object) { - commander.description('Runs a defined package script.'); -} - -export function hasWrapper(commander: Object, args: Array): boolean { - return true; -} - -export async function run(config: Config, reporter: Reporter, flags: Object, args: Array): Promise { - const pkg = await config.readManifest(config.cwd); - +export async function getBinEntries(config: Config): Promise> { const binFolders = new Set(); + const binEntries = new Map(); + // Setup the node_modules/.bin folders for analysis for (const registry of Object.keys(registries)) { binFolders.add(path.join(config.cwd, config.registries[registry].folder, '.bin')); @@ -55,21 +47,39 @@ export async function run(config: Config, reporter: Reporter, flags: Object, arg } } - const binCommands = new Set(); - const pkgCommands = new Set(); - - const scripts: Map = new Map(); - // Build up a list of possible scripts by exploring the folders marked for analysis for (const binFolder of binFolders) { if (await fs.exists(binFolder)) { for (const name of await fs.readdir(binFolder)) { - scripts.set(name, quoteForShell(path.join(binFolder, name))); - binCommands.add(name); + binEntries.set(name, path.join(binFolder, name)); } } } + return binEntries; +} + +export function setFlags(commander: Object) { + commander.description('Runs a defined package script.'); +} + +export function hasWrapper(commander: Object, args: Array): boolean { + return true; +} + +export async function run(config: Config, reporter: Reporter, flags: Object, args: Array): Promise { + const pkg = await config.readManifest(config.cwd); + + const binCommands = new Set(); + const pkgCommands = new Set(); + + const scripts: Map = new Map(); + + for (const [name, loc] of await getBinEntries(config)) { + scripts.set(name, quoteForShell(loc)); + binCommands.add(name); + } + const pkgScripts = pkg.scripts; if (pkgScripts) { From 75eb8813d9df0925b43d339a2d322a5eb28a9f81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Wed, 25 Apr 2018 18:00:26 +0100 Subject: [PATCH 061/111] Implements an --into option to yarn node/yarn run Branch: opt-into --- src/cli/commands/node.js | 8 ++++++-- src/cli/commands/run.js | 2 +- src/cli/index.js | 11 ++++++++--- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/cli/commands/node.js b/src/cli/commands/node.js index 4f1604b88e..a759cf3153 100644 --- a/src/cli/commands/node.js +++ b/src/cli/commands/node.js @@ -6,7 +6,11 @@ import * as child from '../../util/child.js'; import * as fs from '../../util/fs.js'; import {NODE_BIN_PATH, PNP_FILENAME} from '../../constants'; -export function setFlags(commander: Object) {} +export function setFlags(commander: Object) { + commander.description('Runs Node with the same version that the one used by Yarn itself, and by default from the project root'); + commander.usage('node [--into PATH] [... args]'); + commander.option('--into ', 'Sets the cwd to the specified location'); +} export function hasWrapper(commander: Object, args: Array): boolean { return true; @@ -22,7 +26,7 @@ export async function run(config: Config, reporter: Reporter, flags: Object, arg try { await child.spawn(NODE_BIN_PATH, args, { stdio: 'inherit', - cwd: config.cwd, + cwd: flags.into || config.cwd, }); } catch (err) { throw err; diff --git a/src/cli/commands/run.js b/src/cli/commands/run.js index 94eb92ac69..ddeb68f37a 100644 --- a/src/cli/commands/run.js +++ b/src/cli/commands/run.js @@ -126,7 +126,7 @@ export async function run(config: Config, reporter: Reporter, flags: Object, arg stage, config, cmd: cmdWithArgs, - cwd: config.cwd, + cwd: flags.into || config.cwd, isInteractive: true, customShell: customShell ? String(customShell) : undefined, }); diff --git a/src/cli/index.js b/src/cli/index.js index e498b97a7a..25c77cc42b 100644 --- a/src/cli/index.js +++ b/src/cli/index.js @@ -168,13 +168,18 @@ export function main({ const PROXY_COMMANDS = new Set([`run`, `create`, `node`]); if (PROXY_COMMANDS.has(commandName)) { if (endArgs.length === 0) { + let preservedArgs = 0; // the "run" and "create" command take one argument that we want to parse as usual (the // script/package name), hence the splice(1) if (command === commands.run || command === commands.create) { - endArgs = ['--', ...args.splice(1)]; - } else { - endArgs = ['--', ...args.splice(0)]; + preservedArgs += 1; + } + // If the --into option immediately follows the command (or the script name in the "run/create" + // case), we parse them as regular options so that we can cd into them + if (args[preservedArgs] === `--into`) { + preservedArgs += 2; } + endArgs = ['--', ...args.splice(preservedArgs)]; } else { warnAboutRunDashDash = true; } From 8a413306250d458672e499d92329393bfdf50bad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Wed, 25 Apr 2018 22:06:22 +0100 Subject: [PATCH 062/111] Implements the `--pnp` option Branch: pnp-option --- src/cli/index.js | 2 ++ src/config.js | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/cli/index.js b/src/cli/index.js index 25c77cc42b..438890092a 100644 --- a/src/cli/index.js +++ b/src/cli/index.js @@ -59,6 +59,7 @@ export function main({ commander.option('--verbose', 'output verbose messages on internal operations'); commander.option('--offline', 'trigger an error if any required dependencies are not available in local cache'); commander.option('--prefer-offline', 'use network only if dependencies are not available in local cache'); + commander.option('--pnp', 'enable the Plug\'n\'Play installation'); commander.option('--strict-semver'); commander.option('--json', 'format Yarn log messages as lines of JSON (see jsonlines.org)'); commander.option('--ignore-scripts', "don't run lifecycle scripts"); @@ -481,6 +482,7 @@ export function main({ cwd, commandName, + pnp: commander.pnp, binLinks: commander.binLinks, modulesFolder: commander.modulesFolder, linkFolder: commander.linkFolder, diff --git a/src/config.js b/src/config.js index 861ed86e1e..5598d89bd3 100644 --- a/src/config.js +++ b/src/config.js @@ -325,7 +325,7 @@ export default class Config { } else { this._cacheRootFolder = String(cacheRootFolder); } - this.plugnplayEnabled = Boolean(this.getOption('plugnplay-experimental')); + this.plugnplayEnabled = opts.pnp || Boolean(this.getOption('plugnplay-experimental')); this.workspacesEnabled = this.getOption('workspaces-experimental') !== false; this.workspacesNohoistEnabled = this.getOption('workspaces-nohoist-experimental') !== false; From e3426c589df1625ba86a7e7d4c714430ac4c1292 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Mon, 30 Apr 2018 16:46:09 +0100 Subject: [PATCH 063/111] Adds new tests for checking that packages are correctly locked Branch: lock-tests --- .../pkg-tests-core/sources/utils/tests.js | 18 ++++++++++- .../pkg-tests-specs/sources/index.js | 1 + .../pkg-tests/pkg-tests-specs/sources/lock.js | 30 +++++++++++++++++++ .../pkg-tests/pkg-tests-specs/sources/pnp.js | 8 ++++- packages/pkg-tests/yarn.test.js | 2 ++ src/cli/commands/node.js | 4 ++- src/cli/index.js | 2 +- src/config.js | 1 + 8 files changed, 62 insertions(+), 4 deletions(-) create mode 100644 packages/pkg-tests/pkg-tests-specs/sources/lock.js diff --git a/packages/pkg-tests/pkg-tests-core/sources/utils/tests.js b/packages/pkg-tests/pkg-tests-core/sources/utils/tests.js index a1662eabe5..2f294ca504 100644 --- a/packages/pkg-tests/pkg-tests-core/sources/utils/tests.js +++ b/packages/pkg-tests/pkg-tests-core/sources/utils/tests.js @@ -22,6 +22,17 @@ export type PackageRunDriver = ( export type PackageDriver = any; +let whitelist = new Map(); + +exports.setPackageWhitelist = async function whitelistPackages( + packages: Map>, + fn: () => Promise, +) { + whitelist = packages; + await fn(); + whitelist = new Map(); +}; + exports.getPackageRegistry = function getPackageRegistry(): Promise { if (getPackageRegistry.promise) { return getPackageRegistry.promise; @@ -182,7 +193,12 @@ exports.startPackageServer = function startPackageServer(): Promise { return processError(res, 404, `Package not found: ${name}`); } - const versions = Array.from(packageEntry.keys()); + let versions = Array.from(packageEntry.keys()); + + const whitelistedVersions = whitelist.get(name); + if (whitelistedVersions) { + versions = versions.filter(version => whitelistedVersions.has(version)); + } const data = JSON.stringify({ name, diff --git a/packages/pkg-tests/pkg-tests-specs/sources/index.js b/packages/pkg-tests/pkg-tests-specs/sources/index.js index 21e97e174d..c2ac091cba 100644 --- a/packages/pkg-tests/pkg-tests-specs/sources/index.js +++ b/packages/pkg-tests/pkg-tests-specs/sources/index.js @@ -2,6 +2,7 @@ exports.basic = require('./basic'); exports.dragon = require('./dragon'); +exports.lock = require('./lock'); exports.pnp = require('./pnp'); exports.script = require('./script'); exports.workspace = require('./workspace'); diff --git a/packages/pkg-tests/pkg-tests-specs/sources/lock.js b/packages/pkg-tests/pkg-tests-specs/sources/lock.js new file mode 100644 index 0000000000..2c6ffc1355 --- /dev/null +++ b/packages/pkg-tests/pkg-tests-specs/sources/lock.js @@ -0,0 +1,30 @@ +/* @flow */ + +import type {PackageDriver} from 'pkg-tests-core'; + +const {fs: {writeFile, writeJson}, tests: {setPackageWhitelist}} = require('pkg-tests-core'); + +module.exports = (makeTemporaryEnv: PackageDriver) => { + describe(`Lock tests`, () => { + test( + `it should correctly lock dependencies`, + makeTemporaryEnv( + { + dependencies: {[`no-deps`]: `^1.0.0`}, + }, + async ({path, run, source}) => { + await setPackageWhitelist(new Map([[`no-deps`, new Set([`1.0.0`])]]), async () => { + await run(`install`); + }); + await setPackageWhitelist(new Map([[`no-deps`, new Set([`1.0.0`, `1.1.0`])]]), async () => { + await run(`install`, `-f`); + }); + await expect(source(`require('no-deps')`)).resolves.toMatchObject({ + name: `no-deps`, + version: `1.0.0`, + }); + }, + ), + ); + }); +}; diff --git a/packages/pkg-tests/pkg-tests-specs/sources/pnp.js b/packages/pkg-tests/pkg-tests-specs/sources/pnp.js index 20e0722468..9b81457260 100644 --- a/packages/pkg-tests/pkg-tests-specs/sources/pnp.js +++ b/packages/pkg-tests/pkg-tests-specs/sources/pnp.js @@ -1,7 +1,7 @@ const {fs: {createTemporaryFolder, writeFile, writeJson}, tests: {getPackageDirectoryPath}} = require('pkg-tests-core'); module.exports = makeTemporaryEnv => { - const {basic: basicSpecs, script: scriptSpecs, workspace: workspaceSpecs} = require('pkg-tests-specs'); + const {basic: basicSpecs, lock: lockSpecs, script: scriptSpecs, workspace: workspaceSpecs} = require('pkg-tests-specs'); describe(`Plug'n'Play`, () => { basicSpecs( @@ -10,6 +10,12 @@ module.exports = makeTemporaryEnv => { }), ); + lockSpecs( + makeTemporaryEnv.withConfig({ + plugNPlay: true, + }), + ); + scriptSpecs( makeTemporaryEnv.withConfig({ plugNPlay: true, diff --git a/packages/pkg-tests/yarn.test.js b/packages/pkg-tests/yarn.test.js index 739a7e63c2..61185ce817 100644 --- a/packages/pkg-tests/yarn.test.js +++ b/packages/pkg-tests/yarn.test.js @@ -10,6 +10,7 @@ const { const { basic: basicSpecs, dragon: dragonSpecs, + lock: lockSpecs, pnp: pnpSpecs, script: scriptSpecs, workspace: workspaceSpecs, @@ -41,6 +42,7 @@ beforeEach(async () => { }); basicSpecs(pkgDriver); +lockSpecs(pkgDriver); scriptSpecs(pkgDriver); workspaceSpecs(pkgDriver); pnpSpecs(pkgDriver); diff --git a/src/cli/commands/node.js b/src/cli/commands/node.js index a759cf3153..a8c752c1a1 100644 --- a/src/cli/commands/node.js +++ b/src/cli/commands/node.js @@ -7,7 +7,9 @@ import * as fs from '../../util/fs.js'; import {NODE_BIN_PATH, PNP_FILENAME} from '../../constants'; export function setFlags(commander: Object) { - commander.description('Runs Node with the same version that the one used by Yarn itself, and by default from the project root'); + commander.description( + 'Runs Node with the same version that the one used by Yarn itself, and by default from the project root', + ); commander.usage('node [--into PATH] [... args]'); commander.option('--into ', 'Sets the cwd to the specified location'); } diff --git a/src/cli/index.js b/src/cli/index.js index 438890092a..dc1cba62c5 100644 --- a/src/cli/index.js +++ b/src/cli/index.js @@ -59,7 +59,7 @@ export function main({ commander.option('--verbose', 'output verbose messages on internal operations'); commander.option('--offline', 'trigger an error if any required dependencies are not available in local cache'); commander.option('--prefer-offline', 'use network only if dependencies are not available in local cache'); - commander.option('--pnp', 'enable the Plug\'n\'Play installation'); + commander.option('--pnp', "enable the Plug'n'Play installation"); commander.option('--strict-semver'); commander.option('--json', 'format Yarn log messages as lines of JSON (see jsonlines.org)'); commander.option('--ignore-scripts', "don't run lifecycle scripts"); diff --git a/src/config.js b/src/config.js index 5598d89bd3..897cb6c6bb 100644 --- a/src/config.js +++ b/src/config.js @@ -47,6 +47,7 @@ export type ConfigOptions = { childConcurrency?: number, networkTimeout?: number, nonInteractive?: boolean, + pnp?: boolean, // Loosely compare semver for invalid cases like "0.01.0" looseSemver?: ?boolean, From 666de0feb912d0234b594534f1031b6ebf164aff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Tue, 1 May 2018 08:18:50 -0700 Subject: [PATCH 064/111] Bugfixes This diff ships with two fixes: - Fixes calling a pnp script from a non-pnp scripts - Fixes relative requires from binaries It also adds tests for all those cases Branch: bugfixes --- .../bin-with-relative-require.js | 5 ++ .../has-bin-entries-1.0.0/package.json | 3 +- .../packages/has-bin-entries-1.0.0/secret.js | 1 + .../pkg-tests-specs/sources/basic.js | 2 +- .../pkg-tests/pkg-tests-specs/sources/pnp.js | 90 +++++++++---------- .../pkg-tests-specs/sources/script.js | 16 +++- packages/pkg-tests/yarn.test.js | 2 + src/util/generate-pnp-map-api.tpl.js | 38 ++++++-- 8 files changed, 104 insertions(+), 53 deletions(-) create mode 100644 packages/pkg-tests/pkg-tests-fixtures/packages/has-bin-entries-1.0.0/bin-with-relative-require.js create mode 100644 packages/pkg-tests/pkg-tests-fixtures/packages/has-bin-entries-1.0.0/secret.js diff --git a/packages/pkg-tests/pkg-tests-fixtures/packages/has-bin-entries-1.0.0/bin-with-relative-require.js b/packages/pkg-tests/pkg-tests-fixtures/packages/has-bin-entries-1.0.0/bin-with-relative-require.js new file mode 100644 index 0000000000..3edc61061a --- /dev/null +++ b/packages/pkg-tests/pkg-tests-fixtures/packages/has-bin-entries-1.0.0/bin-with-relative-require.js @@ -0,0 +1,5 @@ +#!/usr/bin/env node + +const secret = require('./secret'); + +console.log(secret); diff --git a/packages/pkg-tests/pkg-tests-fixtures/packages/has-bin-entries-1.0.0/package.json b/packages/pkg-tests/pkg-tests-fixtures/packages/has-bin-entries-1.0.0/package.json index b45b064d28..a83f4d2903 100644 --- a/packages/pkg-tests/pkg-tests-fixtures/packages/has-bin-entries-1.0.0/package.json +++ b/packages/pkg-tests/pkg-tests-fixtures/packages/has-bin-entries-1.0.0/package.json @@ -3,7 +3,8 @@ "version": "1.0.0", "bin": { "has-bin-entries": "./bin.js", - "has-bin-entries-with-require": "./bin-with-require.js" + "has-bin-entries-with-require": "./bin-with-require.js", + "has-bin-entries-with-relative-require": "./bin-with-relative-require.js" }, "dependencies": { "no-deps": "1.0.0" diff --git a/packages/pkg-tests/pkg-tests-fixtures/packages/has-bin-entries-1.0.0/secret.js b/packages/pkg-tests/pkg-tests-fixtures/packages/has-bin-entries-1.0.0/secret.js new file mode 100644 index 0000000000..888cae37af --- /dev/null +++ b/packages/pkg-tests/pkg-tests-fixtures/packages/has-bin-entries-1.0.0/secret.js @@ -0,0 +1 @@ +module.exports = 42; diff --git a/packages/pkg-tests/pkg-tests-specs/sources/basic.js b/packages/pkg-tests/pkg-tests-specs/sources/basic.js index d8b8da3d6f..05bfb4d1a7 100644 --- a/packages/pkg-tests/pkg-tests-specs/sources/basic.js +++ b/packages/pkg-tests/pkg-tests-specs/sources/basic.js @@ -3,7 +3,7 @@ import type {PackageDriver} from 'pkg-tests-core'; const { - fs: {writeFile, writeJson}, + fs: {createTemporaryFolder, writeFile, writeJson}, tests: {getPackageArchivePath, getPackageHttpArchivePath, getPackageDirectoryPath}, } = require('pkg-tests-core'); diff --git a/packages/pkg-tests/pkg-tests-specs/sources/pnp.js b/packages/pkg-tests/pkg-tests-specs/sources/pnp.js index 9b81457260..3c53e02695 100644 --- a/packages/pkg-tests/pkg-tests-specs/sources/pnp.js +++ b/packages/pkg-tests/pkg-tests-specs/sources/pnp.js @@ -374,56 +374,36 @@ module.exports = makeTemporaryEnv => { }, ), ); - }); - - test( - `it should load the index.js file when loading from a folder`, - makeTemporaryEnv({}, {plugNPlay: true}, async ({path, run, source}) => { - await run(`install`); - - const tmp = await createTemporaryFolder(); - - await writeFile(`${tmp}/folder/index.js`, `module.exports = 42;`); - - await expect(source(`require("${tmp}/folder")`)).resolves.toEqual(42); - }), - ); - test( - `it should resolve the .js extension`, - makeTemporaryEnv({}, {plugNPlay: true}, async ({path, run, source}) => { - await run(`install`); + test( + `it should load the index.js file when loading from a folder`, + makeTemporaryEnv({}, {plugNPlay: true}, async ({path, run, source}) => { + await run(`install`); - const tmp = await createTemporaryFolder(); + const tmp = await createTemporaryFolder(); - await writeFile(`${tmp}/file.js`, `module.exports = 42;`); + await writeFile(`${tmp}/folder/index.js`, `module.exports = 42;`); - await expect(source(`require("${tmp}/file")`)).resolves.toEqual(42); - }), - ); + await expect(source(`require("${tmp}/folder")`)).resolves.toEqual(42); + }), + ); - test( - `it should use the regular Node resolution when requiring files outside of the pnp install tree`, - makeTemporaryEnv({}, {plugNPlay: true}, async ({path, run, source}) => { - await run(`install`); + test( + `it should resolve the .js extension`, + makeTemporaryEnv({}, {plugNPlay: true}, async ({path, run, source}) => { + await run(`install`); - const tmp = await createTemporaryFolder(); + const tmp = await createTemporaryFolder(); - await writeFile(`${tmp}/node_modules/dep/index.js`, `module.exports = 42;`); - await writeFile(`${tmp}/index.js`, `require('dep')`); + await writeFile(`${tmp}/file.js`, `module.exports = 42;`); - await source(`require("${tmp}/index.js")`); - }), - ); + await expect(source(`require("${tmp}/file")`)).resolves.toEqual(42); + }), + ); - test( - `it should not setup pnp when calling a script outside of the install tree`, - makeTemporaryEnv( - {}, - { - plugNPlay: true, - }, - async ({path, run, source}) => { + test( + `it should use the regular Node resolution when requiring files outside of the pnp install tree`, + makeTemporaryEnv({}, {plugNPlay: true}, async ({path, run, source}) => { await run(`install`); const tmp = await createTemporaryFolder(); @@ -431,8 +411,28 @@ module.exports = makeTemporaryEnv => { await writeFile(`${tmp}/node_modules/dep/index.js`, `module.exports = 42;`); await writeFile(`${tmp}/index.js`, `require('dep')`); - await run(`node`, `${tmp}/index.js`); - }, - ), - ); + await source(`require("${tmp}/index.js")`); + }), + ); + + test( + `it should allow scripts outside of the dependency tree to require files within the dependency tree`, + makeTemporaryEnv( + { dependencies: { [`no-deps`]: `1.0.0` } }, + { + plugNPlay: true, + }, + async ({path, run, source}) => { + await run(`install`); + + const tmp = await createTemporaryFolder(); + + await writeFile(`${tmp}/index.js`, `require(process.argv[2])`); + await writeFile(`${path}/index.js`, `require('no-deps')`); + + await run(`node`, `${tmp}/index.js`, `${path}/index.js`); + }, + ), + ); + }); }; diff --git a/packages/pkg-tests/pkg-tests-specs/sources/script.js b/packages/pkg-tests/pkg-tests-specs/sources/script.js index 3c726b47f6..0826e15cb7 100644 --- a/packages/pkg-tests/pkg-tests-specs/sources/script.js +++ b/packages/pkg-tests/pkg-tests-specs/sources/script.js @@ -81,7 +81,7 @@ module.exports = (makeTemporaryEnv: PackageDriver) => { ); test( - `it should allow dependencies binaries to require their own dependencies`, + `it should allow dependency binaries to require their own dependencies`, makeTemporaryEnv( { dependencies: { @@ -97,5 +97,19 @@ module.exports = (makeTemporaryEnv: PackageDriver) => { }, ), ); + + test( + `it should allow dependency binaries to require relative paths`, + makeTemporaryEnv( + { dependencies: { [`has-bin-entries`]: `1.0.0` } }, + async ({path, run, source}) => { + await run(`install`); + + await expect(run(`run`, `has-bin-entries-with-relative-require`)).resolves.toMatchObject({ + stdout: `42\n`, + }); + }, + ), + ); }); }; diff --git a/packages/pkg-tests/yarn.test.js b/packages/pkg-tests/yarn.test.js index 61185ce817..e43c3347fb 100644 --- a/packages/pkg-tests/yarn.test.js +++ b/packages/pkg-tests/yarn.test.js @@ -28,6 +28,8 @@ const pkgDriver = generatePkgDriver({ env: { [`NPM_CONFIG_REGISTRY`]: registryUrl, [`YARN_SILENT`]: `1`, + [`YARN_PROXY`]: ``, + [`YARN_HTTPS_PROXY`]: ``, [`YARN_PLUGNPLAY_EXPERIMENTAL`]: plugNPlay ? `true` : `false`, [`PATH`]: `${path}/bin${delimiter}${process.env.PATH}`, }, diff --git a/src/util/generate-pnp-map-api.tpl.js b/src/util/generate-pnp-map-api.tpl.js index 335a319b41..d4dcf211a5 100644 --- a/src/util/generate-pnp-map-api.tpl.js +++ b/src/util/generate-pnp-map-api.tpl.js @@ -25,6 +25,19 @@ const moduleCache = new Map(); /** * Ensures that the returned locator isn't a blacklisted one. + * + * Blacklisted packages are packages that cannot be used because their dependencies cannot be deduced. This only + * happens with peer dependencies, which effectively have different sets of dependencies depending on their parents. + * + * In order to deambiguate those different sets of dependencies, the Yarn implementation of PnP will generate a + * symlink for each combination of // it will find, and will + * blacklist the target of those symlinks. By doing this, we ensure that files loaded through a specific path + * will always have the same set of dependencies, provided the symlinks are correctly preserved. + * + * Unfortunately, some tools do not preserve them, and when it happens PnP isn't able anymore to deduce the set of + * dependencies based on the path of the file that makes the require calls. But since we've blacklisted those paths, + * we're able to print a more helpful error message that points out that a third-party package is doing something + * incompatible! */ // eslint-disable-next-line no-unused-vars @@ -199,6 +212,10 @@ exports.getPackageInformation = function getPackageInformation({name, reference} * - The owning package locator * - The owning package path in the dependency tree * - The file cache key + * + * Note that it is extremely important that the `issuer` path ends with a forward slash if the issuer is to be + * treated as a folder (ie. "/tmp/foo/" rather than "/tmp/foo" if "foo" is a directory). Otherwise relative + * imports won't be computed correctly (they'll get resolved relative to "/tmp/" instead of "/tmp/foo/"). */ exports.resolveRequest = function resolveRequest(request, issuer) { @@ -211,12 +228,26 @@ exports.resolveRequest = function resolveRequest(request, issuer) { let filesystemPath; // If the request is a relative or absolute path, we just return it normalized + // + // Note that if the very last component of the issuer is a symlink to a file, we then need to resolve it, but + // only it, and not the rest of the path! This allows us to support the case of bin symlinks, where a symlink + // in "/.../pkg-name/.bin/bin-name" will point somewhere else (like "/../pkg-name/index.js"). In such a case, + // we want relative requires to be resolved relative to "/../pkg-name/" rather than "/../pkg-name/.bin/". + // + // Also note that the reason we must use readlink on the last component (instead of realpath on the whole path) + // is that we must preserve the other symlinks, in particular those used by pnp to deambiguate packages using + // peer dependencies. For example, "/../.pnp/local/pnp-01234569/.bin/bin-name" should see its relative requires + // be resolved relative to "/../.pnp/local/pnp-0123456789/" rather than "/../pkg-with-peers/", because otherwise + // we would lose the information that would tell us what are the dependencies of pkg-with-peers relative to its + // ancestors. const dependencyNameMatch = request.match(pathRegExp); if (!dependencyNameMatch) { if (issuer.match(isDirRegExp)) { filesystemPath = path.normalize(path.resolve(issuer, request)); + } else if (fs.lstatSync(issuer).isSymbolicLink()) { + filesystemPath = path.normalize(path.resolve(path.dirname(issuer), path.dirname(fs.readlinkSync(issuer)), request)); } else { filesystemPath = path.normalize(path.resolve(path.dirname(issuer), request)); } @@ -454,11 +485,8 @@ if (module.parent && module.parent.id === 'internal/preload') { const issuerPath = process.argv[1] || process.cwd() + path.sep; const issuerLocator = exports.findPackageLocator(issuerPath); - // We don't want to boot pnp if the script being run isn't part of the project we've installed - if (issuerLocator) { - exports.setup(); - exports.setupCompatibilityLayer(); - } + exports.setup(); + exports.setupCompatibilityLayer(); } if (process.mainModule === module) { From 2f82e75b8024ba7b25b148ce5d40c57717a3f61d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Tue, 1 May 2018 11:41:40 -0700 Subject: [PATCH 065/111] Fixes workspace registration Branch: workspace-registration-fix --- .../pkg-tests-specs/sources/dragon.js | 68 ++++++++++++++++++- .../pkg-tests/pkg-tests-specs/sources/pnp.js | 9 ++- .../pkg-tests-specs/sources/script.js | 15 ++-- src/util/generate-pnp-map.js | 25 ++++--- 4 files changed, 92 insertions(+), 25 deletions(-) diff --git a/packages/pkg-tests/pkg-tests-specs/sources/dragon.js b/packages/pkg-tests/pkg-tests-specs/sources/dragon.js index 8c67b07dae..e68a926d13 100644 --- a/packages/pkg-tests/pkg-tests-specs/sources/dragon.js +++ b/packages/pkg-tests/pkg-tests-specs/sources/dragon.js @@ -2,6 +2,8 @@ import type {PackageDriver} from 'pkg-tests-core'; +const {fs: {writeFile, writeJson}} = require('pkg-tests-core'); + // Here be dragons. The biggest and baddest tests, that just can't be described in a single line of summary. Because // of this, they each must be clearly documented and explained. // @@ -19,7 +21,7 @@ module.exports = (makeTemporaryEnv: PackageDriver) => { [`dragon-test-1-e`]: `1.0.0`, }, }, - async ({path, run}) => { + async ({path, run, source}) => { // This test assumes the following: // // . -> D@1.0.0 -> C@1.0.0 -> B@1.0.0 -> A@1.0.0 @@ -54,5 +56,69 @@ module.exports = (makeTemporaryEnv: PackageDriver) => { }, ), ); + + describe( + `it should pass the dragon test 2`, + makeTemporaryEnv( + { + private: true, + workspaces: [`dragon-test-2-a`, `dragon-test-2-b`], + dependencies: { + [`dragon-test-2-a`]: `1.0.0`, + }, + }, + { + plugNPlay: true, + }, + async ({path, run, source}) => { + // This test assumes the following: + // + // . -> A@workspace -> B@workspace -> no-deps@* (peer dep) + // -> no-deps@1.0.0 + // + // In this situation, the implementation might register the workspaces one by + // one, going through all their dependencies before moving to the next one. + // Because the workspace B is also a dependency of the workspace A, it will be + // traversed a first time as a dependency of A, and then a second time as a + // workspace. + // + // A problem is when B also has peer dependencies, like in the setup described + // above. In this case, the Yarn implementation of PnP needs to generate a virtual + // package for B (in order to deambiguate the dependencies), and register it while + // processing A. Then later, when iterating over B, it is possible that the + // workspace registration overwrites the previously registered virtual dependency, + // making it unavailable whilst still being referenced in the dependencies of A. + // + // This test ensures that A can always require B. + + await writeJson(`${path}/dragon-test-2-a/package.json`, { + name: `dragon-test-2-a`, + version: `1.0.0`, + dependencies: { + [`dragon-test-2-b`]: `1.0.0`, + [`no-deps`]: `1.0.0`, + }, + }); + + await writeJson(`${path}/dragon-test-2-b/package.json`, { + name: `dragon-test-2-b`, + version: `1.0.0`, + peerDependencies: { + [`no-deps`]: `*`, + }, + }); + + await writeFile(`${path}/dragon-test-2-a/index.js`, `module.exports = require('dragon-test-2-b')`); + await writeFile(`${path}/dragon-test-2-b/index.js`, `module.exports = require('no-deps')`); + + await run(`install`); + + await expect(source(`require("dragon-test-2-a")`)).resolves.toMatchObject({ + name: `no-deps`, + version: `1.0.0`, + }); + }, + ), + ); }); }; diff --git a/packages/pkg-tests/pkg-tests-specs/sources/pnp.js b/packages/pkg-tests/pkg-tests-specs/sources/pnp.js index 3c53e02695..d4b4b63849 100644 --- a/packages/pkg-tests/pkg-tests-specs/sources/pnp.js +++ b/packages/pkg-tests/pkg-tests-specs/sources/pnp.js @@ -1,7 +1,12 @@ const {fs: {createTemporaryFolder, writeFile, writeJson}, tests: {getPackageDirectoryPath}} = require('pkg-tests-core'); module.exports = makeTemporaryEnv => { - const {basic: basicSpecs, lock: lockSpecs, script: scriptSpecs, workspace: workspaceSpecs} = require('pkg-tests-specs'); + const { + basic: basicSpecs, + lock: lockSpecs, + script: scriptSpecs, + workspace: workspaceSpecs, + } = require('pkg-tests-specs'); describe(`Plug'n'Play`, () => { basicSpecs( @@ -418,7 +423,7 @@ module.exports = makeTemporaryEnv => { test( `it should allow scripts outside of the dependency tree to require files within the dependency tree`, makeTemporaryEnv( - { dependencies: { [`no-deps`]: `1.0.0` } }, + {dependencies: {[`no-deps`]: `1.0.0`}}, { plugNPlay: true, }, diff --git a/packages/pkg-tests/pkg-tests-specs/sources/script.js b/packages/pkg-tests/pkg-tests-specs/sources/script.js index 0826e15cb7..1feec3652e 100644 --- a/packages/pkg-tests/pkg-tests-specs/sources/script.js +++ b/packages/pkg-tests/pkg-tests-specs/sources/script.js @@ -100,16 +100,13 @@ module.exports = (makeTemporaryEnv: PackageDriver) => { test( `it should allow dependency binaries to require relative paths`, - makeTemporaryEnv( - { dependencies: { [`has-bin-entries`]: `1.0.0` } }, - async ({path, run, source}) => { - await run(`install`); + makeTemporaryEnv({dependencies: {[`has-bin-entries`]: `1.0.0`}}, async ({path, run, source}) => { + await run(`install`); - await expect(run(`run`, `has-bin-entries-with-relative-require`)).resolves.toMatchObject({ - stdout: `42\n`, - }); - }, - ), + await expect(run(`run`, `has-bin-entries-with-relative-require`)).resolves.toMatchObject({ + stdout: `42\n`, + }); + }), ); }); }; diff --git a/src/util/generate-pnp-map.js b/src/util/generate-pnp-map.js index 363ace0e5e..822df8bfd3 100644 --- a/src/util/generate-pnp-map.js +++ b/src/util/generate-pnp-map.js @@ -293,19 +293,18 @@ async function getPackageInformationStores( const loc = ref.location; invariant(loc, `Workspaces should have a location`); - packageInformationStores.set( - name, - new Map([ - [ - pkg.version, - { - packageMainEntry: pkg.main, - packageLocation: ensureTrailingSlash(await fs.realpath(loc)), - packageDependencies: await visit(ref.dependencies, [name, pkg.version]), - }, - ], - ]), - ); + let packageInformationStore = packageInformationStores.get(name); + + if (!packageInformationStore) { + packageInformationStore = new Map(); + packageInformationStores.set(name, packageInformationStore); + } + + packageInformationStore.set(pkg.version, { + packageMainEntry: pkg.main, + packageLocation: ensureTrailingSlash(await fs.realpath(loc)), + packageDependencies: await visit(ref.dependencies, [name, pkg.version]) + }); } } From 44941066451110cf020f2d0a688f19b1cfd6ed46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Thu, 3 May 2018 16:11:12 -0700 Subject: [PATCH 066/111] Uses --enable-pnp (alias --pnp) and --disable-pnp Branch: instalconfig-pnp --- .../pkg-tests/pkg-tests-specs/sources/pnp.js | 61 ++++++++++++++++++- src/cli/commands/add.js | 52 ++++++++-------- src/cli/commands/install.js | 41 ++++++++++++- src/cli/index.js | 6 +- src/config.js | 21 ++++++- src/types.js | 4 ++ src/util/generate-pnp-map-api.tpl.js | 7 +-- src/util/generate-pnp-map.js | 2 +- 8 files changed, 157 insertions(+), 37 deletions(-) diff --git a/packages/pkg-tests/pkg-tests-specs/sources/pnp.js b/packages/pkg-tests/pkg-tests-specs/sources/pnp.js index d4b4b63849..3fae00656b 100644 --- a/packages/pkg-tests/pkg-tests-specs/sources/pnp.js +++ b/packages/pkg-tests/pkg-tests-specs/sources/pnp.js @@ -1,4 +1,9 @@ -const {fs: {createTemporaryFolder, writeFile, writeJson}, tests: {getPackageDirectoryPath}} = require('pkg-tests-core'); +const fs = require('fs-extra'); + +const { + fs: {createTemporaryFolder, readJson, writeFile, writeJson}, + tests: {getPackageDirectoryPath}, +} = require('pkg-tests-core'); module.exports = makeTemporaryEnv => { const { @@ -439,5 +444,59 @@ module.exports = makeTemporaryEnv => { }, ), ); + + test( + `it should update the installConfig.pnp field of the package.json when installing with --enable-pnp`, + makeTemporaryEnv({}, async ({path, run, source}) => { + await run(`install`, `--enable-pnp`); + + await expect(readJson(`${path}/package.json`)).resolves.toMatchObject({ + installConfig: {pnp: true}, + }); + }), + ); + + test( + `it should install dependencies using pnp when the installConfig.pnp field is set to true`, + makeTemporaryEnv( + { + dependencies: {[`no-deps`]: `1.0.0`}, + installConfig: {pnp: true}, + }, + async ({path, run, source}) => { + await run(`install`); + + expect(fs.existsSync(`${path}/.pnp.js`)).toEqual(true); + }, + ), + ); + + test( + `it should update the installConfig.pnp field of the package.json when installing with --disable-pnp`, + makeTemporaryEnv( + { + installConfig: {pnp: true}, + }, + async ({path, run, source}) => { + await run(`install`, `--disable-pnp`); + + await expect(readJson(`${path}/package.json`)).resolves.not.toHaveProperty('installConfig.pnp'); + }, + ), + ); + + test( + `it should not remove other fields than installConfig.pnp when using --disable-pnp`, + makeTemporaryEnv( + { + installConfig: {pnp: true, foo: true}, + }, + async ({path, run, source}) => { + await run(`install`, `--disable-pnp`); + + await expect(readJson(`${path}/package.json`)).resolves.toHaveProperty('installConfig.foo', true); + }, + ), + ); }); }; diff --git a/src/cli/commands/add.js b/src/cli/commands/add.js index 78631ba8fe..347af7f4c2 100644 --- a/src/cli/commands/add.js +++ b/src/cli/commands/add.js @@ -1,9 +1,10 @@ /* @flow */ +import type {RegistryNames} from '../../registries/index.js'; import type {Reporter} from '../../reporters/index.js'; import type {InstallCwdRequest} from './install.js'; import type {DependencyRequestPatterns, Manifest} from '../../types.js'; -import type Config from '../../config.js'; +import type Config, {RootManifests} from '../../config.js'; import type {ListOptions} from './list.js'; import Lockfile from '../../lockfile'; import {normalizePattern} from '../../util/normalize-pattern.js'; @@ -180,10 +181,32 @@ export class Add extends Install { this.addedPatterns = []; const patterns = await Install.prototype.init.call(this); await this.maybeOutputSaveTree(patterns); - await this.savePackages(); return patterns; } + async applyChanges(manifests: RootManifests): Promise { + await Install.prototype.applyChanges.call(this, manifests); + + // fill rootPatternsToOrigin without `excludePatterns` + await Install.prototype.fetchRequestFromCwd.call(this); + + this._iterateAddedPackages((pattern, registry, dependencyType, pkgName, version) => { + // add it to manifest + const {object} = manifests[registry]; + + object[dependencyType] = object[dependencyType] || {}; + object[dependencyType][pkgName] = version; + if ( + SILENCE_DEPENDENCY_TYPE_WARNINGS.indexOf(this.config.commandName) === -1 && + dependencyType !== this.flagToOrigin + ) { + this.reporter.warn(this.reporter.lang('moduleAlreadyInManifest', pkgName, dependencyType, this.flagToOrigin)); + } + }); + + return true; + } + /** * Description */ @@ -234,31 +257,10 @@ export class Add extends Install { * Save added packages to manifest if any of the --save flags were used. */ - async savePackages(): Promise { - // fill rootPatternsToOrigin without `excludePatterns` - await Install.prototype.fetchRequestFromCwd.call(this); - // // 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; - if ( - SILENCE_DEPENDENCY_TYPE_WARNINGS.indexOf(this.config.commandName) === -1 && - dependencyType !== this.flagToOrigin - ) { - this.reporter.warn(this.reporter.lang('moduleAlreadyInManifest', pkgName, dependencyType, this.flagToOrigin)); - } - }); - - await this.config.saveRootManifests(manifests); - } + async savePackages(): Promise {} _iterateAddedPackages( - f: (pattern: string, registry: string, dependencyType: string, pkgName: string, version: string) => void, + f: (pattern: string, registry: RegistryNames, dependencyType: string, pkgName: string, version: string) => void, ) { const patternOrigins = Object.keys(this.rootPatternsToOrigin); diff --git a/src/cli/commands/install.js b/src/cli/commands/install.js index 85eecbde8d..856fe04071 100644 --- a/src/cli/commands/install.js +++ b/src/cli/commands/install.js @@ -4,7 +4,7 @@ import type {InstallationMethod} from '../../util/yarn-version.js'; import type {Reporter} from '../../reporters/index.js'; import type {ReporterSelectOption} from '../../reporters/types.js'; import type {Manifest, DependencyRequestPatterns} from '../../types.js'; -import type Config from '../../config.js'; +import type Config, {RootManifests} from '../../config.js'; import type {RegistryNames} from '../../registries/index.js'; import type {LockfileObject} from '../../lockfile'; import {callThroughHook} from '../../util/hooks.js'; @@ -673,11 +673,50 @@ export class Install { this.reporter.info(this.reporter.lang('notSavedLockfileNoDependencies')); } + await this.persistChanges(); + this.maybeOutputUpdate(); this.config.requestManager.clearCache(); return flattenedTopLevelPatterns; } + async persistChanges(): Promise { + // get all the different registry manifests in this folder + const manifests = await this.config.getRootManifests(); + + if (await this.applyChanges(manifests)) { + await this.config.saveRootManifests(manifests); + } + } + + applyChanges(manifests: RootManifests): Promise { + let hasChanged = false; + + if (!this.config.plugnplayByEnv) { + for (const registry of Object.keys(manifests)) { + const {object} = manifests[registry]; + + if (typeof object.installConfig !== 'object') { + object.installConfig = {}; + } + + if (this.config.plugnplayEnabled && object.installConfig.pnp !== true) { + object.installConfig.pnp = true; + hasChanged = true; + } else if (!this.config.plugnplayEnabled && typeof object.installConfig.pnp !== 'undefined') { + delete object.installConfig.pnp; + hasChanged = true; + } + + if (Object.keys(object.installConfig).length === 0) { + delete object.installConfig; + } + } + } + + return Promise.resolve(hasChanged); + } + /** * Check if we should run the cleaning step. */ diff --git a/src/cli/index.js b/src/cli/index.js index dc1cba62c5..e9fb771bcc 100644 --- a/src/cli/index.js +++ b/src/cli/index.js @@ -59,7 +59,8 @@ export function main({ commander.option('--verbose', 'output verbose messages on internal operations'); commander.option('--offline', 'trigger an error if any required dependencies are not available in local cache'); commander.option('--prefer-offline', 'use network only if dependencies are not available in local cache'); - commander.option('--pnp', "enable the Plug'n'Play installation"); + commander.option('--enable-pnp, --pnp', "enable the Plug'n'Play installation"); + commander.option('--disable-pnp', "disable the Plug'n'Play installation"); commander.option('--strict-semver'); commander.option('--json', 'format Yarn log messages as lines of JSON (see jsonlines.org)'); commander.option('--ignore-scripts', "don't run lifecycle scripts"); @@ -482,7 +483,8 @@ export function main({ cwd, commandName, - pnp: commander.pnp, + enablePnp: commander.pnp, + disablePnp: commander.disablePnp, binLinks: commander.binLinks, modulesFolder: commander.modulesFolder, linkFolder: commander.linkFolder, diff --git a/src/config.js b/src/config.js index 897cb6c6bb..5379a8e085 100644 --- a/src/config.js +++ b/src/config.js @@ -47,7 +47,8 @@ export type ConfigOptions = { childConcurrency?: number, networkTimeout?: number, nonInteractive?: boolean, - pnp?: boolean, + enablePnp?: boolean, + disablePnp?: boolean, // Loosely compare semver for invalid cases like "0.01.0" looseSemver?: ?boolean, @@ -69,7 +70,7 @@ type PackageMetadata = { package: Manifest, }; -type RootManifests = { +export type RootManifests = { [registryName: RegistryNames]: { loc: string, indent: ?string, @@ -158,6 +159,7 @@ export default class Config { nonInteractive: boolean; + plugnplayByEnv: boolean; plugnplayEnabled: boolean; workspacesEnabled: boolean; @@ -326,7 +328,20 @@ export default class Config { } else { this._cacheRootFolder = String(cacheRootFolder); } - this.plugnplayEnabled = opts.pnp || Boolean(this.getOption('plugnplay-experimental')); + + const manifest = await this.maybeReadManifest(this.cwd); + + this.plugnplayByEnv = !opts.enablePnp && !opts.disablePnp; + + if (this.plugnplayByEnv) { + if (manifest && manifest.installConfig && manifest.installConfig.pnp) { + this.plugnplayEnabled = !!manifest.installConfig.pnp; + } else { + this.plugnplayEnabled = Boolean(this.getOption('plugnplay-experimental')); + } + } else { + this.plugnplayEnabled = !!opts.enablePnp; + } this.workspacesEnabled = this.getOption('workspaces-experimental') !== false; this.workspacesNohoistEnabled = this.getOption('workspaces-nohoist-experimental') !== false; diff --git a/src/types.js b/src/types.js index 6252b89ae8..abbc5e450b 100644 --- a/src/types.js +++ b/src/types.js @@ -132,6 +132,10 @@ export type Manifest = { bundleDependencies?: Array, bundledDependencies?: Array, + installConfig?: { + pnp?: boolean, + }, + deprecated?: string, files?: Array, main?: string, diff --git a/src/util/generate-pnp-map-api.tpl.js b/src/util/generate-pnp-map-api.tpl.js index d4dcf211a5..14501ceeeb 100644 --- a/src/util/generate-pnp-map-api.tpl.js +++ b/src/util/generate-pnp-map-api.tpl.js @@ -247,7 +247,9 @@ exports.resolveRequest = function resolveRequest(request, issuer) { if (issuer.match(isDirRegExp)) { filesystemPath = path.normalize(path.resolve(issuer, request)); } else if (fs.lstatSync(issuer).isSymbolicLink()) { - filesystemPath = path.normalize(path.resolve(path.dirname(issuer), path.dirname(fs.readlinkSync(issuer)), request)); + filesystemPath = path.normalize( + path.resolve(path.dirname(issuer), path.dirname(fs.readlinkSync(issuer)), request), + ); } else { filesystemPath = path.normalize(path.resolve(path.dirname(issuer), request)); } @@ -482,9 +484,6 @@ exports.setupCompatibilityLayer = () => { }; if (module.parent && module.parent.id === 'internal/preload') { - const issuerPath = process.argv[1] || process.cwd() + path.sep; - const issuerLocator = exports.findPackageLocator(issuerPath); - exports.setup(); exports.setupCompatibilityLayer(); } diff --git a/src/util/generate-pnp-map.js b/src/util/generate-pnp-map.js index 822df8bfd3..7b7c184eb1 100644 --- a/src/util/generate-pnp-map.js +++ b/src/util/generate-pnp-map.js @@ -303,7 +303,7 @@ async function getPackageInformationStores( packageInformationStore.set(pkg.version, { packageMainEntry: pkg.main, packageLocation: ensureTrailingSlash(await fs.realpath(loc)), - packageDependencies: await visit(ref.dependencies, [name, pkg.version]) + packageDependencies: await visit(ref.dependencies, [name, pkg.version]), }); } } From 4ba007312a97f35e160c2cce452518b6a16a0e9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Wed, 9 May 2018 10:41:55 -0700 Subject: [PATCH 067/111] Adds the issuer into the error messages when requesting a package one shouldn't have access to. Branch: via-issuer --- src/util/generate-pnp-map-api.tpl.js | 53 +++++++++++++++++++++------- 1 file changed, 40 insertions(+), 13 deletions(-) diff --git a/src/util/generate-pnp-map-api.tpl.js b/src/util/generate-pnp-map-api.tpl.js index 14501ceeeb..570d1f42ca 100644 --- a/src/util/generate-pnp-map-api.tpl.js +++ b/src/util/generate-pnp-map-api.tpl.js @@ -23,6 +23,16 @@ const blacklistedLocator = {name: NaN, reference: NaN}; const moduleShims = new Map(); const moduleCache = new Map(); +/** + * Simple helper function that assign an error code to an error, so that it can more easily be caught and used + * by third-parties. + */ + +function makeError(code, message, data = {}) { + const error = new Error(message); + return Object.assign(error, {code, data}); +} + /** * Ensures that the returned locator isn't a blacklisted one. * @@ -43,7 +53,8 @@ const moduleCache = new Map(); // eslint-disable-next-line no-unused-vars function blacklistCheck(locator) { if (locator === blacklistedLocator) { - throw new Error( + throw makeError( + `BLACKLISTED`, [ `A package has been resolved through a blacklisted path - this is usually caused by one of your tool calling`, `"realpath" on the return value of "require.resolve". Since the returned values use symlinks to disambiguate`, @@ -80,7 +91,8 @@ function getPackageInformationSafe(packageLocator) { const packageInformation = exports.getPackageInformation(packageLocator); if (!packageInformation) { - throw new Error( + throw makeError( + `INTERNAL`, `Couldn't find a matching entry in the dependency tree for the specified parent (this is probably an internal error)`, ); } @@ -290,24 +302,33 @@ exports.resolveRequest = function resolveRequest(request, issuer) { if (!dependencyReference) { if (dependencyReference === null) { if (issuerLocator === topLevelLocator) { - throw new Error( + throw makeError( + `MISSING_PEER_DEPENDENCY`, `You seem to be requiring a peer dependency ("${dependencyName}"), but it is not installed (which might be because you're the top-level package)`, + {request, issuer, dependencyName}, ); } else { - throw new Error( + throw makeError( + `MISSING_PEER_DEPENDENCY`, `Package "${issuerLocator.name}@${issuerLocator.reference}" is trying to access a peer dependency ("${dependencyName}") that should be provided by its direct ancestor but isn't`, + {request, issuer, issuerLocator: Object.assign({}, issuerLocator), dependencyName}, ); } } else { if (issuerLocator === topLevelLocator) { - throw new Error( - `You cannot require a package ("${dependencyName}") that is not declared in your dependencies`, + throw makeError( + `UNDECLARED_DEPENDENCY`, + `You cannot require a package ("${dependencyName}") that is not declared in your dependencies (via "${issuer}")`, + {request, issuer, dependencyName}, ); } else { - throw new Error( - `Package ${issuerLocator.name}@${issuerLocator.reference} is trying to require package ${dependencyName} (via "${request}") without it being listed in its dependencies (${Array.from( - issuerInformation.packageDependencies.keys(), - ).join(`, `)})`, + const candidates = Array.from(issuerInformation.packageDependencies.keys()); + throw makeError( + `UNDECLARED_DEPENDENCY`, + `Package "${issuerLocator.name}@${issuerLocator.reference}" (via "${issuer}") is trying to require the package "${dependencyName}" (via "${request}") without it being listed in its dependencies (${candidates.join( + `, `, + )})`, + {request, issuer, issuerLocator: Object.assign({}, issuerLocator), dependencyName, candidates}, ); } } @@ -320,8 +341,10 @@ exports.resolveRequest = function resolveRequest(request, issuer) { const dependencyLocation = dependencyInformation.packageLocation; if (!dependencyLocation) { - throw new Error( - `Package "${dependencyLocator.name}@${dependencyLocator.reference}" is a valid dependency, but hasn't been installed and thus cannot be required`, + throw makeError( + `MISSING_DEPENDENCY`, + `Package "${dependencyLocator.name}@${dependencyLocator.reference}" is a valid dependency, but hasn't been installed and thus cannot be required (it might be caused if you install a partial tree, such as on production environments)`, + {request, issuer, dependencyLocator: Object.assign({}, dependencyLocator)}, ); } @@ -341,7 +364,11 @@ exports.resolveRequest = function resolveRequest(request, issuer) { if (qualifiedFilesystemPath) { return path.normalize(qualifiedFilesystemPath); } else { - throw new Error(`Couldn't find a suitable Node resolution for path "${filesystemPath}"`); + throw makeError( + `QUALIFIED_PATH_RESOLUTION_FAILED`, + `Couldn't find a suitable Node resolution for path "${filesystemPath}"`, + {request, issuer, filesystemPath}, + ); } }; From e447dc98370f781810af99081a441931158b3543 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Fri, 11 May 2018 04:56:51 -0700 Subject: [PATCH 068/111] Implements extendedQualifiedPathResolution Branch: extended-qualified-path-resolution --- src/util/generate-pnp-map-api.tpl.js | 128 +++++++++++++++++---------- 1 file changed, 79 insertions(+), 49 deletions(-) diff --git a/src/util/generate-pnp-map-api.tpl.js b/src/util/generate-pnp-map-api.tpl.js index 570d1f42ca..9c5cbaec04 100644 --- a/src/util/generate-pnp-map-api.tpl.js +++ b/src/util/generate-pnp-map-api.tpl.js @@ -8,7 +8,7 @@ const Module = require('module'); const path = require('path'); const StringDecoder = require('string_decoder'); -const builtinModules = Module.builtinModules || Object.keys(process.binding('natives')); +const builtinModules = new Set(Module.builtinModules || Object.keys(process.binding('natives'))); const originalLoader = Module._load; const originalFindPath = Module._findPath; @@ -104,19 +104,19 @@ function getPackageInformationSafe(packageLocator) { * Implements the node resolution for folder access and extension selection */ -function applyNodeExtensionResolution(filesystemPath) { +function applyNodeExtensionResolution(unqualifiedPath, {extensions}) { // We use this "infinite while" so that we can restart the process as long as we hit package folders while (true) { let stat; try { - stat = fs.statSync(filesystemPath); + stat = fs.statSync(unqualifiedPath); } catch (error) {} // If the file exists and is a file, we can stop right there if (stat && !stat.isDirectory()) { - return filesystemPath; + return unqualifiedPath; } // If the file is a directory, we must check if it contains a package.json with a "main" entry @@ -125,52 +125,50 @@ function applyNodeExtensionResolution(filesystemPath) { let pkgJson; try { - pkgJson = JSON.parse(fs.readFileSync(`${filesystemPath}/package.json`, 'utf-8')); + pkgJson = JSON.parse(fs.readFileSync(`${unqualifiedPath}/package.json`, 'utf-8')); } catch (error) {} - let nextFilesystemPath; + let nextUnqualifiedPath; if (pkgJson && pkgJson.main) { - nextFilesystemPath = path.resolve(filesystemPath, pkgJson.main); + nextUnqualifiedPath = path.resolve(unqualifiedPath, pkgJson.main); } // If the "main" field changed the path, we start again from this new location - if (nextFilesystemPath && nextFilesystemPath !== filesystemPath) { - filesystemPath = nextFilesystemPath; + if (nextUnqualifiedPath && nextUnqualifiedPath !== unqualifiedPath) { + unqualifiedPath = nextUnqualifiedPath; continue; } } // Otherwise we check if we find a file that match one of the supported extensions - const extensions = Object.keys(Module._extensions); - - const qualifiedFile = extensions + const qualifiedPath = extensions .map(extension => { - return `${filesystemPath}${extension}`; + return `${unqualifiedPath}${extension}`; }) .find(candidateFile => { return fs.existsSync(candidateFile); }); - if (qualifiedFile) { - return qualifiedFile; + if (qualifiedPath) { + return qualifiedPath; } // Otherwise, we check if the path is a folder - in such a case, we try to use its index if (stat && stat.isDirectory()) { - const indexFile = extensions + const indexPath = extensions .map(extension => { - return `${filesystemPath}/index${extension}`; + return `${unqualifiedPath}/index${extension}`; }) .find(candidateFile => { return fs.existsSync(candidateFile); }); - if (indexFile) { - return indexFile; + if (indexPath) { + return indexPath; } } @@ -216,28 +214,25 @@ exports.getPackageInformation = function getPackageInformation({name, reference} }; /** - * Transforms a request (what's typically passed as argument to the require function) into a location on the - * filesystem, amongst other data. - * - * It also returns the following information: - * - * - The owning package locator - * - The owning package path in the dependency tree - * - The file cache key + * Transforms a request (what's typically passed as argument to the require function) into an unqualified path. + * This path is called "unqualified" because it only changes the package name to the package location on the disk, + * which means that the end result still cannot be directly accessed (for example, it doesn't try to resolve the + * file extension, or to resolve directories to their "index.js" content). Use the "resolveUnqualified" function + * to convert them to fully-qualified paths, or just use "resolveRequest" that do both operations in one go. * * Note that it is extremely important that the `issuer` path ends with a forward slash if the issuer is to be * treated as a folder (ie. "/tmp/foo/" rather than "/tmp/foo" if "foo" is a directory). Otherwise relative * imports won't be computed correctly (they'll get resolved relative to "/tmp/" instead of "/tmp/foo/"). */ -exports.resolveRequest = function resolveRequest(request, issuer) { +exports.resolveToUnqualified = function resolveToUnqualified(request, issuer) { // Bailout if the request is a native module - if (builtinModules.indexOf(request) !== -1) { + if (builtinModules.has(request)) { return request; } - let filesystemPath; + let unqualifiedPath; // If the request is a relative or absolute path, we just return it normalized // @@ -257,13 +252,13 @@ exports.resolveRequest = function resolveRequest(request, issuer) { if (!dependencyNameMatch) { if (issuer.match(isDirRegExp)) { - filesystemPath = path.normalize(path.resolve(issuer, request)); + unqualifiedPath = path.normalize(path.resolve(issuer, request)); } else if (fs.lstatSync(issuer).isSymbolicLink()) { - filesystemPath = path.normalize( + unqualifiedPath = path.normalize( path.resolve(path.dirname(issuer), path.dirname(fs.readlinkSync(issuer)), request), ); } else { - filesystemPath = path.normalize(path.resolve(path.dirname(issuer), request)); + unqualifiedPath = path.normalize(path.resolve(path.dirname(issuer), request)); } } @@ -351,36 +346,71 @@ exports.resolveRequest = function resolveRequest(request, issuer) { // Now that we know which package we should resolve to, we only have to find out the file location if (subPath) { - filesystemPath = path.resolve(dependencyLocation, subPath); // slice(1) to strip the leading '/' + unqualifiedPath = path.resolve(dependencyLocation, subPath); } else { - filesystemPath = dependencyLocation; + unqualifiedPath = dependencyLocation; } } - // Try to resolve the filesystem according to the Node rules (directory -> index, optional .js extensions, etc) + return path.normalize(unqualifiedPath); +}; + +/** + * Transforms an unqualified path into a qualified path by using the Node resolution algorithm (which automatically + * appends ".js" / ".json", and transforms directory accesses into "index.js"). + */ + +exports.resolveUnqualified = function resolveUnqualified(unqualifiedPath, {extensions = Object.keys(Module._extensions)} = {}) { + if (builtinModules.has(unqualifiedPath)) { + return unqualifiedPath; + } - const qualifiedFilesystemPath = applyNodeExtensionResolution(filesystemPath); + let qualifiedPath = applyNodeExtensionResolution(unqualifiedPath, {extensions}); - if (qualifiedFilesystemPath) { - return path.normalize(qualifiedFilesystemPath); + if (qualifiedPath) { + return path.normalize(qualifiedPath); } else { throw makeError( `QUALIFIED_PATH_RESOLUTION_FAILED`, - `Couldn't find a suitable Node resolution for path "${filesystemPath}"`, - {request, issuer, filesystemPath}, + `Couldn't find a suitable Node resolution for unqualified path "${unqualifiedPath}"`, + {unqualifiedPath}, ); } }; /** - * Setups the hook into the Node environment + * Transforms a request into a qualified fully path. + * + * Note that it is extremely important that the `issuer` path ends with a forward slash if the issuer is to be + * treated as a folder (ie. "/tmp/foo/" rather than "/tmp/foo" if "foo" is a directory). Otherwise relative + * imports won't be computed correctly (they'll get resolved relative to "/tmp/" instead of "/tmp/foo/"). + */ + +exports.resolveRequest = function resolveRequest(request, issuer) { + let unqualifiedPath = exports.resolveToUnqualified(request, issuer); + + try { + return exports.resolveUnqualified(unqualifiedPath); + } catch (error) { + if (error.code === 'QUALIFIED_PATH_RESOLUTION_FAILED') { + Object.assign(error.data, {request, issuer}); + } + throw error; + } +}; + +/** + * Setups the hook into the Node environment. + * + * From this point on, any call to `require()` will go through the "resolveRequest" function, and the result will + * be used as path of the file to load. */ exports.setup = function setup() { Module._load = function(request, parent, isMain) { // Builtins are managed by the regular Node loader - if (builtinModules.indexOf(request) !== -1) { + if (builtinModules.has(request)) { return originalLoader.call(this, request, parent, isMain); } @@ -394,11 +424,11 @@ exports.setup = function setup() { // Request `Module._resolveFilename` (ie. `resolveRequest`) to tell us which file we should load - const filesystemPath = Module._resolveFilename(request, parent, isMain); + const modulePath = Module._resolveFilename(request, parent, isMain); // Check if the module has already been created for the given file - const cacheEntry = moduleCache.get(filesystemPath); + const cacheEntry = moduleCache.get(modulePath); if (cacheEntry) { return cacheEntry.exports; @@ -406,8 +436,8 @@ exports.setup = function setup() { // Create a new module and store it into the cache - const module = new Module(filesystemPath, parent); - moduleCache.set(filesystemPath, module); + const module = new Module(modulePath, parent); + moduleCache.set(modulePath, module); // The main module is exposed as global variable @@ -421,11 +451,11 @@ exports.setup = function setup() { let hasThrown = true; try { - module.load(filesystemPath); + module.load(modulePath); hasThrown = false; } finally { if (hasThrown) { - moduleCache.delete(filesystemPath); + moduleCache.delete(modulePath); } } From 355efd1adbcba239acb49bb9389d9d5ed6378e30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Wed, 30 May 2018 00:34:21 +0100 Subject: [PATCH 069/111] Changes the return of the pnp daemon to return json data --- src/util/generate-pnp-map-api.tpl.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/util/generate-pnp-map-api.tpl.js b/src/util/generate-pnp-map-api.tpl.js index 9c5cbaec04..b705e9346b 100644 --- a/src/util/generate-pnp-map-api.tpl.js +++ b/src/util/generate-pnp-map-api.tpl.js @@ -563,9 +563,9 @@ if (process.mainModule === module) { try { const data = JSON.parse(line); - process.stdout.write(`${exports.resolveRequest(data[0], data[1])}\n`); + process.stdout.write(`${JSON.stringify([null, exports.resolveRequest(data[0], data[1])])}\n`); } catch (error) { - process.stdout.write(`${error.message}\n`); + process.stdout.write(`${JSON.stringify([error.message, null])}\n`); } } while (true); }); From c2cc8cbc4af14561cf08f17a319091e5c5e0e8d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Wed, 30 May 2018 07:51:19 -0700 Subject: [PATCH 070/111] Implements custom shebangs for the pnp file --- .../pkg-tests/pkg-tests-specs/sources/pnp.js | 76 ++++++++++++++++++- packages/pkg-tests/yarn.test.js | 3 +- src/config.js | 3 + src/util/generate-pnp-map-api.tpl.js | 69 ++++++++++++----- src/util/generate-pnp-map.js | 4 +- 5 files changed, 132 insertions(+), 23 deletions(-) diff --git a/packages/pkg-tests/pkg-tests-specs/sources/pnp.js b/packages/pkg-tests/pkg-tests-specs/sources/pnp.js index 3fae00656b..d640bb3b0b 100644 --- a/packages/pkg-tests/pkg-tests-specs/sources/pnp.js +++ b/packages/pkg-tests/pkg-tests-specs/sources/pnp.js @@ -1,7 +1,8 @@ +const cp = require('child_process'); const fs = require('fs-extra'); const { - fs: {createTemporaryFolder, readJson, writeFile, writeJson}, + fs: {createTemporaryFolder, readFile, readJson, writeFile, writeJson}, tests: {getPackageDirectoryPath}, } = require('pkg-tests-core'); @@ -498,5 +499,78 @@ module.exports = makeTemporaryEnv => { }, ), ); + + test( + `it should generate a file that can be used as an executable to resolve a request (valid request)`, + makeTemporaryEnv( + { + dependencies: { + [`no-deps`]: `1.0.0`, + }, + }, + { + plugNPlay: true, + }, + async ({path, run, source}) => { + await run(`install`); + + expect(fs.statSync(`${path}/.pnp.js`).mode & 0o111).toEqual(0o111); + + const result = JSON.parse(cp.execFileSync(`${path}/.pnp.js`, [`no-deps`, `${path}/`], {encoding: `utf-8`})); + + expect(result[0]).toEqual(null); + expect(typeof result[1]).toEqual(`string`); + + expect(require(result[1])).toMatchObject({ + name: `no-deps`, + version: `1.0.0`, + }); + }, + ), + ); + + test( + `it should generate a file that can be used as an executable to resolve a request (invalid request)`, + makeTemporaryEnv( + { + dependencies: { + [`no-deps`]: `1.0.0`, + }, + }, + { + plugNPlay: true, + }, + async ({path, run, source}) => { + await run(`install`); + + expect(fs.statSync(`${path}/.pnp.js`).mode & 0o111).toEqual(0o111); + + const result = JSON.parse( + cp.execFileSync(`${path}/.pnp.js`, [`doesnt-exists`, `${path}/`], {encoding: `utf-8`}), + ); + + expect(typeof result[0].code).toEqual(`string`); + expect(typeof result[0].message).toEqual(`string`); + + expect(result[1]).toEqual(null); + }, + ), + ); + + test( + `it should generate a file with a custom shebang if configured as such`, + makeTemporaryEnv( + {}, + { + plugNPlay: true, + plugnplayShebang: `foo`, + }, + async ({path, run, source}) => { + await run(`install`); + + expect(await readFile(`${path}/.pnp.js`, `utf-8`)).toMatch(/^#!foo\n/); + }, + ), + ); }); }; diff --git a/packages/pkg-tests/yarn.test.js b/packages/pkg-tests/yarn.test.js index e43c3347fb..f535f4df15 100644 --- a/packages/pkg-tests/yarn.test.js +++ b/packages/pkg-tests/yarn.test.js @@ -17,7 +17,7 @@ const { } = require(`pkg-tests-specs`); const pkgDriver = generatePkgDriver({ - runDriver: (path, [command, ...args], {registryUrl, plugNPlay}) => { + runDriver: (path, [command, ...args], {registryUrl, plugNPlay, plugnplayShebang}) => { let extraArgs = []; if (command === 'install') { @@ -31,6 +31,7 @@ const pkgDriver = generatePkgDriver({ [`YARN_PROXY`]: ``, [`YARN_HTTPS_PROXY`]: ``, [`YARN_PLUGNPLAY_EXPERIMENTAL`]: plugNPlay ? `true` : `false`, + [`YARN_PLUGNPLAY_SHEBANG`]: plugnplayShebang || ``, [`PATH`]: `${path}/bin${delimiter}${process.env.PATH}`, }, cwd: path, diff --git a/src/config.js b/src/config.js index 5379a8e085..a1e22f937a 100644 --- a/src/config.js +++ b/src/config.js @@ -161,6 +161,7 @@ export default class Config { plugnplayByEnv: boolean; plugnplayEnabled: boolean; + plugnplayShebang: ?string; workspacesEnabled: boolean; workspacesNohoistEnabled: boolean; @@ -343,6 +344,8 @@ export default class Config { this.plugnplayEnabled = !!opts.enablePnp; } + this.plugnplayShebang = this.getOption('plugnplay-shebang') || '/usr/bin/env node'; + this.workspacesEnabled = this.getOption('workspaces-experimental') !== false; this.workspacesNohoistEnabled = this.getOption('workspaces-nohoist-experimental') !== false; diff --git a/src/util/generate-pnp-map-api.tpl.js b/src/util/generate-pnp-map-api.tpl.js index b705e9346b..390d9e56b7 100644 --- a/src/util/generate-pnp-map-api.tpl.js +++ b/src/util/generate-pnp-map-api.tpl.js @@ -1,4 +1,4 @@ -#!/usr/bin/env node +#!$$SHEBANG /* eslint-disable max-len, flowtype/require-valid-file-annotation, flowtype/require-return-type */ /* global packageInformationStores, $$SETUP_STATIC_TABLES */ @@ -546,27 +546,56 @@ if (module.parent && module.parent.id === 'internal/preload') { } if (process.mainModule === module) { - let buffer = ''; - const decoder = new StringDecoder.StringDecoder(); + let reportError = (code, message, data) => { + process.stdout.write(`${JSON.stringify([{code, message, data}, null])}\n`); + }; - process.stdin.on('data', chunk => { - buffer += decoder.write(chunk); + let reportSuccess = resolution => { + process.stdout.write(`${JSON.stringify([null, resolution])}\n`) + }; - do { - const index = buffer.indexOf('\n'); - if (index === -1) { - break; - } + let processResolution = (request, issuer) => { + try { + reportSuccess(exports.resolveRequest(request, issuer)); + } catch (error) { + reportError(error.code, error.message, error.data); + } + }; - const line = buffer.slice(0, index); - buffer = buffer.slice(index + 1); + let processRequest = data => { + try { + let [request, issuer] = JSON.parse(data); + processResolution(request, issuer); + } catch (error) { + reportError(`INVALID_JSON`, error.message, error.data); + } + }; - try { - const data = JSON.parse(line); - process.stdout.write(`${JSON.stringify([null, exports.resolveRequest(data[0], data[1])])}\n`); - } catch (error) { - process.stdout.write(`${JSON.stringify([error.message, null])}\n`); - } - } while (true); - }); + if (process.argv.length > 2) { + if (process.argv.length !== 4) { + process.stderr.write(`Usage: ${process.argv[0]} ${process.argv[1]} \n`); + process.exitCode = 64; /* EX_USAGE */ + } else { + processResolution(process.argv[2], process.argv[3]); + } + } else { + let buffer = ''; + const decoder = new StringDecoder.StringDecoder(); + + process.stdin.on('data', chunk => { + buffer += decoder.write(chunk); + + do { + const index = buffer.indexOf('\n'); + if (index === -1) { + break; + } + + const line = buffer.slice(0, index); + buffer = buffer.slice(index + 1); + + processRequest(line); + } while (true); + }); + } } diff --git a/src/util/generate-pnp-map.js b/src/util/generate-pnp-map.js index 7b7c184eb1..61f752402e 100644 --- a/src/util/generate-pnp-map.js +++ b/src/util/generate-pnp-map.js @@ -339,5 +339,7 @@ export async function generatePnpMap( const setupStaticTables = generateMaps(packageInformationStores, blacklistedLocations) + generateFindPackageLocator(packageInformationStores); - return pnpApi.replace(/\$\$SETUP_STATIC_TABLES\(\);/, setupStaticTables); + return pnpApi + .replace(/\$\$SHEBANG/, config.plugnplayShebang) + .replace(/\$\$SETUP_STATIC_TABLES\(\);/, setupStaticTables); } From 51830770ce241bcbf3e5ddd99873d307aec60d7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Thu, 31 May 2018 09:11:19 -0700 Subject: [PATCH 071/111] Changes the return of the pnp-exposed functions to return null with builtins --- .../pkg-tests/pkg-tests-specs/sources/pnp.js | 24 +++++++++++ src/config.js | 2 +- src/util/generate-pnp-map-api.tpl.js | 42 +++++++++---------- 3 files changed, 45 insertions(+), 23 deletions(-) diff --git a/packages/pkg-tests/pkg-tests-specs/sources/pnp.js b/packages/pkg-tests/pkg-tests-specs/sources/pnp.js index d640bb3b0b..90ba31a4f0 100644 --- a/packages/pkg-tests/pkg-tests-specs/sources/pnp.js +++ b/packages/pkg-tests/pkg-tests-specs/sources/pnp.js @@ -529,6 +529,30 @@ module.exports = makeTemporaryEnv => { ), ); + test( + `it should generate a file that can be used as an executable to resolve a request (builtin request)`, + makeTemporaryEnv( + { + dependencies: { + [`no-deps`]: `1.0.0`, + }, + }, + { + plugNPlay: true, + }, + async ({path, run, source}) => { + await run(`install`); + + expect(fs.statSync(`${path}/.pnp.js`).mode & 0o111).toEqual(0o111); + + const result = JSON.parse(cp.execFileSync(`${path}/.pnp.js`, [`fs`, `${path}/`], {encoding: `utf-8`})); + + expect(result[0]).toEqual(null); + expect(result[1]).toEqual(null); + }, + ), + ); + test( `it should generate a file that can be used as an executable to resolve a request (invalid request)`, makeTemporaryEnv( diff --git a/src/config.js b/src/config.js index a1e22f937a..c58514fb05 100644 --- a/src/config.js +++ b/src/config.js @@ -344,7 +344,7 @@ export default class Config { this.plugnplayEnabled = !!opts.enablePnp; } - this.plugnplayShebang = this.getOption('plugnplay-shebang') || '/usr/bin/env node'; + this.plugnplayShebang = String(this.getOption('plugnplay-shebang')) || '/usr/bin/env node'; this.workspacesEnabled = this.getOption('workspaces-experimental') !== false; this.workspacesNohoistEnabled = this.getOption('workspaces-nohoist-experimental') !== false; diff --git a/src/util/generate-pnp-map-api.tpl.js b/src/util/generate-pnp-map-api.tpl.js index 390d9e56b7..749c3fc321 100644 --- a/src/util/generate-pnp-map-api.tpl.js +++ b/src/util/generate-pnp-map-api.tpl.js @@ -229,7 +229,7 @@ exports.resolveToUnqualified = function resolveToUnqualified(request, issuer) { // Bailout if the request is a native module if (builtinModules.has(request)) { - return request; + return null; } let unqualifiedPath; @@ -360,12 +360,11 @@ exports.resolveToUnqualified = function resolveToUnqualified(request, issuer) { * appends ".js" / ".json", and transforms directory accesses into "index.js"). */ -exports.resolveUnqualified = function resolveUnqualified(unqualifiedPath, {extensions = Object.keys(Module._extensions)} = {}) { - if (builtinModules.has(unqualifiedPath)) { - return unqualifiedPath; - } - - let qualifiedPath = applyNodeExtensionResolution(unqualifiedPath, {extensions}); +exports.resolveUnqualified = function resolveUnqualified( + unqualifiedPath, + {extensions = Object.keys(Module._extensions)} = {}, +) { + const qualifiedPath = applyNodeExtensionResolution(unqualifiedPath, {extensions}); if (qualifiedPath) { return path.normalize(qualifiedPath); @@ -387,7 +386,11 @@ exports.resolveUnqualified = function resolveUnqualified(unqualifiedPath, {exten */ exports.resolveRequest = function resolveRequest(request, issuer) { - let unqualifiedPath = exports.resolveToUnqualified(request, issuer); + const unqualifiedPath = exports.resolveToUnqualified(request, issuer); + + if (unqualifiedPath === null) { + return null; + } try { return exports.resolveUnqualified(unqualifiedPath); @@ -466,7 +469,8 @@ exports.setup = function setup() { const issuerModule = getIssuerModule(parent); const issuer = issuerModule ? issuerModule.filename : process.cwd() + path.sep; - return exports.resolveRequest(request, issuer); + const resolution = exports.resolveRequest(request, issuer); + return resolution !== null ? resolution : request; }; Module._findPath = function(request, paths, isMain) { @@ -504,13 +508,7 @@ exports.setupCompatibilityLayer = () => { let basedir = options.basedir || path.dirname(getCaller()); basedir = basedir.replace(/[\\\/]?$/, path.sep); - const resolution = exports.resolveRequest(request, basedir); - - if (resolution) { - return resolution; - } else { - throw new Error(`Resolution failed for path "${request}"`); - } + return exports.resolveRequest(request, basedir); }; const resolveShim = (request, options, callback) => { @@ -546,15 +544,15 @@ if (module.parent && module.parent.id === 'internal/preload') { } if (process.mainModule === module) { - let reportError = (code, message, data) => { + const reportError = (code, message, data) => { process.stdout.write(`${JSON.stringify([{code, message, data}, null])}\n`); }; - let reportSuccess = resolution => { - process.stdout.write(`${JSON.stringify([null, resolution])}\n`) + const reportSuccess = resolution => { + process.stdout.write(`${JSON.stringify([null, resolution])}\n`); }; - let processResolution = (request, issuer) => { + const processResolution = (request, issuer) => { try { reportSuccess(exports.resolveRequest(request, issuer)); } catch (error) { @@ -562,9 +560,9 @@ if (process.mainModule === module) { } }; - let processRequest = data => { + const processRequest = data => { try { - let [request, issuer] = JSON.parse(data); + const [request, issuer] = JSON.parse(data); processResolution(request, issuer); } catch (error) { reportError(`INVALID_JSON`, error.message, error.data); From 07f1cbbc7c0596f2ff00378f99de843c67e3ed9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Tue, 12 Jun 2018 00:48:42 -0700 Subject: [PATCH 072/111] Various fixes & improvements --- package.json | 3 +++ src/cli/commands/install.js | 2 +- src/util/generate-pnp-map-api.tpl.js | 38 +++++++++++++++------------- src/util/generate-pnp-map.js | 4 ++- 4 files changed, 28 insertions(+), 19 deletions(-) diff --git a/package.json b/package.json index a4dc4b5fdb..5ca5846276 100644 --- a/package.json +++ b/package.json @@ -144,5 +144,8 @@ "commitizen": { "path": "./node_modules/cz-conventional-changelog" } + }, + "installConfig": { + "pnp": true } } diff --git a/src/cli/commands/install.js b/src/cli/commands/install.js index 9b46320f00..a1d3e9fbd5 100644 --- a/src/cli/commands/install.js +++ b/src/cli/commands/install.js @@ -688,7 +688,7 @@ export class Install { let hasChanged = false; if (!this.config.plugnplayByEnv) { - for (const registry of Object.keys(manifests)) { + for (const registry of ['npm']) { const {object} = manifests[registry]; if (typeof object.installConfig !== 'object') { diff --git a/src/util/generate-pnp-map-api.tpl.js b/src/util/generate-pnp-map-api.tpl.js index 749c3fc321..526eaa0d3f 100644 --- a/src/util/generate-pnp-map-api.tpl.js +++ b/src/util/generate-pnp-map-api.tpl.js @@ -116,6 +116,24 @@ function applyNodeExtensionResolution(unqualifiedPath, {extensions}) { // If the file exists and is a file, we can stop right there if (stat && !stat.isDirectory()) { + // If the very last component of the resolved path is a symlink to a file, we then resolve it to a file. We only + // do this first the last component, and not the rest of the path! This allows us to support the case of bin + // symlinks, where a symlink in "/xyz/pkg-name/.bin/bin-name" will point somewhere else (like "/xyz/pkg-name/index.js"). + // In such a case, we want relative requires to be resolved relative to "/xyz/pkg-name/" rather than "/xyz/pkg-name/.bin/". + // + // Also note that the reason we must use readlink on the last component (instead of realpath on the whole path) + // is that we must preserve the other symlinks, in particular those used by pnp to deambiguate packages using + // peer dependencies. For example, "/xyz/.pnp/local/pnp-01234569/.bin/bin-name" should see its relative requires + // be resolved relative to "/xyz/.pnp/local/pnp-0123456789/" rather than "/xyz/pkg-with-peers/", because otherwise + // we would lose the information that would tell us what are the dependencies of pkg-with-peers relative to its + // ancestors. + + if (fs.lstatSync(unqualifiedPath).isSymbolicLink()) { + unqualifiedPath = path.normalize( + path.resolve(path.dirname(unqualifiedPath), fs.readlinkSync(unqualifiedPath)), + ); + } + return unqualifiedPath; } @@ -235,28 +253,14 @@ exports.resolveToUnqualified = function resolveToUnqualified(request, issuer) { let unqualifiedPath; // If the request is a relative or absolute path, we just return it normalized - // - // Note that if the very last component of the issuer is a symlink to a file, we then need to resolve it, but - // only it, and not the rest of the path! This allows us to support the case of bin symlinks, where a symlink - // in "/.../pkg-name/.bin/bin-name" will point somewhere else (like "/../pkg-name/index.js"). In such a case, - // we want relative requires to be resolved relative to "/../pkg-name/" rather than "/../pkg-name/.bin/". - // - // Also note that the reason we must use readlink on the last component (instead of realpath on the whole path) - // is that we must preserve the other symlinks, in particular those used by pnp to deambiguate packages using - // peer dependencies. For example, "/../.pnp/local/pnp-01234569/.bin/bin-name" should see its relative requires - // be resolved relative to "/../.pnp/local/pnp-0123456789/" rather than "/../pkg-with-peers/", because otherwise - // we would lose the information that would tell us what are the dependencies of pkg-with-peers relative to its - // ancestors. const dependencyNameMatch = request.match(pathRegExp); if (!dependencyNameMatch) { - if (issuer.match(isDirRegExp)) { + if (path.isAbsolute(request)) { + unqualifiedPath = path.normalize(request); + } else if (issuer.match(isDirRegExp)) { unqualifiedPath = path.normalize(path.resolve(issuer, request)); - } else if (fs.lstatSync(issuer).isSymbolicLink()) { - unqualifiedPath = path.normalize( - path.resolve(path.dirname(issuer), path.dirname(fs.readlinkSync(issuer)), request), - ); } else { unqualifiedPath = path.normalize(path.resolve(path.dirname(issuer), request)); } diff --git a/src/util/generate-pnp-map.js b/src/util/generate-pnp-map.js index 79f9e7a8fb..561eaf276c 100644 --- a/src/util/generate-pnp-map.js +++ b/src/util/generate-pnp-map.js @@ -179,7 +179,9 @@ async function getPackageInformationStores( // on A; it's valid, but it prevents us from computing A and B - and it's even worse with 3+ packages involved) const peerDependencies = new Set(Array.from(Object.keys(pkg.peerDependencies || {}))); - if (peerDependencies.size > 0) { + // As an optimization, we only setup virtual packages if they underlying packages are referenced multiple times in the tree + // This allow us to avoid having to create symlinks in the majority of cases + if (peerDependencies.size > 0 && ref.requests.length > 1) { const hash = getHashFrom([...parentData, packageName, packageReference]); const newLocDir = From 679deb026bab10518637f16a00d48877efa94ccb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Tue, 12 Jun 2018 02:48:21 -0700 Subject: [PATCH 073/111] Adds a test, prettier, fixes a test --- __tests__/integration.js | 5 ++++- packages/pkg-tests/pkg-tests-specs/sources/pnp.js | 8 ++++++++ src/util/generate-pnp-map-api.tpl.js | 4 +--- src/util/generate-pnp-map.js | 4 ++-- 4 files changed, 15 insertions(+), 6 deletions(-) diff --git a/__tests__/integration.js b/__tests__/integration.js index fee53b8730..d01f23740c 100644 --- a/__tests__/integration.js +++ b/__tests__/integration.js @@ -478,7 +478,10 @@ test('relative cache folder', async () => { const [stdoutOutput, _] = await runYarn(['cache', 'dir'], {cwd: `${base}/sub`}); - expect(await fs.realpath(path.dirname(stdoutOutput.toString()))).toEqual(await fs.realpath(`${base}/foo`)); + // The first dirname is to remove the "node_modules" part, the second is to remove the "v2" part + expect(await fs.realpath(path.dirname(path.dirname(stdoutOutput.toString())))).toEqual( + await fs.realpath(`${base}/foo`), + ); }); test('yarn create', async () => { diff --git a/packages/pkg-tests/pkg-tests-specs/sources/pnp.js b/packages/pkg-tests/pkg-tests-specs/sources/pnp.js index 90ba31a4f0..2feb2bee56 100644 --- a/packages/pkg-tests/pkg-tests-specs/sources/pnp.js +++ b/packages/pkg-tests/pkg-tests-specs/sources/pnp.js @@ -165,6 +165,14 @@ module.exports = makeTemporaryEnv => { ), ); + test(`it should correctly resolve an absolute path even when the issuer doesn't exist`, makeTemporaryEnv({ + }, {plugNPlay: true}, async ({path, run, source}) => { + await run(`install`); + + const api = require(`${path}/.pnp.js`); + api.resolveToUnqualified(`${path}/.pnp.js`, `${path}/some/path/that/doesnt/exists/please/`); + })); + test( `it should fallback to the top-level dependencies when it cannot require a transitive dependency require`, makeTemporaryEnv( diff --git a/src/util/generate-pnp-map-api.tpl.js b/src/util/generate-pnp-map-api.tpl.js index 526eaa0d3f..5ddb0aff19 100644 --- a/src/util/generate-pnp-map-api.tpl.js +++ b/src/util/generate-pnp-map-api.tpl.js @@ -129,9 +129,7 @@ function applyNodeExtensionResolution(unqualifiedPath, {extensions}) { // ancestors. if (fs.lstatSync(unqualifiedPath).isSymbolicLink()) { - unqualifiedPath = path.normalize( - path.resolve(path.dirname(unqualifiedPath), fs.readlinkSync(unqualifiedPath)), - ); + unqualifiedPath = path.normalize(path.resolve(path.dirname(unqualifiedPath), fs.readlinkSync(unqualifiedPath))); } return unqualifiedPath; diff --git a/src/util/generate-pnp-map.js b/src/util/generate-pnp-map.js index 561eaf276c..17f7fe5e72 100644 --- a/src/util/generate-pnp-map.js +++ b/src/util/generate-pnp-map.js @@ -179,8 +179,8 @@ async function getPackageInformationStores( // on A; it's valid, but it prevents us from computing A and B - and it's even worse with 3+ packages involved) const peerDependencies = new Set(Array.from(Object.keys(pkg.peerDependencies || {}))); - // As an optimization, we only setup virtual packages if they underlying packages are referenced multiple times in the tree - // This allow us to avoid having to create symlinks in the majority of cases + // As an optimization, we only setup virtual packages if their underlying packages are referenced multiple times + // in the tree. This allow us to avoid having to create symlinks in the majority of cases if (peerDependencies.size > 0 && ref.requests.length > 1) { const hash = getHashFrom([...parentData, packageName, packageReference]); From ee96006a52a89a91efb8c407ab0f1a0949e0b9f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Tue, 12 Jun 2018 02:52:59 -0700 Subject: [PATCH 074/111] Don't iterate on the registries --- src/cli/commands/install.js | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/src/cli/commands/install.js b/src/cli/commands/install.js index a1d3e9fbd5..8a581c5d7c 100644 --- a/src/cli/commands/install.js +++ b/src/cli/commands/install.js @@ -688,24 +688,22 @@ export class Install { let hasChanged = false; if (!this.config.plugnplayByEnv) { - for (const registry of ['npm']) { - const {object} = manifests[registry]; + const {object} = manifests.npm; - if (typeof object.installConfig !== 'object') { - object.installConfig = {}; - } + if (typeof object.installConfig !== 'object') { + object.installConfig = {}; + } - if (this.config.plugnplayEnabled && object.installConfig.pnp !== true) { - object.installConfig.pnp = true; - hasChanged = true; - } else if (!this.config.plugnplayEnabled && typeof object.installConfig.pnp !== 'undefined') { - delete object.installConfig.pnp; - hasChanged = true; - } + if (this.config.plugnplayEnabled && object.installConfig.pnp !== true) { + object.installConfig.pnp = true; + hasChanged = true; + } else if (!this.config.plugnplayEnabled && typeof object.installConfig.pnp !== 'undefined') { + delete object.installConfig.pnp; + hasChanged = true; + } - if (Object.keys(object.installConfig).length === 0) { - delete object.installConfig; - } + if (Object.keys(object.installConfig).length === 0) { + delete object.installConfig; } } From d29120d15f3da2b7ae7d93408b9116a547b47e85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Thu, 21 Jun 2018 06:04:36 -0700 Subject: [PATCH 075/111] Renames YARN_PLUGNPLAY_EXPERIMENTAL into YARN_PLUGNPLAY_OVERRIDE --- .../pkg-tests/pkg-tests-specs/sources/pnp.js | 31 +++++++++++++++---- packages/pkg-tests/yarn.test.js | 20 ++++++------ src/cli/commands/install.js | 2 +- src/config.js | 23 ++++++++------ 4 files changed, 50 insertions(+), 26 deletions(-) diff --git a/packages/pkg-tests/pkg-tests-specs/sources/pnp.js b/packages/pkg-tests/pkg-tests-specs/sources/pnp.js index 2feb2bee56..024c20b237 100644 --- a/packages/pkg-tests/pkg-tests-specs/sources/pnp.js +++ b/packages/pkg-tests/pkg-tests-specs/sources/pnp.js @@ -165,13 +165,15 @@ module.exports = makeTemporaryEnv => { ), ); - test(`it should correctly resolve an absolute path even when the issuer doesn't exist`, makeTemporaryEnv({ - }, {plugNPlay: true}, async ({path, run, source}) => { - await run(`install`); + test( + `it should correctly resolve an absolute path even when the issuer doesn't exist`, + makeTemporaryEnv({}, {plugNPlay: true}, async ({path, run, source}) => { + await run(`install`); - const api = require(`${path}/.pnp.js`); - api.resolveToUnqualified(`${path}/.pnp.js`, `${path}/some/path/that/doesnt/exists/please/`); - })); + const api = require(`${path}/.pnp.js`); + api.resolveToUnqualified(`${path}/.pnp.js`, `${path}/some/path/that/doesnt/exists/please/`); + }), + ); test( `it should fallback to the top-level dependencies when it cannot require a transitive dependency require`, @@ -454,6 +456,23 @@ module.exports = makeTemporaryEnv => { ), ); + test( + `it should not update the installConfig.pnp field of the package.json when installing with an environment override`, + makeTemporaryEnv( + {}, + { + plugNPlay: true, + }, + async ({path, run, source}) => { + await run(`install`); + + await expect(readJson(`${path}/package.json`)).resolves.not.toMatchObject({ + installConfig: {pnp: true}, + }); + }, + ), + ); + test( `it should update the installConfig.pnp field of the package.json when installing with --enable-pnp`, makeTemporaryEnv({}, async ({path, run, source}) => { diff --git a/packages/pkg-tests/yarn.test.js b/packages/pkg-tests/yarn.test.js index f535f4df15..a85bf9fc9d 100644 --- a/packages/pkg-tests/yarn.test.js +++ b/packages/pkg-tests/yarn.test.js @@ -25,15 +25,17 @@ const pkgDriver = generatePkgDriver({ } return execFile(process.execPath, [`${process.cwd()}/../../bin/yarn.js`, command, ...extraArgs, ...args], { - env: { - [`NPM_CONFIG_REGISTRY`]: registryUrl, - [`YARN_SILENT`]: `1`, - [`YARN_PROXY`]: ``, - [`YARN_HTTPS_PROXY`]: ``, - [`YARN_PLUGNPLAY_EXPERIMENTAL`]: plugNPlay ? `true` : `false`, - [`YARN_PLUGNPLAY_SHEBANG`]: plugnplayShebang || ``, - [`PATH`]: `${path}/bin${delimiter}${process.env.PATH}`, - }, + env: Object.assign( + { + [`NPM_CONFIG_REGISTRY`]: registryUrl, + [`YARN_SILENT`]: `1`, + [`YARN_PROXY`]: ``, + [`YARN_HTTPS_PROXY`]: ``, + [`YARN_PLUGNPLAY_SHEBANG`]: plugnplayShebang || ``, + [`PATH`]: `${path}/bin${delimiter}${process.env.PATH}`, + }, + plugNPlay ? {[`YARN_PLUGNPLAY_OVERRIDE`]: plugNPlay} : {}, + ), cwd: path, }); }, diff --git a/src/cli/commands/install.js b/src/cli/commands/install.js index 8a581c5d7c..582129c4a5 100644 --- a/src/cli/commands/install.js +++ b/src/cli/commands/install.js @@ -687,7 +687,7 @@ export class Install { applyChanges(manifests: RootManifests): Promise { let hasChanged = false; - if (!this.config.plugnplayByEnv) { + if (this.config.plugnplayPersist) { const {object} = manifests.npm; if (typeof object.installConfig !== 'object') { diff --git a/src/config.js b/src/config.js index 615c047056..3ed0fa359e 100644 --- a/src/config.js +++ b/src/config.js @@ -162,7 +162,7 @@ export default class Config { nonInteractive: boolean; - plugnplayByEnv: boolean; + plugnplayPersist: boolean; plugnplayEnabled: boolean; plugnplayShebang: ?string; @@ -350,16 +350,19 @@ export default class Config { const manifest = await this.maybeReadManifest(this.cwd); - this.plugnplayByEnv = !opts.enablePnp && !opts.disablePnp; - - if (this.plugnplayByEnv) { - if (manifest && manifest.installConfig && manifest.installConfig.pnp) { - this.plugnplayEnabled = !!manifest.installConfig.pnp; - } else { - this.plugnplayEnabled = Boolean(this.getOption('plugnplay-experimental')); - } - } else { + const plugnplayByEnv = this.getOption('plugnplay-override'); + if (plugnplayByEnv != null) { + this.plugnplayEnabled = Boolean(plugnplayByEnv); + this.plugnplayPersist = false; + } else if (opts.enablePnp || opts.disablePnp) { this.plugnplayEnabled = !!opts.enablePnp; + this.plugnplayPersist = true; + } else if (manifest && manifest.installConfig && manifest.installConfig.pnp) { + this.plugnplayEnabled = !!manifest.installConfig.pnp; + this.plugnplayPersist = false; + } else { + this.plugnplayEnabled = false; + this.plugnplayEnabled = false; } this.plugnplayShebang = String(this.getOption('plugnplay-shebang')) || '/usr/bin/env node'; From 7cf5c8e64e735c83ecb4953b0f002e2624b16e7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Thu, 21 Jun 2018 06:46:15 -0700 Subject: [PATCH 076/111] Avoids touching the .pnp.js file when it doesn't need to change --- .../pkg-tests/pkg-tests-specs/sources/pnp.js | 54 +++++++++++++++++++ src/cli/commands/install.js | 7 +++ 2 files changed, 61 insertions(+) diff --git a/packages/pkg-tests/pkg-tests-specs/sources/pnp.js b/packages/pkg-tests/pkg-tests-specs/sources/pnp.js index 2feb2bee56..329bb2a0a7 100644 --- a/packages/pkg-tests/pkg-tests-specs/sources/pnp.js +++ b/packages/pkg-tests/pkg-tests-specs/sources/pnp.js @@ -39,6 +39,60 @@ module.exports = makeTemporaryEnv => { }), ); + test( + `it should not touch the .pnp.js file when it already exists and is up-to-date`, + makeTemporaryEnv( + {}, + { + plugNPlay: true, + }, + async ({path, run, source}) => { + await run(`install`); + + const beforeTime = (await fs.stat(`${path}/.pnp.js`)).mtimeMs; + + // Need to wait two seconds to be sure that the mtime will change + await new Promise(resolve => setTimeout(resolve, 2000)); + + await run(`install`); + + const afterTime = (await fs.stat(`${path}/.pnp.js`)).mtimeMs; + + expect(afterTime).toEqual(beforeTime); + }, + ), + ); + + test( + `it should update the .pnp.js file when it already exists but isn't up-to-date`, + makeTemporaryEnv( + {}, + { + plugNPlay: true, + }, + async ({path, run, source}) => { + await run(`install`); + + const beforeTime = (await fs.stat(`${path}/.pnp.js`)).mtimeMs; + + await writeJson(`${path}/package.json`, { + dependencies: { + [`no-deps`]: `1.0.0`, + }, + }); + + // Need to wait two seconds to be sure that the mtime will change + await new Promise(resolve => setTimeout(resolve, 2000)); + + await run(`install`); + + const afterTime = (await fs.stat(`${path}/.pnp.js`)).mtimeMs; + + expect(afterTime).not.toEqual(beforeTime); + }, + ), + ); + test( `it should resolve two identical packages with the same object (easy)`, makeTemporaryEnv( diff --git a/src/cli/commands/install.js b/src/cli/commands/install.js index 8a581c5d7c..d5fd59f85a 100644 --- a/src/cli/commands/install.js +++ b/src/cli/commands/install.js @@ -614,6 +614,13 @@ export class Install { const pnpPath = `${this.config.lockfileFolder}/${constants.PNP_FILENAME}`; + try { + const file = await fs.readFile(pnpPath); + if (file === code) { + return; + } + } catch (error) {} + await fs.writeFile(pnpPath, code); await fs.chmod(pnpPath, 0o755); }), From bae51f561bbaffe0031e839f57fb8dc20785a612 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Thu, 21 Jun 2018 06:43:30 -0700 Subject: [PATCH 077/111] Reworks the cache path to contain the "node_modules/" string --- __tests__/commands/install/integration.js | 3 +- .../corrupted-meta-empty/.yarn-metadata.json | 0 .../corrupted-meta-not-existing/.gitkeep | 0 .../corrupted-meta-typo/.yarn-metadata.json | 0 .../node_modules/good/.yarn-metadata.json | 0 __tests__/integration.js | 10 ++- __tests__/package-resolver.js | 4 +- .../pkg-tests/pkg-tests-specs/sources/pnp.js | 63 +++++++++++++++++-- src/cli/commands/cache.js | 46 ++++++++++---- src/config.js | 25 +++++--- src/fetchers/tarball-fetcher.js | 3 +- src/resolvers/registries/npm-resolver.js | 51 +++------------ src/util/generate-pnp-map.js | 9 +-- 13 files changed, 130 insertions(+), 84 deletions(-) rename __tests__/fixtures/cache/corrupted/.yarn-cache/v2/{ => corrupted-meta-empty}/node_modules/corrupted-meta-empty/.yarn-metadata.json (100%) rename __tests__/fixtures/cache/corrupted/.yarn-cache/v2/{ => corrupted-meta-not-existing}/node_modules/corrupted-meta-not-existing/.gitkeep (100%) rename __tests__/fixtures/cache/corrupted/.yarn-cache/v2/{ => corrupted-meta-typo}/node_modules/corrupted-meta-typo/.yarn-metadata.json (100%) rename __tests__/fixtures/cache/corrupted/.yarn-cache/v2/{ => good}/node_modules/good/.yarn-metadata.json (100%) diff --git a/__tests__/commands/install/integration.js b/__tests__/commands/install/integration.js index 74f691539c..77fc585a9a 100644 --- a/__tests__/commands/install/integration.js +++ b/__tests__/commands/install/integration.js @@ -619,8 +619,9 @@ test('install should update checksums in yarn.lock (--update-checksums)', (): Pr const cachePackageJson = path.resolve( config.cwd, '.yarn-cache/v2/', - 'node_modules', packageCacheName, + 'node_modules', + 'abab', 'package.json', ); expect(packageHashInLockfile).toEqual(packageRealHash); diff --git a/__tests__/fixtures/cache/corrupted/.yarn-cache/v2/node_modules/corrupted-meta-empty/.yarn-metadata.json b/__tests__/fixtures/cache/corrupted/.yarn-cache/v2/corrupted-meta-empty/node_modules/corrupted-meta-empty/.yarn-metadata.json similarity index 100% rename from __tests__/fixtures/cache/corrupted/.yarn-cache/v2/node_modules/corrupted-meta-empty/.yarn-metadata.json rename to __tests__/fixtures/cache/corrupted/.yarn-cache/v2/corrupted-meta-empty/node_modules/corrupted-meta-empty/.yarn-metadata.json diff --git a/__tests__/fixtures/cache/corrupted/.yarn-cache/v2/node_modules/corrupted-meta-not-existing/.gitkeep b/__tests__/fixtures/cache/corrupted/.yarn-cache/v2/corrupted-meta-not-existing/node_modules/corrupted-meta-not-existing/.gitkeep similarity index 100% rename from __tests__/fixtures/cache/corrupted/.yarn-cache/v2/node_modules/corrupted-meta-not-existing/.gitkeep rename to __tests__/fixtures/cache/corrupted/.yarn-cache/v2/corrupted-meta-not-existing/node_modules/corrupted-meta-not-existing/.gitkeep diff --git a/__tests__/fixtures/cache/corrupted/.yarn-cache/v2/node_modules/corrupted-meta-typo/.yarn-metadata.json b/__tests__/fixtures/cache/corrupted/.yarn-cache/v2/corrupted-meta-typo/node_modules/corrupted-meta-typo/.yarn-metadata.json similarity index 100% rename from __tests__/fixtures/cache/corrupted/.yarn-cache/v2/node_modules/corrupted-meta-typo/.yarn-metadata.json rename to __tests__/fixtures/cache/corrupted/.yarn-cache/v2/corrupted-meta-typo/node_modules/corrupted-meta-typo/.yarn-metadata.json diff --git a/__tests__/fixtures/cache/corrupted/.yarn-cache/v2/node_modules/good/.yarn-metadata.json b/__tests__/fixtures/cache/corrupted/.yarn-cache/v2/good/node_modules/good/.yarn-metadata.json similarity index 100% rename from __tests__/fixtures/cache/corrupted/.yarn-cache/v2/node_modules/good/.yarn-metadata.json rename to __tests__/fixtures/cache/corrupted/.yarn-cache/v2/good/node_modules/good/.yarn-metadata.json diff --git a/__tests__/integration.js b/__tests__/integration.js index d01f23740c..fc1fd4e269 100644 --- a/__tests__/integration.js +++ b/__tests__/integration.js @@ -454,7 +454,7 @@ test('cache folder fallback', async () => { const [stdoutOutput, stderrOutput] = await runCacheDir(); - expect(stdoutOutput.toString().trim()).toEqual(path.join(cacheFolder, `v${constants.CACHE_VERSION}`, `node_modules`)); + expect(stdoutOutput.toString().trim()).toEqual(path.join(cacheFolder, `v${constants.CACHE_VERSION}`)); expect(stderrOutput.toString()).not.toMatch(/Skipping preferred cache folder/); await fs.unlink(cacheFolder); @@ -463,7 +463,7 @@ test('cache folder fallback', async () => { const [stdoutOutput2, stderrOutput2] = await runCacheDir(); expect(stdoutOutput2.toString().trim()).toEqual( - path.join(constants.PREFERRED_MODULE_CACHE_DIRECTORIES[0], `v${constants.CACHE_VERSION}`, 'node_modules'), + path.join(constants.PREFERRED_MODULE_CACHE_DIRECTORIES[0], `v${constants.CACHE_VERSION}`), ); expect(stderrOutput2.toString()).toMatch(/Skipping preferred cache folder/); }); @@ -478,10 +478,8 @@ test('relative cache folder', async () => { const [stdoutOutput, _] = await runYarn(['cache', 'dir'], {cwd: `${base}/sub`}); - // The first dirname is to remove the "node_modules" part, the second is to remove the "v2" part - expect(await fs.realpath(path.dirname(path.dirname(stdoutOutput.toString())))).toEqual( - await fs.realpath(`${base}/foo`), - ); + // The dirname is to remove the "v2" part + expect(await fs.realpath(path.dirname(stdoutOutput.toString()))).toEqual(await fs.realpath(`${base}/foo`)); }); test('yarn create', async () => { diff --git a/__tests__/package-resolver.js b/__tests__/package-resolver.js index 87279c91cb..b188b3637a 100644 --- a/__tests__/package-resolver.js +++ b/__tests__/package-resolver.js @@ -14,7 +14,7 @@ jasmine.DEFAULT_TIMEOUT_INTERVAL = 90000; const path = require('path'); // regexp which verifies that cache path contains semver + hash -const cachePathRe = /-\d+\.\d+\.\d+-[\dabcdef]{40}$/; +const cachePathRe = /-\d+\.\d+\.\d+-[\dabcdef]{40}[\\\/]/; async function createEnv(configOptions): Object { const lockfile = new Lockfile(); @@ -82,7 +82,7 @@ addTest( '@foo/bar@1.2.3', 'npm', async cacheFolder => { - const folder = path.join(cacheFolder, 'npm-@foo', 'bar'); + const folder = path.join(cacheFolder, 'npm-@foo-bar', 'node_modules', '@foo', 'bar'); await fs.mkdirp(folder); await fs.writeFile( path.join(folder, constants.METADATA_FILENAME), diff --git a/packages/pkg-tests/pkg-tests-specs/sources/pnp.js b/packages/pkg-tests/pkg-tests-specs/sources/pnp.js index 2feb2bee56..ae3ecd1ce2 100644 --- a/packages/pkg-tests/pkg-tests-specs/sources/pnp.js +++ b/packages/pkg-tests/pkg-tests-specs/sources/pnp.js @@ -165,13 +165,15 @@ module.exports = makeTemporaryEnv => { ), ); - test(`it should correctly resolve an absolute path even when the issuer doesn't exist`, makeTemporaryEnv({ - }, {plugNPlay: true}, async ({path, run, source}) => { - await run(`install`); + test( + `it should correctly resolve an absolute path even when the issuer doesn't exist`, + makeTemporaryEnv({}, {plugNPlay: true}, async ({path, run, source}) => { + await run(`install`); - const api = require(`${path}/.pnp.js`); - api.resolveToUnqualified(`${path}/.pnp.js`, `${path}/some/path/that/doesnt/exists/please/`); - })); + const api = require(`${path}/.pnp.js`); + api.resolveToUnqualified(`${path}/.pnp.js`, `${path}/some/path/that/doesnt/exists/please/`); + }), + ); test( `it should fallback to the top-level dependencies when it cannot require a transitive dependency require`, @@ -604,5 +606,54 @@ module.exports = makeTemporaryEnv => { }, ), ); + + test( + `it should install the packages within a node_modules directory (even if within the cache)`, + makeTemporaryEnv( + { + dependencies: { + [`no-deps`]: `1.0.0`, + }, + }, + { + plugNPlay: true, + }, + async ({path, run, source}) => { + // This is to allow a maximal compatibility with packages that expect to + // be located inside a node_modules directory. Various tools (such as + // transpilers) also use regexps in their configuration that it would be + // nice not to break. + + await run(`install`); + + expect(await source(`require.resolve('no-deps')`)).toMatch(/[\\\/]node_modules[\\\/]no-deps[\\\/]/); + }, + ), + ); + + test( + `it should install packages with peer dependencies within a node_modules directory (even if within the .pnp folder)`, + makeTemporaryEnv( + { + dependencies: { + [`peer-deps`]: `1.0.0`, + [`no-deps`]: `2.0.0`, + }, + }, + { + plugNPlay: true, + }, + async ({path, run, source}) => { + // This is to allow a maximal compatibility with packages that expect to + // be located inside a node_modules directory. Various tools (such as + // transpilers) also use regexps in their configuration that it would be + // nice not to break. + + await run(`install`); + + expect(await source(`require.resolve('peer-deps')`)).toMatch(/[\\\/]node_modules[\\\/]peer-deps[\\\/]/); + }, + ), + ); }); }; diff --git a/src/cli/commands/cache.js b/src/cli/commands/cache.js index 5a3cc2f27f..240f11a80f 100644 --- a/src/cli/commands/cache.js +++ b/src/cli/commands/cache.js @@ -5,6 +5,7 @@ import type Config from '../../config.js'; import buildSubCommands from './_build-sub-commands.js'; import * as fs from '../../util/fs.js'; +const invariant = require('invariant'); const path = require('path'); const micromatch = require('micromatch'); @@ -12,11 +13,7 @@ export function hasWrapper(flags: Object, args: Array): boolean { return args[0] !== 'dir'; } -function isScopedPackageDirectory(packagePath): boolean { - return packagePath.indexOf('@') > -1; -} - -async function getPackagesPaths(config, currentPath): Object { +export async function getCachedPackagesDirs(config: Config, currentPath: string): Object { const results = []; const stat = await fs.lstat(currentPath); @@ -29,13 +26,33 @@ async function getPackagesPaths(config, currentPath): Object { if (folder[0] === '.') { continue; } - const packagePath = path.join(currentPath, folder); - if (isScopedPackageDirectory(folder)) { - results.push(...(await getPackagesPaths(config, packagePath))); - } else { - results.push(packagePath); + const packageParentPath = path.join(currentPath, folder, 'node_modules'); + + const candidates = await fs.readdir(packageParentPath); + invariant( + candidates.length === 1, + `There should only be one folder in a package cache (got ${candidates.join(',')})`, + ); + + for (const candidate of candidates) { + const candidatePath = path.join(packageParentPath, candidate); + if (candidate.charAt(0) === '@') { + const subCandidates = await fs.readdir(candidatePath); + invariant( + subCandidates.length === 1, + `There should only be one folder in a package cache (got ${subCandidates.join(',')})`, + ); + + for (const subCandidate of subCandidates) { + const subCandidatePath = path.join(candidatePath, subCandidate); + results.push(subCandidatePath); + } + } else { + results.push(candidatePath); + } } } + return results; } @@ -53,7 +70,7 @@ function _getMetadataWithPath(getMetadataFn: Function, paths: Array): Pr } async function getCachedPackages(config): Object { - const paths = await getPackagesPaths(config, config.cacheFolder); + const paths = await getCachedPackagesDirs(config, config.cacheFolder); return _getMetadataWithPath(config.readPackageMetadata.bind(config), paths).then(packages => packages.filter(p => !!p), ); @@ -90,8 +107,13 @@ async function clean(config: Config, reporter: Reporter, flags: Object, args: Ar const packagesToDelete = packages.filter(shouldDelete); for (const manifest of packagesToDelete) { - await fs.unlink(manifest._path); // save package path when retrieving + let relativePath = path.relative(config.cacheFolder, manifest._path); + while (relativePath && relativePath !== '.') { + await fs.unlink(path.resolve(config.cacheFolder, relativePath)); + relativePath = path.dirname(relativePath); + } } + activity.end(); reporter.success(reporter.lang('clearedPackageFromCache', args[0])); } else { diff --git a/src/config.js b/src/config.js index 615c047056..a03b39b9f8 100644 --- a/src/config.js +++ b/src/config.js @@ -374,7 +374,7 @@ export default class Config { this.packBuiltPackages = Boolean(this.getOption('experimental-pack-script-packages-in-mirror')); //init & create cacheFolder, tempFolder - this.cacheFolder = path.join(this._cacheRootFolder, 'v' + String(constants.CACHE_VERSION), 'node_modules'); + this.cacheFolder = path.join(this._cacheRootFolder, 'v' + String(constants.CACHE_VERSION)); this.tempFolder = opts.tempFolder || path.join(this.cacheFolder, '.tmp'); await fs.mkdirp(this.cacheFolder); await fs.mkdirp(this.tempFolder); @@ -448,21 +448,30 @@ export default class Config { invariant(this.cacheFolder, 'No package root'); invariant(pkg, 'Undefined package'); - let name = pkg.name; - let uid = pkg.uid; + let slug = pkg.name; + + slug = slug.replace(/[^@a-z0-9]+/g, '-'); + slug = slug.replace(/^-+|-+$/g, ''); + if (pkg.registry) { - name = `${pkg.registry}-${name}`; + slug = `${pkg.registry}-${slug}`; + } else { + slug = `unknown-${slug}`; } const {hash} = pkg.remote; - if (pkg.version && pkg.version !== pkg.uid) { - uid = `${pkg.version}-${uid}`; + if (pkg.version) { + slug += `-${pkg.version}`; + } + + if (pkg.uid && pkg.version !== pkg.uid) { + slug += `-${pkg.uid}`; } else if (hash) { - uid += `-${hash}`; + slug += `-${hash}`; } - return path.join(this.cacheFolder, `${name}-${uid}`); + return path.join(this.cacheFolder, slug, `node_modules`, pkg.name); } /** diff --git a/src/fetchers/tarball-fetcher.js b/src/fetchers/tarball-fetcher.js index b49fb4bf19..7c686def57 100644 --- a/src/fetchers/tarball-fetcher.js +++ b/src/fetchers/tarball-fetcher.js @@ -94,8 +94,9 @@ export default class TarballFetcher extends BaseFetcher { // update hash, destination and cached package const destUpdatedHash = this.dest.replace(this.hash || '', actualHash); await fsUtil.unlink(destUpdatedHash); + await fsUtil.mkdirp(path.dirname(destUpdatedHash)); await fsUtil.rename(this.dest, destUpdatedHash); - this.dest = this.dest.replace(this.hash || '', actualHash); + this.dest = destUpdatedHash; this.hash = actualHash; resolve({ hash: actualHash, diff --git a/src/resolvers/registries/npm-resolver.js b/src/resolvers/registries/npm-resolver.js index 62aa09b6f2..85a47fb993 100644 --- a/src/resolvers/registries/npm-resolver.js +++ b/src/resolvers/registries/npm-resolver.js @@ -1,11 +1,12 @@ /* @flow */ +import {getCachedPackagesDirs} from '../../cli/commands/cache.js'; import type {Manifest} from '../../types.js'; import type Config from '../../config.js'; import type PackageRequest from '../../package-request.js'; import {MessageError} from '../../errors.js'; import RegistryResolver from './registry-resolver.js'; -import NpmRegistry, {SCOPE_SEPARATOR} from '../../registries/npm-registry.js'; +import NpmRegistry from '../../registries/npm-registry.js'; import map from '../../util/map.js'; import * as fs from '../../util/fs.js'; import {YARN_REGISTRY} from '../../constants.js'; @@ -13,7 +14,6 @@ import {getPlatformSpecificPackageFilename} from '../../util/package-name-utils. const inquirer = require('inquirer'); const tty = require('tty'); -const invariant = require('invariant'); const path = require('path'); const semver = require('semver'); @@ -101,55 +101,18 @@ export default class NpmResolver extends RegistryResolver { } async resolveRequestOffline(): Promise { - const escapedName = NpmRegistry.escapeName(this.name); - const scope = this.config.registries.npm.getScope(escapedName); - - // find modules of this name - const prefix = scope ? escapedName.split(SCOPE_SEPARATOR)[1] : `${NPM_REGISTRY_ID}-${this.name}-`; - - invariant(this.config.cacheFolder, 'expected packages root'); - const cacheFolder = path.join(this.config.cacheFolder, scope ? `${NPM_REGISTRY_ID}-${scope}` : ''); - - const files = await this.config.getCache('cachedPackages', async (): Promise> => { - // Try to read the folder. - let files = []; - try { - files = await fs.readdir(cacheFolder); - } catch (err) { - if (err.code === 'ENOENT') { - return []; - } - throw err; - } - - const validFiles = []; - - for (const name of files) { - // no hidden files - if (name[0] === '.') { - continue; - } - - // ensure valid module cache - const dir = path.join(cacheFolder, name); - if (await this.config.isValidModuleDest(dir)) { - validFiles.push(name); - } - } - - return validFiles; + const packageDirs = await this.config.getCache('cachedPackages', (): Promise> => { + return getCachedPackagesDirs(this.config, this.config.cacheFolder); }); const versions = map(); - for (const name of files) { - // check if folder starts with our prefix - if (name.indexOf(prefix) !== 0) { + for (const dir of packageDirs) { + // check if folder contains the registry prefix + if (dir.indexOf(`${NPM_REGISTRY_ID}-`) === -1) { continue; } - const dir = path.join(cacheFolder, name); - // read manifest and validate correct name const pkg = await this.config.readManifest(dir, NPM_REGISTRY_ID); if (pkg.name !== this.name) { diff --git a/src/util/generate-pnp-map.js b/src/util/generate-pnp-map.js index 17f7fe5e72..2bf3762174 100644 --- a/src/util/generate-pnp-map.js +++ b/src/util/generate-pnp-map.js @@ -184,13 +184,14 @@ async function getPackageInformationStores( if (peerDependencies.size > 0 && ref.requests.length > 1) { const hash = getHashFrom([...parentData, packageName, packageReference]); - const newLocDir = + const virtualLoc = ref.remote.type !== 'workspace' - ? path.resolve(config.lockfileFolder, '.pnp', 'global', 'node_modules') - : path.resolve(config.lockfileFolder, '.pnp', 'local'); + ? path.resolve(config.lockfileFolder, '.pnp', 'externals', `pnp-${hash}`, 'node_modules', packageName) + : path.resolve(config.lockfileFolder, '.pnp', 'workspaces', `pnp-${hash}`, packageName); + // Don't forget to update the loc to point at the newly created indirection const physicalLoc = loc; - const virtualLoc = (loc = path.resolve(newLocDir, `pnp-${hash}`)); + loc = virtualLoc; await fs.mkdirp(path.dirname(virtualLoc)); await fs.symlink(physicalLoc, virtualLoc); From 60752b53bc5b1a7eeb8fe09479d10e02e42fa250 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Tue, 26 Jun 2018 03:28:21 -0700 Subject: [PATCH 078/111] Shims resolve#isCore --- src/util/generate-pnp-map-api.tpl.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/util/generate-pnp-map-api.tpl.js b/src/util/generate-pnp-map-api.tpl.js index 5ddb0aff19..5e662c704b 100644 --- a/src/util/generate-pnp-map-api.tpl.js +++ b/src/util/generate-pnp-map-api.tpl.js @@ -537,7 +537,11 @@ exports.setupCompatibilityLayer = () => { }); }; - moduleShims.set('resolve', Object.assign(resolveShim, {sync: resolveSyncShim})); + const isCoreShim = request => { + return builtinModules.has(request); + }; + + moduleShims.set('resolve', Object.assign(resolveShim, {sync: resolveSyncShim, isCore: isCoreShim})); }; if (module.parent && module.parent.id === 'internal/preload') { From 9d132bef845ed8d0caabb20b1e26e57beae8a0e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Tue, 26 Jun 2018 08:30:48 -0700 Subject: [PATCH 079/111] Improves error messages --- src/util/generate-pnp-map-api.tpl.js | 72 +++++++++++++++++++++++++--- 1 file changed, 65 insertions(+), 7 deletions(-) diff --git a/src/util/generate-pnp-map-api.tpl.js b/src/util/generate-pnp-map-api.tpl.js index 5ddb0aff19..97da705ee9 100644 --- a/src/util/generate-pnp-map-api.tpl.js +++ b/src/util/generate-pnp-map-api.tpl.js @@ -276,7 +276,20 @@ exports.resolveToUnqualified = function resolveToUnqualified(request, issuer) { // resolution algorithm in the chain, usually the native Node resolution one if (!issuerLocator) { - return callNativeResolution(request, issuer); + const result = callNativeResolution(request, issuer); + + if (result === false) { + throw makeError( + `BUILTIN_NODE_RESOLUTION_FAIL`, + `The builtin node resolution algorithm was unable to resolve the module referenced by "${request}" and requested from "${issuer}" (it didn't go through the pnp resolver because the issuer doesn't seem to be part of the Yarn-managed dependency tree)`, + { + request, + issuer, + }, + ); + } + + return result; } const issuerInformation = getPackageInformationSafe(issuerLocator); @@ -380,7 +393,7 @@ exports.resolveUnqualified = function resolveUnqualified( }; /** - * Transforms a request into a qualified fully path. + * Transforms a request into a fully qualified path. * * Note that it is extremely important that the `issuer` path ends with a forward slash if the issuer is to be * treated as a folder (ie. "/tmp/foo/" rather than "/tmp/foo" if "foo" is a directory). Otherwise relative @@ -388,7 +401,52 @@ exports.resolveUnqualified = function resolveUnqualified( */ exports.resolveRequest = function resolveRequest(request, issuer) { - const unqualifiedPath = exports.resolveToUnqualified(request, issuer); + let unqualifiedPath; + + try { + unqualifiedPath = exports.resolveToUnqualified(request, issuer); + } catch (originalError) { + // If we get a BUILTIN_NODE_RESOLUTION_FAIL error there, it means that we've had to use the builtin node + // resolution, which usually shouldn't happen. It might be because the user is trying to require something + // from a path loaded through a symlink (which is not possible, because we need something normalized to + // figure out which package is making the require call), so we try to make the same request using a fully + // resolved issuer and throws a better and more actionable error if it works. + if (originalError.code === `BUILTIN_NODE_RESOLUTION_FAIL`) { + let realIssuer; + + try { + realIssuer = fs.realpathSync(issuer); + } catch (error) {} + + if (realIssuer) { + if (issuer.endsWith(`/`)) { + realIssuer = realIssuer.replace(/\/?$/, `/`); + } + + try { + exports.resolveToUnqualified(request, realIssuer); + } catch (error) { + // If an error was thrown, the problem doesn't seem to come from a path not being normalized, so we + // can just throw the original error which was legit. + throw originalError; + } + + // If we reach this stage, it means that resolveToUnqualified didn't fail when using the fully resolved + // file path, which is very likely caused by a module being invoked through Node with a path not being + // correctly normalized (ie you should use "node $(realpath script.js)" instead of "node script.js"). + throw makeError( + `SYMLINKED_PATH_DETECTED`, + `A pnp module ("${request}") has been required from what seems to be a symlinked path ("${issuer}"). This is not possible, you must ensure that your modules are invoked through their fully resolved path on the filesystem (in this case "${realIssuer}").`, + { + request, + issuer, + realIssuer, + }, + ); + } + } + throw originalError; + } if (unqualifiedPath === null) { return null; @@ -396,11 +454,11 @@ exports.resolveRequest = function resolveRequest(request, issuer) { try { return exports.resolveUnqualified(unqualifiedPath); - } catch (error) { - if (error.code === 'QUALIFIED_PATH_RESOLUTION_FAILED') { - Object.assign(error.data, {request, issuer}); + } catch (resolutionError) { + if (resolutionError.code === 'QUALIFIED_PATH_RESOLUTION_FAILED') { + Object.assign(resolutionError.data, {request, issuer}); } - throw error; + throw resolutionError; } }; From 254c8a0961b29da854ae1c7b8b4ae7ad96888417 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Mon, 2 Jul 2018 04:19:01 -0700 Subject: [PATCH 080/111] Fixes the environment cast to allow passing false/0 --- packages/pkg-tests/pkg-tests-specs/sources/pnp.js | 9 +++++++++ packages/pkg-tests/yarn.test.js | 2 +- src/config.js | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/packages/pkg-tests/pkg-tests-specs/sources/pnp.js b/packages/pkg-tests/pkg-tests-specs/sources/pnp.js index 10b4aa4363..36d2d7ca1c 100644 --- a/packages/pkg-tests/pkg-tests-specs/sources/pnp.js +++ b/packages/pkg-tests/pkg-tests-specs/sources/pnp.js @@ -39,6 +39,15 @@ module.exports = makeTemporaryEnv => { }), ); + test( + `it should not use pnp when setting the override to false`, + makeTemporaryEnv({}, {plugNPlay: false}, async ({path, run, source}) => { + await run(`install`); + + expect(fs.existsSync(`${path}/.pnp.js`)).toEqual(false); + }), + ); + test( `it should not touch the .pnp.js file when it already exists and is up-to-date`, makeTemporaryEnv( diff --git a/packages/pkg-tests/yarn.test.js b/packages/pkg-tests/yarn.test.js index a85bf9fc9d..2eccf7d01e 100644 --- a/packages/pkg-tests/yarn.test.js +++ b/packages/pkg-tests/yarn.test.js @@ -34,7 +34,7 @@ const pkgDriver = generatePkgDriver({ [`YARN_PLUGNPLAY_SHEBANG`]: plugnplayShebang || ``, [`PATH`]: `${path}/bin${delimiter}${process.env.PATH}`, }, - plugNPlay ? {[`YARN_PLUGNPLAY_OVERRIDE`]: plugNPlay} : {}, + plugNPlay ? {[`YARN_PLUGNPLAY_OVERRIDE`]: plugNPlay ? `1` : `0`} : {}, ), cwd: path, }); diff --git a/src/config.js b/src/config.js index 2d898cc29c..59f54399b6 100644 --- a/src/config.js +++ b/src/config.js @@ -352,7 +352,7 @@ export default class Config { const plugnplayByEnv = this.getOption('plugnplay-override'); if (plugnplayByEnv != null) { - this.plugnplayEnabled = Boolean(plugnplayByEnv); + this.plugnplayEnabled = plugnplayByEnv !== 'false' && plugnplayByEnv !== '0'; this.plugnplayPersist = false; } else if (opts.enablePnp || opts.disablePnp) { this.plugnplayEnabled = !!opts.enablePnp; From 1645e22568da2ecff5cfbadebcd7775549cd102c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Tue, 10 Jul 2018 09:58:25 -0700 Subject: [PATCH 081/111] Implements a pnp blacklist settings --- .../pkg-tests/pkg-tests-specs/sources/pnp.js | 23 +++++++++++++++++ packages/pkg-tests/yarn.test.js | 3 ++- src/config.js | 2 ++ src/util/generate-pnp-map-api.tpl.js | 25 ++++++++++++++++++- src/util/generate-pnp-map.js | 5 ++-- 5 files changed, 54 insertions(+), 4 deletions(-) diff --git a/packages/pkg-tests/pkg-tests-specs/sources/pnp.js b/packages/pkg-tests/pkg-tests-specs/sources/pnp.js index 36d2d7ca1c..907f5b288a 100644 --- a/packages/pkg-tests/pkg-tests-specs/sources/pnp.js +++ b/packages/pkg-tests/pkg-tests-specs/sources/pnp.js @@ -687,6 +687,29 @@ module.exports = makeTemporaryEnv => { ), ); + it( + `it should not be enabled for paths matching the specified regex`, + makeTemporaryEnv( + {}, + { + plugNPlay: true, + plugnplayBlacklist: `/foo/`, + }, + async ({path, run, source}) => { + await writeFile(`${path}/foo/shouldwork.js`, `module.exports = require('bad-dep');\n`); + await writeFile(`${path}/doesntwork.js`, `module.exports = require('bad-dep');\n`); + + await run(`install`); + + // Force it to exist so that the two scripts would succeed if using the node resolution + await writeFile(`${path}/node_modules/bad-dep/index.js`, `module.exports = 42;\n`); + + await expect(source(`require('./doesntwork')`)).rejects.toBeTruthy(); + await expect(source(`require('./foo/shouldwork')`)).resolves.toBeTruthy(); + }, + ), + ); + test( `it should install the packages within a node_modules directory (even if within the cache)`, makeTemporaryEnv( diff --git a/packages/pkg-tests/yarn.test.js b/packages/pkg-tests/yarn.test.js index 2eccf7d01e..86239666e8 100644 --- a/packages/pkg-tests/yarn.test.js +++ b/packages/pkg-tests/yarn.test.js @@ -17,7 +17,7 @@ const { } = require(`pkg-tests-specs`); const pkgDriver = generatePkgDriver({ - runDriver: (path, [command, ...args], {registryUrl, plugNPlay, plugnplayShebang}) => { + runDriver: (path, [command, ...args], {registryUrl, plugNPlay, plugnplayShebang, plugnplayBlacklist}) => { let extraArgs = []; if (command === 'install') { @@ -32,6 +32,7 @@ const pkgDriver = generatePkgDriver({ [`YARN_PROXY`]: ``, [`YARN_HTTPS_PROXY`]: ``, [`YARN_PLUGNPLAY_SHEBANG`]: plugnplayShebang || ``, + [`YARN_PLUGNPLAY_BLACKLIST`]: plugnplayBlacklist || ``, [`PATH`]: `${path}/bin${delimiter}${process.env.PATH}`, }, plugNPlay ? {[`YARN_PLUGNPLAY_OVERRIDE`]: plugNPlay ? `1` : `0`} : {}, diff --git a/src/config.js b/src/config.js index 59f54399b6..2d07252f33 100644 --- a/src/config.js +++ b/src/config.js @@ -165,6 +165,7 @@ export default class Config { plugnplayPersist: boolean; plugnplayEnabled: boolean; plugnplayShebang: ?string; + plugnplayBlacklist: ?string; scriptsPrependNodePath: boolean; @@ -366,6 +367,7 @@ export default class Config { } this.plugnplayShebang = String(this.getOption('plugnplay-shebang')) || '/usr/bin/env node'; + this.plugnplayBlacklist = String(this.getOption('plugnplay-blacklist')) || null; this.workspacesEnabled = this.getOption('workspaces-experimental') !== false; this.workspacesNohoistEnabled = this.getOption('workspaces-nohoist-experimental') !== false; diff --git a/src/util/generate-pnp-map-api.tpl.js b/src/util/generate-pnp-map-api.tpl.js index b508610997..7f58064ba9 100644 --- a/src/util/generate-pnp-map-api.tpl.js +++ b/src/util/generate-pnp-map-api.tpl.js @@ -1,13 +1,15 @@ #!$$SHEBANG /* eslint-disable max-len, flowtype/require-valid-file-annotation, flowtype/require-return-type */ -/* global packageInformationStores, $$SETUP_STATIC_TABLES */ +/* global packageInformationStores, $$BLACKLIST, $$SETUP_STATIC_TABLES */ const fs = require('fs'); const Module = require('module'); const path = require('path'); const StringDecoder = require('string_decoder'); +const ignorePattern = $$BLACKLIST ? new RegExp($$BLACKLIST) : null; + const builtinModules = new Set(Module.builtinModules || Object.keys(process.binding('natives'))); const originalLoader = Module._load; @@ -248,6 +250,27 @@ exports.resolveToUnqualified = function resolveToUnqualified(request, issuer) { return null; } + // We allow disabling the pnp resolution for some subpaths. This is because some projects, often legacy, + // contain multiple levels of dependencies (ie. a yarn.lock inside a subfolder of a yarn.lock). This is + // typically solved using workspaces, but not all of them have been converted already. + + if (ignorePattern && ignorePattern.test(issuer)) { + const result = callNativeResolution(request, issuer); + + if (result === false) { + throw makeError( + `BUILTIN_NODE_RESOLUTION_FAIL`, + `The builtin node resolution algorithm was unable to resolve the module referenced by "${request}" and requested from "${issuer}" (it didn't go through the pnp resolver because the issuer was explicitely ignored by the regexp "$$BLACKLIST")`, + { + request, + issuer, + }, + ); + } + + return result; + } + let unqualifiedPath; // If the request is a relative or absolute path, we just return it normalized diff --git a/src/util/generate-pnp-map.js b/src/util/generate-pnp-map.js index 2bf3762174..8083760033 100644 --- a/src/util/generate-pnp-map.js +++ b/src/util/generate-pnp-map.js @@ -345,6 +345,7 @@ export async function generatePnpMap( generateMaps(packageInformationStores, blacklistedLocations) + generateFindPackageLocator(packageInformationStores); return pnpApi - .replace(/\$\$SHEBANG/, config.plugnplayShebang) - .replace(/\$\$SETUP_STATIC_TABLES\(\);/, setupStaticTables); + .replace(/\$\$SHEBANG/g, config.plugnplayShebang) + .replace(/\$\$BLACKLIST/g, JSON.stringify(config.plugnplayBlacklist)) + .replace(/\$\$SETUP_STATIC_TABLES\(\);/g, setupStaticTables); } From c2c31426c06f3f42763f7cadeebd643ce0345f17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Thu, 12 Jul 2018 03:16:36 -0700 Subject: [PATCH 082/111] Fixes the fallback resolution to use _resolveFilename instead of _finePath --- src/util/generate-pnp-map-api.tpl.js | 48 +++++++++++++++++++++++----- 1 file changed, 40 insertions(+), 8 deletions(-) diff --git a/src/util/generate-pnp-map-api.tpl.js b/src/util/generate-pnp-map-api.tpl.js index 7f58064ba9..6c318724c6 100644 --- a/src/util/generate-pnp-map-api.tpl.js +++ b/src/util/generate-pnp-map-api.tpl.js @@ -12,10 +12,6 @@ const ignorePattern = $$BLACKLIST ? new RegExp($$BLACKLIST) : null; const builtinModules = new Set(Module.builtinModules || Object.keys(process.binding('natives'))); -const originalLoader = Module._load; -const originalFindPath = Module._findPath; -const originalNodeModulePaths = Module._nodeModulePaths; - const pathRegExp = /^(?!\.{0,2}(?:\/|$))((?:@[^\/]+\/)?[^\/]+)\/?(.*|)$/; const isDirRegExp = /[\\\/]$/; @@ -25,6 +21,13 @@ const blacklistedLocator = {name: NaN, reference: NaN}; const moduleShims = new Map(); const moduleCache = new Map(); +/** + * Used to disable the resolution hooks (for when we want to fallback to the previous resolution - we then need + * a way to "reset" the environment temporarily) + */ + +let enableNativeHooks = true; + /** * Simple helper function that assign an error code to an error, so that it can more easily be caught and used * by third-parties. @@ -205,10 +208,16 @@ function callNativeResolution(request, issuer) { issuer += 'internal.js'; } - const paths = originalNodeModulePaths.call(Module, issuer); - const result = originalFindPath.call(Module, request, paths, false); + try { + enableNativeHooks = false; + + const paths = Module._nodeModulePaths(issuer); + const resolution = Module._resolveFilename(request, null, false, {paths}); - return result; + return resolution; + } finally { + enableNativeHooks = true; + } } /** @@ -493,11 +502,22 @@ exports.resolveRequest = function resolveRequest(request, issuer) { */ exports.setup = function setup() { + const originalModuleLoad = Module._load; + Module._load = function(request, parent, isMain) { + if (!enableNativeHooks) { + return originalModuleLoad.call(Module, request, parent, isMain); + } + // Builtins are managed by the regular Node loader if (builtinModules.has(request)) { - return originalLoader.call(this, request, parent, isMain); + try { + enableNativeHooks = false; + return originalModuleLoad.call(Module, request, parent, isMain); + } finally { + enableNativeHooks = true; + } } // We allow to shim modules, which is useful for packages such as `resolve` @@ -548,7 +568,13 @@ exports.setup = function setup() { return module.exports; }; + const originalModuleResolveFilename = Module._resolveFilename; + Module._resolveFilename = function(request, parent, isMain, options) { + if (!enableNativeHooks) { + return originalModuleResolveFilename.call(Module, request, parent, isMain, options); + } + const issuerModule = getIssuerModule(parent); const issuer = issuerModule ? issuerModule.filename : process.cwd() + path.sep; @@ -556,7 +582,13 @@ exports.setup = function setup() { return resolution !== null ? resolution : request; }; + const originalFindPath = Module._findPath; + Module._findPath = function(request, paths, isMain) { + if (!enableNativeHooks) { + return originalFindPath.call(Module, request, paths, isMain); + } + for (const path of paths) { let resolution; From 2c2ccfd6b88fe07f29a8a7a81063b4195679815b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Thu, 12 Jul 2018 03:53:18 -0700 Subject: [PATCH 083/111] Fixes fallback relative path resolution --- .../pkg-tests/pkg-tests-specs/sources/pnp.js | 19 ++++++++++++++ src/util/generate-pnp-map-api.tpl.js | 25 ++++++++++++++++--- 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/packages/pkg-tests/pkg-tests-specs/sources/pnp.js b/packages/pkg-tests/pkg-tests-specs/sources/pnp.js index 907f5b288a..e245f9e590 100644 --- a/packages/pkg-tests/pkg-tests-specs/sources/pnp.js +++ b/packages/pkg-tests/pkg-tests-specs/sources/pnp.js @@ -710,6 +710,25 @@ module.exports = makeTemporaryEnv => { ), ); + it( + `it should not break relative requires for files within a blacklist`, + makeTemporaryEnv( + {}, + { + plugNPlay: true, + plugnplayBlacklist: `/foo/`, + }, + async ({path, run, source}) => { + await writeFile(`${path}/foo/filea.js`, `module.exports = require('./fileb');\n`); + await writeFile(`${path}/foo/fileb.js`, `module.exports = 42;\n`); + + await run(`install`); + + await expect(source(`require('./foo/filea')`)).resolves.toEqual(42); + }, + ), + ); + test( `it should install the packages within a node_modules directory (even if within the cache)`, makeTemporaryEnv( diff --git a/src/util/generate-pnp-map-api.tpl.js b/src/util/generate-pnp-map-api.tpl.js index 6c318724c6..713a69c735 100644 --- a/src/util/generate-pnp-map-api.tpl.js +++ b/src/util/generate-pnp-map-api.tpl.js @@ -199,6 +199,22 @@ function applyNodeExtensionResolution(unqualifiedPath, {extensions}) { } } +/** + * This function creates fake modules that can be used with the _resolveFilename function. + * Ideally it would be nice to be able to avoid this, since it causes useless allocations + * and cannot be cached efficiently (we recompute the nodeModulePaths every time). + * + * Fortunately, this should only affect the fallback, and there hopefully shouldn't have a + * lot of them. + */ + +function makeFakeModule(path) { + const fakeModule = new Module(path, false); + fakeModule.filename = path; + fakeModule.paths = Module._nodeModulePaths(path); + return fakeModule; +} + /** * Forward the resolution to the next resolver (usually the native one) */ @@ -211,10 +227,11 @@ function callNativeResolution(request, issuer) { try { enableNativeHooks = false; - const paths = Module._nodeModulePaths(issuer); - const resolution = Module._resolveFilename(request, null, false, {paths}); - - return resolution; + // Since we would need to create a fake module anyway (to call _resolveLookupPath that + // would give us the paths to give to _resolveFilename), we can as well not use + // the {paths} option at all, since it internally makes _resolveFilename create another + // fake module anyway. + return Module._resolveFilename(request, makeFakeModule(issuer), false); } finally { enableNativeHooks = true; } From 6e46e7893f2369b90a6d33efe8bb978ac87d454e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Mon, 16 Jul 2018 05:45:48 -0700 Subject: [PATCH 084/111] Implements require.cache --- .../pkg-tests-core/sources/utils/tests.js | 2 +- .../pkg-tests-specs/sources/basic.js | 52 +++++++++++++++++++ src/util/generate-pnp-map-api.tpl.js | 13 +++-- 3 files changed, 62 insertions(+), 5 deletions(-) diff --git a/packages/pkg-tests/pkg-tests-core/sources/utils/tests.js b/packages/pkg-tests/pkg-tests-core/sources/utils/tests.js index 213a89016d..5615e9f6bf 100644 --- a/packages/pkg-tests/pkg-tests-core/sources/utils/tests.js +++ b/packages/pkg-tests/pkg-tests-core/sources/utils/tests.js @@ -332,7 +332,7 @@ exports.generatePkgDriver = function generatePkgDriver({runDriver}: {|runDriver: }; const source = async script => { - return JSON.parse((await run('node', '-p', `JSON.stringify(${script})`)).stdout.toString()); + return JSON.parse((await run('node', '-p', `JSON.stringify((() => ${script})())`)).stdout.toString()); }; try { diff --git a/packages/pkg-tests/pkg-tests-specs/sources/basic.js b/packages/pkg-tests/pkg-tests-specs/sources/basic.js index 05bfb4d1a7..c958a72176 100644 --- a/packages/pkg-tests/pkg-tests-specs/sources/basic.js +++ b/packages/pkg-tests/pkg-tests-specs/sources/basic.js @@ -283,5 +283,57 @@ module.exports = (makeTemporaryEnv: PackageDriver) => { }, ), ); + + test( + `it should cache the loaded modules`, + makeTemporaryEnv( + { + dependencies: {[`no-deps`]: `1.0.0`}, + }, + async ({path, run, source}) => { + await run(`install`); + + await expect( + source( + `{ let before = require('no-deps/package.json'); let after = require('no-deps/package.json'); return before === after }`, + ), + ).resolves.toEqual(true); + }, + ), + ); + + test( + `it should expose the cached modules into require.cache`, + makeTemporaryEnv( + { + dependencies: {[`no-deps`]: `1.0.0`}, + }, + async ({path, run, source}) => { + await run(`install`); + + await expect( + source(`require('no-deps') === require.cache[require.resolve('no-deps')].exports`), + ).resolves.toEqual(true); + }, + ), + ); + + test( + `it should allow resetting a loaded module by deleting its entry from require.cache`, + makeTemporaryEnv( + { + dependencies: {[`no-deps`]: `1.0.0`}, + }, + async ({path, run, source}) => { + await run(`install`); + + await expect( + source( + `{ let before = require('no-deps/package.json'); delete require.cache[require.resolve('no-deps/package.json')]; let after = require('no-deps/package.json'); return before === after }`, + ), + ).resolves.toEqual(false); + }, + ), + ); }); }; diff --git a/src/util/generate-pnp-map-api.tpl.js b/src/util/generate-pnp-map-api.tpl.js index 713a69c735..f011433ced 100644 --- a/src/util/generate-pnp-map-api.tpl.js +++ b/src/util/generate-pnp-map-api.tpl.js @@ -19,7 +19,6 @@ const topLevelLocator = {name: null, reference: null}; const blacklistedLocator = {name: NaN, reference: NaN}; const moduleShims = new Map(); -const moduleCache = new Map(); /** * Used to disable the resolution hooks (for when we want to fallback to the previous resolution - we then need @@ -519,6 +518,12 @@ exports.resolveRequest = function resolveRequest(request, issuer) { */ exports.setup = function setup() { + // A small note: we don't replace the cache here (and instead use the native one). This is an effort to not + // break code similar to "delete require.cache[require.resolve(FOO)]", where FOO is a package located outside + // of the Yarn dependency tree. In this case, we defer the load to the native loader. If we were to replace the + // cache by our own, the native loader would populate its own cache, which wouldn't be exposed anymore, so the + // delete call would be broken. + const originalModuleLoad = Module._load; Module._load = function(request, parent, isMain) { @@ -551,7 +556,7 @@ exports.setup = function setup() { // Check if the module has already been created for the given file - const cacheEntry = moduleCache.get(modulePath); + const cacheEntry = Module._cache[modulePath]; if (cacheEntry) { return cacheEntry.exports; @@ -560,7 +565,7 @@ exports.setup = function setup() { // Create a new module and store it into the cache const module = new Module(modulePath, parent); - moduleCache.set(modulePath, module); + Module._cache[modulePath] = module; // The main module is exposed as global variable @@ -578,7 +583,7 @@ exports.setup = function setup() { hasThrown = false; } finally { if (hasThrown) { - moduleCache.delete(modulePath); + delete Module._cache[modulePath]; } } From 1a498f8767e8063af0e8addeafff9de08368c454 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Fri, 10 Aug 2018 17:45:23 +0100 Subject: [PATCH 085/111] Prevents pnp from being enabled on Windows --- src/config.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/config.js b/src/config.js index 80c76c28f6..ead607e7c5 100644 --- a/src/config.js +++ b/src/config.js @@ -370,7 +370,10 @@ export default class Config { const manifest = await this.maybeReadManifest(this.cwd); const plugnplayByEnv = this.getOption('plugnplay-override'); - if (plugnplayByEnv != null) { + if (process.platform === 'win32') { + this.plugnplayEnabled = false; + this.plugnplayPersist = false; + } else if (plugnplayByEnv != null) { this.plugnplayEnabled = plugnplayByEnv !== 'false' && plugnplayByEnv !== '0'; this.plugnplayPersist = false; } else if (opts.enablePnp || opts.disablePnp) { From df61b90c98ad06879b13ff9595b8773db618a186 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Fri, 10 Aug 2018 17:34:16 +0100 Subject: [PATCH 086/111] Removes absolute paths from the pnp files --- .../pkg-tests/pkg-tests-specs/sources/pnp.js | 72 +++++++++++++++++++ src/cli/commands/install.js | 5 +- src/util/generate-pnp-map-api.tpl.js | 17 +++-- src/util/generate-pnp-map.js | 54 ++++++++++---- 4 files changed, 127 insertions(+), 21 deletions(-) diff --git a/packages/pkg-tests/pkg-tests-specs/sources/pnp.js b/packages/pkg-tests/pkg-tests-specs/sources/pnp.js index e245f9e590..7c167e5003 100644 --- a/packages/pkg-tests/pkg-tests-specs/sources/pnp.js +++ b/packages/pkg-tests/pkg-tests-specs/sources/pnp.js @@ -777,5 +777,77 @@ module.exports = makeTemporaryEnv => { }, ), ); + + test( + `it should make it possible to copy the pnp file and cache from one place to another`, + makeTemporaryEnv( + { + dependencies: { + [`no-deps`]: `1.0.0`, + }, + }, + { + plugNPlay: true, + }, + async ({path, run, source}) => { + await run(`install`); + + await makeTemporaryEnv( + { + [`no-deps`]: `1.0.0`, + }, + { + plugNPlay: true, + }, + async ({path: path2, run: run2, source: source2}) => { + // Move the install artifacts into a new location + // If the .pnp.js file references absolute paths, they will stop working + await fs.rename(`${path}/.cache`, `${path2}/.cache`); + await fs.rename(`${path}/.pnp.js`, `${path2}/.pnp.js`); + + await expect(source2(`require('no-deps')`)).resolves.toMatchObject({ + name: `no-deps`, + version: `1.0.0`, + }); + }, + )(); + }, + ), + ); + + test( + `it should generate the same hooks for two projects with the same configuration`, + makeTemporaryEnv( + { + dependencies: { + [`no-deps`]: `1.0.0`, + }, + }, + { + plugNPlay: true, + }, + async ({path, run, source}) => { + await run(`install`); + + await makeTemporaryEnv( + { + dependencies: { + [`no-deps`]: `1.0.0`, + }, + }, + { + plugNPlay: true, + }, + async ({path: path2, run: run2, source: source2}) => { + expect(path2).not.toEqual(path); + + await run2(`install`); + + expect(readFile(`${path2}/.pnp.js`, 'utf8')).resolves.toEqual(await readFile(`${path}/.pnp.js`, 'utf8')); + }, + )(); + }, + ), + ); }); }; diff --git a/src/cli/commands/install.js b/src/cli/commands/install.js index e73df4b2ce..a6ae2be423 100644 --- a/src/cli/commands/install.js +++ b/src/cli/commands/install.js @@ -609,13 +609,14 @@ export class Install { if (this.config.plugnplayEnabled) { steps.push((curr: number, total: number) => callThroughHook('pnpStep', async () => { + const pnpPath = `${this.config.lockfileFolder}/${constants.PNP_FILENAME}`; + const code = await generatePnpMap(this.config, flattenedTopLevelPatterns, { resolver: this.resolver, + targetPath: pnpPath, workspaceLayout, }); - const pnpPath = `${this.config.lockfileFolder}/${constants.PNP_FILENAME}`; - try { const file = await fs.readFile(pnpPath); if (file === code) { diff --git a/src/util/generate-pnp-map-api.tpl.js b/src/util/generate-pnp-map-api.tpl.js index f011433ced..604c8947a7 100644 --- a/src/util/generate-pnp-map-api.tpl.js +++ b/src/util/generate-pnp-map-api.tpl.js @@ -12,8 +12,15 @@ const ignorePattern = $$BLACKLIST ? new RegExp($$BLACKLIST) : null; const builtinModules = new Set(Module.builtinModules || Object.keys(process.binding('natives'))); +// Splits a require request into its components, or return null if the request is a file path const pathRegExp = /^(?!\.{0,2}(?:\/|$))((?:@[^\/]+\/)?[^\/]+)\/?(.*|)$/; -const isDirRegExp = /[\\\/]$/; + +// Matches if the path starts with a valid path qualifier (./, ../, /) +// eslint-disable-next-line no-unused-vars +const isStrictRegExp = /^\.{0,2}\//; + +// Matches if the path must point to a directory (ie ends with /) +const isDirRegExp = /\/$/; const topLevelLocator = {name: null, reference: null}; const blacklistedLocator = {name: NaN, reference: NaN}; @@ -396,7 +403,7 @@ exports.resolveToUnqualified = function resolveToUnqualified(request, issuer) { const dependencyLocator = {name: dependencyName, reference: dependencyReference}; const dependencyInformation = exports.getPackageInformation(dependencyLocator); - const dependencyLocation = dependencyInformation.packageLocation; + const dependencyLocation = path.resolve(__dirname, dependencyInformation.packageLocation); if (!dependencyLocation) { throw makeError( @@ -598,7 +605,7 @@ exports.setup = function setup() { } const issuerModule = getIssuerModule(parent); - const issuer = issuerModule ? issuerModule.filename : process.cwd() + path.sep; + const issuer = issuerModule ? issuerModule.filename : process.cwd() + '/'; const resolution = exports.resolveRequest(request, issuer); return resolution !== null ? resolution : request; @@ -643,7 +650,7 @@ exports.setupCompatibilityLayer = () => { const resolveSyncShim = (request, options = {}) => { let basedir = options.basedir || path.dirname(getCaller()); - basedir = basedir.replace(/[\\\/]?$/, path.sep); + basedir = basedir.replace(/\/?$/, '/'); return exports.resolveRequest(request, basedir); }; @@ -656,7 +663,7 @@ exports.setupCompatibilityLayer = () => { // We need to compute it here because otherwise resolveSyncShim will read the wrong stacktrace entry let basedir = options.basedir || path.dirname(getCaller()); - basedir = basedir.replace(/[\\\/]?$/, path.sep); + basedir = basedir.replace(/\/?$/, '/'); setImmediate(() => { let error; diff --git a/src/util/generate-pnp-map.js b/src/util/generate-pnp-map.js index 8083760033..21f9d974fe 100644 --- a/src/util/generate-pnp-map.js +++ b/src/util/generate-pnp-map.js @@ -21,6 +21,7 @@ type PackageInformationStores = Map; type GeneratePnpMapOptions = {| resolver: PackageResolver, + targetPath: string, workspaceLayout: ?WorkspaceLayout, |}; @@ -83,9 +84,14 @@ function generateFindPackageLocator(packageInformationStores: PackageInformation for (const packageInformationStore of packageInformationStores.values()) { for (const {packageLocation} of packageInformationStore.values()) { - if (packageLocation !== null) { - lengths.set(packageLocation.length, (lengths.get(packageLocation.length) || 0) + 1); + if (packageLocation === null) { + continue; } + + const length = packageLocation.length; + const count = (lengths.get(length) || 0) + 1; + + lengths.set(length, count); } } @@ -97,12 +103,20 @@ function generateFindPackageLocator(packageInformationStores: PackageInformation // Generate a function that, given a file path, returns the associated package name code += `exports.findPackageLocator = function findPackageLocator(location) {\n`; + code += ` let relativeLocation = path.relative(__dirname, location);\n`; + code += `\n`; + code += ` if (!relativeLocation.match(isStrictRegExp))\n`; + code += ` relativeLocation = \`./\${relativeLocation}\`;\n`; + code += `\n`; + code += ` if (location.match(isDirRegExp) && relativeLocation.charAt(relativeLocation.length - 1) !== '/')\n`; + code += ` relativeLocation = \`\${relativeLocation}/\`;\n`; + code += `\n`; code += ` let match;\n`; for (const [length] of sortedLengths) { code += `\n`; - code += ` if (location.length >= ${length} && location[${length} - 1] === path.sep)\n`; - code += ` if (match = locatorsByLocations.get(location.substr(0, ${length})))\n`; + code += ` if (relativeLocation.length >= ${length} && relativeLocation[${length - 1}] === '/')\n`; + code += ` if (match = locatorsByLocations.get(relativeLocation.substr(0, ${length})))\n`; code += ` return blacklistCheck(match);\n`; } @@ -116,13 +130,21 @@ function generateFindPackageLocator(packageInformationStores: PackageInformation async function getPackageInformationStores( config: Config, seedPatterns: Array, - {resolver, workspaceLayout}: GeneratePnpMapOptions, + {resolver, targetPath, workspaceLayout}: GeneratePnpMapOptions, ): Promise<[PackageInformationStores, Set]> { + const targetDirectory = path.dirname(targetPath); + const packageInformationStores: PackageInformationStores = new Map(); const blacklistedLocations: Set = new Set(); - const ensureTrailingSlash = (fsPath: string) => { - return fsPath.replace(/[\\\/]?$/, path.sep); + const normalizeDirectoryPath = (fsPath: string) => { + let relativePath = path.relative(targetDirectory, fsPath); + + if (!relativePath.match(/^\.{0,2}\//)) { + relativePath = `./${relativePath}`; + } + + return relativePath.replace(/\/?$/, '/'); }; const getHashFrom = (data: Array) => { @@ -200,7 +222,7 @@ async function getPackageInformationStores( // We blacklist this path so that we can print a nicer error message if someone tries to require it (it usually // means that they're using realpath on the return value of require.resolve) - blacklistedLocations.add(ensureTrailingSlash(physicalLoc)); + blacklistedLocations.add(normalizeDirectoryPath(physicalLoc)); } // Now that we have the final reference, we need to store it @@ -244,7 +266,7 @@ async function getPackageInformationStores( packageInformation = { packageMainEntry: pkg.main, - packageLocation: ensureTrailingSlash(loc), + packageLocation: normalizeDirectoryPath(loc), packageDependencies: new Map(), }; @@ -307,7 +329,7 @@ async function getPackageInformationStores( packageInformationStore.set(pkg.version, { packageMainEntry: pkg.main, - packageLocation: ensureTrailingSlash(await fs.realpath(loc)), + packageLocation: normalizeDirectoryPath(loc), packageDependencies: await visit(ref.dependencies, [name, pkg.version]), }); } @@ -322,7 +344,7 @@ async function getPackageInformationStores( null, { packageMainEntry: null, - packageLocation: ensureTrailingSlash(await fs.realpath(config.lockfileFolder)), + packageLocation: normalizeDirectoryPath(config.lockfileFolder), packageDependencies: await visit(seedPatterns), }, ], @@ -335,14 +357,18 @@ async function getPackageInformationStores( export async function generatePnpMap( config: Config, seedPatterns: Array, - {resolver, workspaceLayout}: GeneratePnpMapOptions, + {resolver, workspaceLayout, targetPath}: GeneratePnpMapOptions, ): Promise { const [packageInformationStores, blacklistedLocations] = await getPackageInformationStores(config, seedPatterns, { resolver, + targetPath, workspaceLayout, }); - const setupStaticTables = - generateMaps(packageInformationStores, blacklistedLocations) + generateFindPackageLocator(packageInformationStores); + + const setupStaticTables = [ + generateMaps(packageInformationStores, blacklistedLocations), + generateFindPackageLocator(packageInformationStores), + ].join(``); return pnpApi .replace(/\$\$SHEBANG/g, config.plugnplayShebang) From f46a7637acea77540982761bfdc3d357126efc66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Wed, 15 Aug 2018 18:54:15 +0100 Subject: [PATCH 087/111] Implements a super basic offline cache integration --- src/config.js | 9 +++++++-- src/rc.js | 9 ++++++++- src/registries/yarn-registry.js | 2 +- src/util/generate-pnp-map.js | 15 +++++++++++++++ 4 files changed, 31 insertions(+), 4 deletions(-) diff --git a/src/config.js b/src/config.js index aee2816da9..2a35711653 100644 --- a/src/config.js +++ b/src/config.js @@ -50,6 +50,7 @@ export type ConfigOptions = { enablePnp?: boolean, disablePnp?: boolean, scriptsPrependNodePath?: boolean, + offlineCacheFolder?: string, enableDefaultRc?: boolean, extraneousYarnrcFiles?: Array, @@ -179,6 +180,8 @@ export default class Config { workspacesEnabled: boolean; workspacesNohoistEnabled: boolean; + offlineCacheFolder: ?string; + // cwd: string; workspaceRootFolder: ?string; @@ -390,18 +393,20 @@ export default class Config { } this.plugnplayShebang = String(this.getOption('plugnplay-shebang')) || '/usr/bin/env node'; - this.plugnplayBlacklist = String(this.getOption('plugnplay-blacklist')) || null; + this.plugnplayBlacklist = String(this.getOption('plugnplay-blacklist') || '') || null; this.workspacesEnabled = this.getOption('workspaces-experimental') !== false; this.workspacesNohoistEnabled = this.getOption('workspaces-nohoist-experimental') !== false; + this.offlineCacheFolder = String(this.getOption('offline-cache-folder') || '') || null; + this.pruneOfflineMirror = Boolean(this.getOption('yarn-offline-mirror-pruning')); this.enableMetaFolder = Boolean(this.getOption('enable-meta-folder')); this.enableLockfileVersions = Boolean(this.getOption('yarn-enable-lockfile-versions')); this.linkFileDependencies = Boolean(this.getOption('yarn-link-file-dependencies')); this.packBuiltPackages = Boolean(this.getOption('experimental-pack-script-packages-in-mirror')); - this.autoAddIntegrity = !Boolean(this.getOption('unsafe-disable-integrity-migration')); + this.autoAddIntegrity = !this.getOption('unsafe-disable-integrity-migration'); //init & create cacheFolder, tempFolder this.cacheFolder = path.join(this._cacheRootFolder, 'v' + String(constants.CACHE_VERSION)); diff --git a/src/rc.js b/src/rc.js index fe19259d95..98e71a28f3 100644 --- a/src/rc.js +++ b/src/rc.js @@ -9,7 +9,14 @@ import {parse} from './lockfile'; import * as rcUtil from './util/rc.js'; // Keys that will get resolved relative to the path of the rc file they belong to -const PATH_KEYS = new Set(['yarn-path', 'cache-folder', 'global-folder', 'modules-folder', 'cwd']); +const PATH_KEYS = new Set([ + 'yarn-path', + 'cache-folder', + 'global-folder', + 'modules-folder', + 'cwd', + 'offline-cache-folder', +]); // given a cwd, load all .yarnrc files relative to it export function getRcConfigForCwd(cwd: string, args: Array): {[key: string]: string} { diff --git a/src/registries/yarn-registry.js b/src/registries/yarn-registry.js index 8c58760296..020638afa5 100644 --- a/src/registries/yarn-registry.js +++ b/src/registries/yarn-registry.js @@ -31,7 +31,7 @@ export const DEFAULTS = { 'user-agent': [`yarn/${version}`, 'npm/?', `node/${process.version}`, process.platform, process.arch].join(' '), }; -const RELATIVE_KEYS = ['yarn-offline-mirror', 'cache-folder']; +const RELATIVE_KEYS = ['yarn-offline-mirror', 'cache-folder', 'offline-cache-folder']; const npmMap = { 'version-git-sign': 'sign-git-tag', diff --git a/src/util/generate-pnp-map.js b/src/util/generate-pnp-map.js index 21f9d974fe..64db9e0b0c 100644 --- a/src/util/generate-pnp-map.js +++ b/src/util/generate-pnp-map.js @@ -133,11 +133,26 @@ async function getPackageInformationStores( {resolver, targetPath, workspaceLayout}: GeneratePnpMapOptions, ): Promise<[PackageInformationStores, Set]> { const targetDirectory = path.dirname(targetPath); + const offlineCacheFolder = config.offlineCacheFolder; const packageInformationStores: PackageInformationStores = new Map(); const blacklistedLocations: Set = new Set(); const normalizeDirectoryPath = (fsPath: string) => { + if (offlineCacheFolder) { + const cacheRelativePath = path.relative(config.cacheFolder, fsPath); + + // if fsPath is inside cacheRelativePath + if (!cacheRelativePath.match(/^\.\.\//)) { + const components = cacheRelativePath.split(/\//g); + + // eslint-disable-next-line no-unused-vars + const [cacheEntry, nodeModules, ...internalPath] = components; + + fsPath = path.resolve(offlineCacheFolder, `${cacheEntry}.zip`, internalPath.join('/')); + } + } + let relativePath = path.relative(targetDirectory, fsPath); if (!relativePath.match(/^\.{0,2}\//)) { From dba71ee8d10b024aa87d2bd99e5916946c488ad8 Mon Sep 17 00:00:00 2001 From: Aram Drevekenin Date: Fri, 24 Aug 2018 11:51:19 +0200 Subject: [PATCH 088/111] feat(pnp): eject package command (#92) * test(pnp): support ejecting packages * feat(pnp): eject package command * test(pnp): use fs.readdir instead of fs.readdirSync * test(pnp): do not expect specific error message * refactor(pnp): move eject logic to package linker * fix(pnp): change ejected folder to .pnp/ejected/pkgName-pkgVersion/node_modules/pkgName * fix(pnp): do not re-eject package * test(pnp): do not rely on installConfig --- .../pkg-tests/pkg-tests-specs/sources/pnp.js | 273 ++++++++++++++++++ src/cli/commands/eject.js | 45 +++ src/cli/commands/index.js | 2 + src/cli/commands/install.js | 1 + src/config.js | 2 + src/package-linker.js | 54 +++- src/reporters/lang/en.js | 2 + src/util/generate-pnp-map.js | 7 +- 8 files changed, 382 insertions(+), 4 deletions(-) create mode 100644 src/cli/commands/eject.js diff --git a/packages/pkg-tests/pkg-tests-specs/sources/pnp.js b/packages/pkg-tests/pkg-tests-specs/sources/pnp.js index 7c167e5003..825f4f6937 100644 --- a/packages/pkg-tests/pkg-tests-specs/sources/pnp.js +++ b/packages/pkg-tests/pkg-tests-specs/sources/pnp.js @@ -847,6 +847,279 @@ module.exports = makeTemporaryEnv => { }, )(); }, + ), + ); + + test( + `it should allow ejecting packages from a pnp installation`, + makeTemporaryEnv( + { + dependencies: { + [`no-deps`]: `1.0.0`, + [`various-requires`]: `1.0.0`, + }, + }, + { + plugNPlay: true, + }, + async ({path, run, source}) => { + await run(`install`); + await run(`eject`, `various-requires`); + await writeFile(`${path}/.pnp/ejected/various-requires-1.0.0/node_modules/various-requires/alternative-index.js`, `module.exports = "6 * 9";\n`); + await expect(source(`require('various-requires/relative-require')`)).resolves.toMatch('6 * 9'); + await expect(source(`require('no-deps/package.json')`)).resolves.toMatchObject({ + name: `no-deps`, + version: `1.0.0`, + }); + expect(await fs.readdir(`${path}/.pnp/ejected`)).toEqual([ + 'various-requires-1.0.0' + ]); + }, + ), + ); + + test( + `it should allow ejecting packages from a still uninstalled pnp installation`, + makeTemporaryEnv( + { + dependencies: { + [`no-deps`]: `1.0.0`, + [`various-requires`]: `1.0.0`, + }, + }, + { + plugNPlay: true, + }, + async ({path, run, source}) => { + await run(`eject`, `various-requires`); + await writeFile(`${path}/.pnp/ejected/various-requires-1.0.0/node_modules/various-requires/alternative-index.js`, `module.exports = "6 * 9";\n`); + await expect(source(`require('various-requires/relative-require')`)).resolves.toMatch('6 * 9'); + await expect(source(`require('no-deps/package.json')`)).resolves.toMatchObject({ + name: `no-deps`, + version: `1.0.0`, + }); + expect(await fs.readdir(`${path}/.pnp/ejected`)).toEqual([ + 'various-requires-1.0.0' + ]); + }, + ), + ); + + test( + `it should produce an error if ejecting with pnp disabled`, + makeTemporaryEnv( + { + dependencies: { + [`no-deps`]: `1.0.0`, + [`various-requires`]: `1.0.0`, + }, + }, + { + plugNPlay: false, + }, + async ({path, run, source}) => { + await expect(run(`eject`, `various-requires`)).rejects.toBeTruthy(); + }, + ), + ); + + test( + 'it should produce an error if ejecting with no packages in args', + makeTemporaryEnv( + { + dependencies: { + [`no-deps`]: `1.0.0`, + [`various-requires`]: `1.0.0`, + }, + }, + { + plugNPlay: true, + }, + async ({path, run, source}) => { + await expect(run(`eject`)).rejects.toMatchObject({ + message: expect.stringContaining(`Not enough arguments, expected at least 1.`), + }); + }, + ), + ); + + test( + `it should allow ejecting multiple (deep) packages from a pnp installation`, + makeTemporaryEnv( + { + dependencies: { + [`no-deps`]: `2.0.0`, + [`one-fixed-dep`]: `1.0.0`, + [`various-requires`]: `1.0.0`, + }, + }, + { + plugNPlay: true, + }, + async ({path, run, source}) => { + await run(`install`); + await run(`eject`, `various-requires`, `no-deps`); + expect((await fs.readdir(`${path}/.pnp/ejected`)).sort()).toEqual( + ['no-deps-1.0.0', 'no-deps-2.0.0', 'various-requires-1.0.0'].sort(), + ); + }, + ), + ); + + test( + 'it should allow ejecting package (semver) ranges from a pnp installation', + makeTemporaryEnv( + { + dependencies: { + [`no-deps`]: `2.0.0`, + [`one-fixed-dep`]: `1.0.0`, + [`various-requires`]: `1.0.0`, + }, + }, + { + plugNPlay: true, + }, + async ({path, run, source}) => { + await run(`install`); + await run(`eject`, `various-requires`, `no-deps@^1.0.0`); + expect((await fs.readdir(`${path}/.pnp/ejected`)).sort()).toEqual([ + 'no-deps-1.0.0', + 'various-requires-1.0.0', + ].sort()); + }, + ), + ); + + test( + 'it should properly eject a package with peer dependencies', + makeTemporaryEnv( + { + dependencies: {[`provides-peer-deps-1-0-0`]: `1.0.0`, [`provides-peer-deps-2-0-0`]: `1.0.0`}, + }, + { + plugNPlay: true, + }, + async ({path, run, source}) => { + await run(`eject`, `no-deps`, `peer-deps`); + + await expect( + source(`require('provides-peer-deps-1-0-0') !== require('provides-peer-deps-2-0-0')`), + ).resolves.toEqual(true); + + await expect(source(`require('provides-peer-deps-1-0-0')`)).resolves.toMatchObject({ + name: `provides-peer-deps-1-0-0`, + version: `1.0.0`, + dependencies: { + [`peer-deps`]: { + name: `peer-deps`, + version: `1.0.0`, + peerDependencies: { + [`no-deps`]: { + name: `no-deps`, + version: `1.0.0`, + }, + }, + }, + [`no-deps`]: { + name: `no-deps`, + version: `1.0.0`, + }, + }, + }); + + await expect(source(`require('provides-peer-deps-2-0-0')`)).resolves.toMatchObject({ + name: `provides-peer-deps-2-0-0`, + version: `1.0.0`, + dependencies: { + [`peer-deps`]: { + name: `peer-deps`, + version: `1.0.0`, + peerDependencies: { + [`no-deps`]: { + name: `no-deps`, + version: `2.0.0`, + }, + }, + }, + [`no-deps`]: { + name: `no-deps`, + version: `2.0.0`, + }, + }, + }); + }, + ), + ) + + test( + `it should clear previous ejected folder on new pnp install`, + makeTemporaryEnv( + { + dependencies: { + [`no-deps`]: `1.0.0`, + [`various-requires`]: `1.0.0`, + }, + }, + { + plugNPlay: true, + }, + async ({path, run, source}) => { + await run(`eject`, `various-requires`); + await run(`install`); + expect(await fs.readdir(`${path}/.pnp/ejected`)).toEqual([]); + }, + ), + ); + + test( + `it should clear previous ejected folder on new eject`, + makeTemporaryEnv( + { + dependencies: { + [`no-deps`]: `1.0.0`, + [`various-requires`]: `1.0.0`, + }, + }, + { + plugNPlay: true, + }, + async ({path, run, source}) => { + await run(`eject`, `various-requires`); + await run(`eject`, `no-deps`); + expect(await fs.readdir(`${path}/.pnp/ejected`)).toEqual([ + 'no-deps-1.0.0' + ]); + }, + ), + ); + + test( + `it should not override an already ejected package`, + makeTemporaryEnv( + { + dependencies: { + [`no-deps`]: `1.0.0`, + [`various-requires`]: `1.0.0`, + }, + }, + { + plugNPlay: true, + }, + async ({path, run, source}) => { + await run(`install`); + await run(`eject`, `various-requires`); + await writeFile(`${path}/.pnp/ejected/various-requires-1.0.0/node_modules/various-requires/alternative-index.js`, `module.exports = "6 * 9";\n`); + await run(`eject`, `various-requires`, `no-deps`); + await expect(source(`require('various-requires/relative-require')`)).resolves.toMatch('6 * 9'); + await expect(source(`require('no-deps/package.json')`)).resolves.toMatchObject({ + name: `no-deps`, + version: `1.0.0`, + }); + expect(await fs.readdir(`${path}/.pnp/ejected`)).toEqual([ + 'no-deps-1.0.0', + 'various-requires-1.0.0', + ]); + }, ), ); }); diff --git a/src/cli/commands/eject.js b/src/cli/commands/eject.js new file mode 100644 index 0000000000..e701d6d392 --- /dev/null +++ b/src/cli/commands/eject.js @@ -0,0 +1,45 @@ +/* @flow */ + +import type {Reporter} from '../../reporters/index.js'; +import type Config from '../../config.js'; +import Lockfile from '../../lockfile'; +import {wrapLifecycle, Install} from './install.js'; +import {MessageError} from '../../errors.js'; + +export class Eject extends Install { + constructor(args: Array, flags: Object, config: Config, reporter: Reporter, lockfile: Lockfile) { + const workspaceRootIsCwd = config.cwd === config.lockfileFolder; + const _flags = flags ? {...flags, workspaceRootIsCwd} : {workspaceRootIsCwd}; + config.plugnplayEjected = args; + super(_flags, config, reporter, lockfile); + } + + init(): Promise> { + if (!this.config.plugnplayEnabled) { + throw new MessageError(this.reporter.lang('ejectPlugnplayDisabled')); + } + return Install.prototype.init.call(this); + } +} + +export function hasWrapper(commander: Object): boolean { + return true; +} + +export function setFlags(commander: Object) { + commander.description( + 'Temporarily copies a package (with an optional @range suffix) outside of the global cache for debugging purposes', + ); + commander.usage('eject [packages ...] [flags]'); +} + +export async function run(config: Config, reporter: Reporter, flags: Object, args: Array): Promise { + if (!args.length) { + throw new MessageError(reporter.lang('tooFewArguments', 1)); + } + const lockfile = await Lockfile.fromDirectory(config.lockfileFolder, reporter); + await wrapLifecycle(config, flags, async () => { + const install = new Eject(args, flags, config, reporter, lockfile); + await install.init(); + }); +} diff --git a/src/cli/commands/index.js b/src/cli/commands/index.js index e992381aa5..1836e862b0 100644 --- a/src/cli/commands/index.js +++ b/src/cli/commands/index.js @@ -14,6 +14,7 @@ import * as cache from './cache.js'; import * as check from './check.js'; import * as config from './config.js'; import * as create from './create.js'; +import * as eject from './eject.js'; import * as exec from './exec.js'; import * as generateLockEntry from './generate-lock-entry.js'; import * as global from './global.js'; @@ -57,6 +58,7 @@ const commands = { config, create, dedupe: buildUseless("The dedupe command isn't necessary. `yarn install` will already dedupe."), + eject, exec, generateLockEntry, global, diff --git a/src/cli/commands/install.js b/src/cli/commands/install.js index a6ae2be423..51baa45c89 100644 --- a/src/cli/commands/install.js +++ b/src/cli/commands/install.js @@ -613,6 +613,7 @@ export class Install { const code = await generatePnpMap(this.config, flattenedTopLevelPatterns, { resolver: this.resolver, + reporter: this.reporter, targetPath: pnpPath, workspaceLayout, }); diff --git a/src/config.js b/src/config.js index befda5fefd..bb2556ca4f 100644 --- a/src/config.js +++ b/src/config.js @@ -174,6 +174,7 @@ export default class Config { plugnplayEnabled: boolean; plugnplayShebang: ?string; plugnplayBlacklist: ?string; + plugnplayEjected: Array; scriptsPrependNodePath: boolean; @@ -458,6 +459,7 @@ export default class Config { this.offline = !!opts.offline; this.binLinks = !!opts.binLinks; this.updateChecksums = !!opts.updateChecksums; + this.plugnplayEjected = []; this.ignorePlatform = !!opts.ignorePlatform; this.ignoreScripts = !!opts.ignoreScripts; diff --git a/src/package-linker.js b/src/package-linker.js index 867acc8754..529f8de61a 100644 --- a/src/package-linker.js +++ b/src/package-linker.js @@ -10,6 +10,7 @@ import type {InstallArtifacts} from './package-install-scripts.js'; import PackageHoister from './package-hoister.js'; import * as constants from './constants.js'; import * as promise from './util/promise.js'; +import {normalizePattern} from './util/normalize-pattern.js'; import {entries} from './util/misc.js'; import * as fs from './util/fs.js'; import lockMutex from './util/mutex.js'; @@ -19,6 +20,7 @@ import WorkspaceLayout from './workspace-layout.js'; const invariant = require('invariant'); const cmdShim = require('@zkochan/cmd-shim'); const path = require('path'); +const semver = require('semver'); // Concurrency for creating bin links disabled because of the issue #1961 const linkBinConcurrency = 1; @@ -49,6 +51,7 @@ export default class PackageLinker { this.config = config; this.artifacts = {}; this.topLevelBinLinking = true; + this._alreadyEjected = new Set(); } artifacts: InstallArtifacts; @@ -57,6 +60,7 @@ export default class PackageLinker { config: Config; topLevelBinLinking: boolean; _treeHash: ?Map; + _alreadyEjected: Set; setArtifacts(artifacts: InstallArtifacts) { this.artifacts = artifacts; @@ -273,8 +277,23 @@ export default class PackageLinker { if (this.config.plugnplayEnabled) { ref.isPlugnplay = true; - ref.addLocation(src); - continue; + if (this._isEjected(ref.name, ref.version)) { + dest = path.resolve( + this.config.lockfileFolder, + '.pnp', + 'ejected', + `${pkg.name}-${pkg.version}`, + 'node_modules', + pkg.name, + ); + if (this._alreadyEjected.has(`${pkg.name}-${pkg.version}`)) { + ref.addLocation(dest); + continue; + } + } else { + ref.addLocation(src); + continue; + } } ref.addLocation(dest); @@ -647,6 +666,26 @@ export default class PackageLinker { } } + async delPrevEjectedModules(): Promise { + try { + const ejectedPath = `${this.config.lockfileFolder}/.pnp/ejected`; + for (const currentlyEjectedPkg of await fs.readdir(ejectedPath)) { + const pkgName = currentlyEjectedPkg.split('-').slice(0, -1).join('-'); + const pkgVersion = currentlyEjectedPkg.split('-').pop(); + // eg. foo-bar-baz-1.5.2 (pkgName: foo-bar-baz, pkgVersion: 1.5.2) + if (this._isEjected(pkgName, pkgVersion)) { + this._alreadyEjected.add(currentlyEjectedPkg); + } else { + await fs.unlink(path.join(ejectedPath, currentlyEjectedPkg)); + } + } + } catch (err) { + if (err.code !== 'ENOENT') { + throw err; + } + } + } + _satisfiesPeerDependency(range: string, version: string): boolean { return range === '*' || satisfiesWithPrereleases(version, range, this.config.looseSemver); } @@ -668,12 +707,23 @@ export default class PackageLinker { } } + _isEjected(pkgName: string, pkgVersion: string): boolean { + // ejected module: temporarily (until next install) run a copy of this module from outside the global cache + // for debugging purposes + return this.config.plugnplayEjected.some(patternToEject => { + const {name, range, hasVersion} = normalizePattern(patternToEject); + const satisfiesSemver = hasVersion ? semver.satisfies(pkgVersion, range) : true; + return name === pkgName && satisfiesSemver; + }); + } + async init( patterns: Array, workspaceLayout?: WorkspaceLayout, {linkDuplicates, ignoreOptional}: {linkDuplicates: ?boolean, ignoreOptional: ?boolean} = {}, ): Promise { this.resolvePeerModules(); + await this.delPrevEjectedModules(); await this.copyModules(patterns, workspaceLayout, {linkDuplicates, ignoreOptional}); if (!this.config.plugnplayEnabled) { diff --git a/src/reporters/lang/en.js b/src/reporters/lang/en.js index 346d002cd4..7e076c8a0d 100644 --- a/src/reporters/lang/en.js +++ b/src/reporters/lang/en.js @@ -355,6 +355,8 @@ const messages = { downloadGitWithoutCommit: 'Downloading the git repo $0 over plain git without a commit hash', downloadHTTPWithoutCommit: 'Downloading the git repo $0 over HTTP without a commit hash', + ejectPlugnplayDisabled: "Can only eject packages when Plug'n'Play is enabled", + packageInstalledWithBinaries: 'Installed $0 with binaries:', packageHasBinaries: '$0 has binaries:', packageHasNoBinaries: '$0 has no binaries', diff --git a/src/util/generate-pnp-map.js b/src/util/generate-pnp-map.js index 64db9e0b0c..5fed3882b3 100644 --- a/src/util/generate-pnp-map.js +++ b/src/util/generate-pnp-map.js @@ -3,6 +3,7 @@ import type Config from '../config.js'; import type WorkspaceLayout from '../workspace-layout.js'; import type PackageResolver from '../package-resolver.js'; +import type Reporter from '../reporters/base-reporter.js'; import pnpApi from './generate-pnp-map-api.tpl.js'; import * as fs from './fs.js'; @@ -21,6 +22,7 @@ type PackageInformationStores = Map; type GeneratePnpMapOptions = {| resolver: PackageResolver, + reporter: Reporter, targetPath: string, workspaceLayout: ?WorkspaceLayout, |}; @@ -130,7 +132,7 @@ function generateFindPackageLocator(packageInformationStores: PackageInformation async function getPackageInformationStores( config: Config, seedPatterns: Array, - {resolver, targetPath, workspaceLayout}: GeneratePnpMapOptions, + {resolver, reporter, targetPath, workspaceLayout}: GeneratePnpMapOptions, ): Promise<[PackageInformationStores, Set]> { const targetDirectory = path.dirname(targetPath); const offlineCacheFolder = config.offlineCacheFolder; @@ -372,10 +374,11 @@ async function getPackageInformationStores( export async function generatePnpMap( config: Config, seedPatterns: Array, - {resolver, workspaceLayout, targetPath}: GeneratePnpMapOptions, + {resolver, reporter, workspaceLayout, targetPath}: GeneratePnpMapOptions, ): Promise { const [packageInformationStores, blacklistedLocations] = await getPackageInformationStores(config, seedPatterns, { resolver, + reporter, targetPath, workspaceLayout, }); From 428f9ae6298a22b558d852018d44d27d6f236feb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Fri, 24 Aug 2018 13:13:09 +0100 Subject: [PATCH 089/111] Fixes yarn bin --- .../pkg-tests-core/sources/utils/fs.js | 4 +- .../pkg-tests-core/sources/utils/tests.js | 7 ++ .../has-bin-entries-1.0.0/bin-get-pwd.js | 3 + .../has-bin-entries-1.0.0/package.json | 3 +- .../pkg-tests-specs/sources/script.js | 90 ++++++++++++++++++- packages/pkg-tests/yarn.lock | 6 +- packages/pkg-tests/yarn.test.js | 50 +++++++---- src/cli/commands/run.js | 3 +- 8 files changed, 138 insertions(+), 28 deletions(-) create mode 100644 packages/pkg-tests/pkg-tests-fixtures/packages/has-bin-entries-1.0.0/bin-get-pwd.js diff --git a/packages/pkg-tests/pkg-tests-core/sources/utils/fs.js b/packages/pkg-tests/pkg-tests-core/sources/utils/fs.js index 597857bf35..a39f4a9058 100644 --- a/packages/pkg-tests/pkg-tests-core/sources/utils/fs.js +++ b/packages/pkg-tests/pkg-tests-core/sources/utils/fs.js @@ -174,8 +174,8 @@ exports.readJson = async function readJson(source: string): Promise { } }; -exports.chmod = function chmod(target: string, mod: number): Promise { - return fs.chmod(target, mod); +exports.chmod = async function chmod(target: string, mod: number): Promise { + await fs.chmod(target, mod); }; exports.realpath = function realpath(source: string): Promise { diff --git a/packages/pkg-tests/pkg-tests-core/sources/utils/tests.js b/packages/pkg-tests/pkg-tests-core/sources/utils/tests.js index 5615e9f6bf..f1a9e20132 100644 --- a/packages/pkg-tests/pkg-tests-core/sources/utils/tests.js +++ b/packages/pkg-tests/pkg-tests-core/sources/utils/tests.js @@ -324,10 +324,17 @@ exports.generatePkgDriver = function generatePkgDriver({runDriver}: {|runDriver: await fsUtils.writeJson(`${path}/package.json`, await deepResolve(packageJson)); const run = (...args) => { + let callDefinition = {}; + + if (args.length > 0 && typeof args[args.length - 1] === 'object') { + callDefinition = args.pop(); + } + return runDriver(path, args, { registryUrl, ...definition, ...subDefinition, + ...callDefinition, }); }; diff --git a/packages/pkg-tests/pkg-tests-fixtures/packages/has-bin-entries-1.0.0/bin-get-pwd.js b/packages/pkg-tests/pkg-tests-fixtures/packages/has-bin-entries-1.0.0/bin-get-pwd.js new file mode 100644 index 0000000000..5e4016f4d1 --- /dev/null +++ b/packages/pkg-tests/pkg-tests-fixtures/packages/has-bin-entries-1.0.0/bin-get-pwd.js @@ -0,0 +1,3 @@ +#!/usr/bin/env node + +console.log(process.cwd()); diff --git a/packages/pkg-tests/pkg-tests-fixtures/packages/has-bin-entries-1.0.0/package.json b/packages/pkg-tests/pkg-tests-fixtures/packages/has-bin-entries-1.0.0/package.json index a83f4d2903..56d66a579a 100644 --- a/packages/pkg-tests/pkg-tests-fixtures/packages/has-bin-entries-1.0.0/package.json +++ b/packages/pkg-tests/pkg-tests-fixtures/packages/has-bin-entries-1.0.0/package.json @@ -4,7 +4,8 @@ "bin": { "has-bin-entries": "./bin.js", "has-bin-entries-with-require": "./bin-with-require.js", - "has-bin-entries-with-relative-require": "./bin-with-relative-require.js" + "has-bin-entries-with-relative-require": "./bin-with-relative-require.js", + "has-bin-entries-get-pwd": "./bin-get-pwd.js" }, "dependencies": { "no-deps": "1.0.0" diff --git a/packages/pkg-tests/pkg-tests-specs/sources/script.js b/packages/pkg-tests/pkg-tests-specs/sources/script.js index 1feec3652e..15beb47201 100644 --- a/packages/pkg-tests/pkg-tests-specs/sources/script.js +++ b/packages/pkg-tests/pkg-tests-specs/sources/script.js @@ -2,7 +2,10 @@ import type {PackageDriver} from 'pkg-tests-core'; -const {fs: {makeFakeBinary}} = require(`pkg-tests-core`); +const {existsSync, mkdirp} = require('fs-extra'); +const {isAbsolute, resolve} = require('path'); + +const {fs: {createTemporaryFolder, makeFakeBinary}} = require(`pkg-tests-core`); module.exports = (makeTemporaryEnv: PackageDriver) => { describe(`Scripts tests`, () => { @@ -45,7 +48,7 @@ module.exports = (makeTemporaryEnv: PackageDriver) => { ); test( - `it should expose its dependencies within the $PATH`, + `it should allow to execute the dependencies binaries`, makeTemporaryEnv( { dependencies: { @@ -62,6 +65,89 @@ module.exports = (makeTemporaryEnv: PackageDriver) => { ), ); + test( + `it should allow to execute the dependencies binaries even from a different cwd than the project root`, + makeTemporaryEnv( + { + dependencies: { + [`has-bin-entries`]: `1.0.0`, + }, + }, + async ({path, run, source}) => { + await run(`install`); + + await mkdirp(`${path}/foo/bar`); + + await expect( + run(`run`, `has-bin-entries`, `success`, { + cwd: `${path}/foo/bar`, + }), + ).resolves.toMatchObject({ + stdout: `success\n`, + }); + }, + ), + ); + + test( + `it should allow to retrieve the path to a dependency binary by its name`, + makeTemporaryEnv( + { + dependencies: { + [`has-bin-entries`]: `1.0.0`, + }, + }, + async ({path, run, source}) => { + await run(`install`); + + const {stdout} = await run(`bin`, `has-bin-entries`); + + expect(stdout.trim()).not.toEqual(``); + expect(existsSync(resolve(path, stdout.trim()))).toEqual(true); + }, + ), + ); + + test( + `it should return an absolute path when retrieving the path to a dependency binary`, + makeTemporaryEnv( + { + dependencies: { + [`has-bin-entries`]: `1.0.0`, + }, + }, + async ({path, run, source}) => { + await run(`install`); + + const {stdout} = await run(`bin`, `has-bin-entries`); + + expect(isAbsolute(stdout.trim())).toEqual(true); + }, + ), + ); + + test( + `it should allow to retrieve the path to a dependency binary, even when running from outside the project`, + makeTemporaryEnv( + { + dependencies: {[`has-bin-entries`]: `1.0.0`}, + }, + async ({path, run, source}) => { + await run(`install`); + + const tmp = await createTemporaryFolder(); + + const {stdout} = await run(`bin`, `has-bin-entries`, { + projectFolder: path, + cwd: tmp, + }); + + expect(stdout.trim()).not.toEqual(``); + expect(existsSync(resolve(tmp, stdout.trim()))).toEqual(true); + }, + ), + ); + test( `it shouldn't require the "--" flag to stop interpreting options after "run" commands`, makeTemporaryEnv( diff --git a/packages/pkg-tests/yarn.lock b/packages/pkg-tests/yarn.lock index 39ef4d7231..8adeb97797 100644 --- a/packages/pkg-tests/yarn.lock +++ b/packages/pkg-tests/yarn.lock @@ -1393,9 +1393,9 @@ fragment-cache@^0.2.1: dependencies: map-cache "^0.2.2" -fs-extra@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-6.0.0.tgz#0f0afb290bb3deb87978da816fcd3c7797f3a817" +fs-extra@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.0.tgz#8cc3f47ce07ef7b3593a11b9fb245f7e34c041d6" dependencies: graceful-fs "^4.1.2" jsonfile "^4.0.0" diff --git a/packages/pkg-tests/yarn.test.js b/packages/pkg-tests/yarn.test.js index 86239666e8..96d88c02f7 100644 --- a/packages/pkg-tests/yarn.test.js +++ b/packages/pkg-tests/yarn.test.js @@ -17,28 +17,41 @@ const { } = require(`pkg-tests-specs`); const pkgDriver = generatePkgDriver({ - runDriver: (path, [command, ...args], {registryUrl, plugNPlay, plugnplayShebang, plugnplayBlacklist}) => { - let extraArgs = []; + runDriver: ( + path, + [command, ...args], + {cwd, projectFolder, registryUrl, plugNPlay, plugnplayShebang, plugnplayBlacklist}, + ) => { + let beforeArgs = []; + let middleArgs = []; + + if (projectFolder) { + beforeArgs = [...beforeArgs, `--cwd`, projectFolder]; + } if (command === 'install') { - extraArgs = [...extraArgs, `--cache-folder`, `${path}/.cache`]; + middleArgs = [...middleArgs, `--cache-folder`, `${path}/.cache`]; } - return execFile(process.execPath, [`${process.cwd()}/../../bin/yarn.js`, command, ...extraArgs, ...args], { - env: Object.assign( - { - [`NPM_CONFIG_REGISTRY`]: registryUrl, - [`YARN_SILENT`]: `1`, - [`YARN_PROXY`]: ``, - [`YARN_HTTPS_PROXY`]: ``, - [`YARN_PLUGNPLAY_SHEBANG`]: plugnplayShebang || ``, - [`YARN_PLUGNPLAY_BLACKLIST`]: plugnplayBlacklist || ``, - [`PATH`]: `${path}/bin${delimiter}${process.env.PATH}`, - }, - plugNPlay ? {[`YARN_PLUGNPLAY_OVERRIDE`]: plugNPlay ? `1` : `0`} : {}, - ), - cwd: path, - }); + return execFile( + process.execPath, + [`${process.cwd()}/../../bin/yarn.js`, ...beforeArgs, command, ...middleArgs, ...args], + { + env: Object.assign( + { + [`NPM_CONFIG_REGISTRY`]: registryUrl, + [`YARN_SILENT`]: `1`, + [`YARN_PROXY`]: ``, + [`YARN_HTTPS_PROXY`]: ``, + [`YARN_PLUGNPLAY_SHEBANG`]: plugnplayShebang || ``, + [`YARN_PLUGNPLAY_BLACKLIST`]: plugnplayBlacklist || ``, + [`PATH`]: `${path}/bin${delimiter}${process.env.PATH}`, + }, + plugNPlay ? {[`YARN_PLUGNPLAY_OVERRIDE`]: plugNPlay ? `1` : `0`} : {}, + ), + cwd: cwd || path, + }, + ); }, }); @@ -53,4 +66,3 @@ scriptSpecs(pkgDriver); workspaceSpecs(pkgDriver); pnpSpecs(pkgDriver); dragonSpecs(pkgDriver); -scriptSpecs(pkgDriver); diff --git a/src/cli/commands/run.js b/src/cli/commands/run.js index ddeb68f37a..ccc7915df1 100644 --- a/src/cli/commands/run.js +++ b/src/cli/commands/run.js @@ -42,7 +42,8 @@ export async function getBinEntries(config: Config): Promise const dependencyInformation = pnpApi.getPackageInformation({name, reference}); if (dependencyInformation.packageLocation) { - binFolders.add(`${dependencyInformation.packageLocation}/.bin`); + const fullPath = path.resolve(config.lockfileFolder, dependencyInformation.packageLocation); + binFolders.add(`${fullPath}/.bin`); } } } From bdef391598daab3446d6e42e016547a3f025c824 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Fri, 24 Aug 2018 21:39:10 +0100 Subject: [PATCH 090/111] Preserves the node_modules components in zip paths --- src/util/generate-pnp-map.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/generate-pnp-map.js b/src/util/generate-pnp-map.js index 5fed3882b3..3d50f64b11 100644 --- a/src/util/generate-pnp-map.js +++ b/src/util/generate-pnp-map.js @@ -149,7 +149,7 @@ async function getPackageInformationStores( const components = cacheRelativePath.split(/\//g); // eslint-disable-next-line no-unused-vars - const [cacheEntry, nodeModules, ...internalPath] = components; + const [cacheEntry, ...internalPath] = components; fsPath = path.resolve(offlineCacheFolder, `${cacheEntry}.zip`, internalPath.join('/')); } From 6ee42c1dbb4ecad0fd7c8a4efba64af2941d2ba9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Wed, 29 Aug 2018 05:50:17 -0700 Subject: [PATCH 091/111] Fixes the offline cache --- src/util/fs.js | 25 +++++----- src/util/generate-pnp-map.js | 95 +++++++++++++++++++++++++++--------- 2 files changed, 84 insertions(+), 36 deletions(-) diff --git a/src/util/fs.js b/src/util/fs.js index 25a36f40fd..7877d0a63c 100644 --- a/src/util/fs.js +++ b/src/util/fs.js @@ -675,10 +675,18 @@ export async function find(filename: string, dir: string): Promise { + if (process.platform !== 'win32') { + // use relative paths otherwise which will be retained if the directory is moved + src = path.relative(path.dirname(dest), src); + // When path.relative returns an empty string for the current directory, we should instead use + // '.', which is a valid fs.symlink target. + src = src || '.'; + } + try { const stats = await lstat(dest); if (stats.isSymbolicLink()) { - const resolved = await realpath(dest); + const resolved = dest; if (resolved === src) { return; } @@ -688,6 +696,7 @@ export async function symlink(src: string, dest: string): Promise { throw err; } } + // We use rimraf for unlink which never throws an ENOENT on missing target await unlink(dest); @@ -695,19 +704,7 @@ export async function symlink(src: string, dest: string): Promise { // use directory junctions if possible on win32, this requires absolute paths await fsSymlink(src, dest, 'junction'); } else { - // use relative paths otherwise which will be retained if the directory is moved - let relative; - try { - relative = path.relative(fs.realpathSync(path.dirname(dest)), fs.realpathSync(src)); - } catch (err) { - if (err.code !== 'ENOENT') { - throw err; - } - relative = path.relative(path.dirname(dest), src); - } - // When path.relative returns an empty string for the current directory, we should instead use - // '.', which is a valid fs.symlink target. - await fsSymlink(relative || '.', dest); + await fsSymlink(src, dest); } } diff --git a/src/util/generate-pnp-map.js b/src/util/generate-pnp-map.js index 3d50f64b11..12ef063e23 100644 --- a/src/util/generate-pnp-map.js +++ b/src/util/generate-pnp-map.js @@ -11,6 +11,8 @@ const crypto = require('crypto'); const invariant = require('invariant'); const path = require('path'); +const OFFLINE_CACHE_EXTENSION = `.zip`; + type PackageInformation = {| packageLocation: string, packageMainEntry: ?string, @@ -140,22 +142,37 @@ async function getPackageInformationStores( const packageInformationStores: PackageInformationStores = new Map(); const blacklistedLocations: Set = new Set(); - const normalizeDirectoryPath = (fsPath: string) => { - if (offlineCacheFolder) { - const cacheRelativePath = path.relative(config.cacheFolder, fsPath); + const getCachePath = (fsPath: string) => { + const cacheRelativePath = path.relative(config.cacheFolder, fsPath); - // if fsPath is inside cacheRelativePath - if (!cacheRelativePath.match(/^\.\.\//)) { - const components = cacheRelativePath.split(/\//g); + // if fsPath is not inside cacheRelativePath, we just skip it + if (cacheRelativePath.match(/^\.\.\//)) { + return null; + } - // eslint-disable-next-line no-unused-vars - const [cacheEntry, ...internalPath] = components; + return cacheRelativePath; + }; - fsPath = path.resolve(offlineCacheFolder, `${cacheEntry}.zip`, internalPath.join('/')); - } + const resolveOfflineCacheFolder = (fsPath: string) => { + if (!offlineCacheFolder) { + return fsPath; } - let relativePath = path.relative(targetDirectory, fsPath); + const cacheRelativePath = getCachePath(fsPath); + + // if fsPath is not inside the cache, we shouldn't replace it (workspace) + if (!cacheRelativePath) { + return fsPath; + } + + const components = cacheRelativePath.split(/\//g); + const [cacheEntry, ...internalPath] = components; + + return path.resolve(offlineCacheFolder, `${cacheEntry}${OFFLINE_CACHE_EXTENSION}`, internalPath.join('/')); + }; + + const normalizeDirectoryPath = (fsPath: string) => { + let relativePath = path.relative(targetDirectory, resolveOfflineCacheFolder(fsPath)); if (!relativePath.match(/^\.{0,2}\//)) { relativePath = `./${relativePath}`; @@ -223,23 +240,57 @@ async function getPackageInformationStores( if (peerDependencies.size > 0 && ref.requests.length > 1) { const hash = getHashFrom([...parentData, packageName, packageReference]); - const virtualLoc = - ref.remote.type !== 'workspace' - ? path.resolve(config.lockfileFolder, '.pnp', 'externals', `pnp-${hash}`, 'node_modules', packageName) - : path.resolve(config.lockfileFolder, '.pnp', 'workspaces', `pnp-${hash}`, packageName); - - // Don't forget to update the loc to point at the newly created indirection - const physicalLoc = loc; - loc = virtualLoc; + let symlinkSource; + let symlinkFile; + + switch (ref.remote.type) { + case 'workspace': + { + symlinkSource = loc; + symlinkFile = path.resolve(config.lockfileFolder, '.pnp', 'workspaces', `pnp-${hash}`, packageName); + + loc = symlinkFile; + } + break; + + default: + { + const isFromCache = getCachePath(loc); + + const hashName = + isFromCache && offlineCacheFolder ? `pnp-${hash}${OFFLINE_CACHE_EXTENSION}` : `pnp-${hash}`; + const newLoc = path.resolve( + config.lockfileFolder, + '.pnp', + 'externals', + hashName, + 'node_modules', + packageName, + ); + + // The `node_modules/` part is already there when the package comes from the cache + if (isFromCache) { + const getBase = source => path.resolve(source, '../'.repeat(1 + packageName.split('/').length)); + symlinkSource = resolveOfflineCacheFolder(getBase(loc)); + symlinkFile = getBase(newLoc); + } else { + symlinkSource = loc; + symlinkFile = newLoc; + } + + loc = newLoc; + } + break; + } - await fs.mkdirp(path.dirname(virtualLoc)); - await fs.symlink(physicalLoc, virtualLoc); + await fs.mkdirp(path.dirname(symlinkFile)); + await fs.symlink(symlinkSource, symlinkFile); packageReference = `pnp:${hash}`; // We blacklist this path so that we can print a nicer error message if someone tries to require it (it usually // means that they're using realpath on the return value of require.resolve) - blacklistedLocations.add(normalizeDirectoryPath(physicalLoc)); + blacklistedLocations.add(normalizeDirectoryPath(loc)); } // Now that we have the final reference, we need to store it From 143a4629907c01629f7b3e178c4af9d49b3ca7db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Thu, 6 Sep 2018 16:48:49 +0100 Subject: [PATCH 092/111] Adds a VERSIONS field into the generated resolver --- src/util/generate-pnp-map-api.tpl.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/util/generate-pnp-map-api.tpl.js b/src/util/generate-pnp-map-api.tpl.js index 604c8947a7..9026a6dcbb 100644 --- a/src/util/generate-pnp-map-api.tpl.js +++ b/src/util/generate-pnp-map-api.tpl.js @@ -243,6 +243,17 @@ function callNativeResolution(request, issuer) { } } +/** + * This key indicates which version of the standard is implemented by this resolver. The `std` key is the + * Plug'n'Play standard, and any other key are third-party extensions. Third-party extensions are not allowed + * to override the standard, and can only offer new methods. + * + * If an new version of the Plug'n'Play standard is released and some extensions conflict with newly added + * functions, they'll just have to fix the conflicts and bump their own version number. + */ + +exports.VERSIONS = {std: 1}; + /** * Gets the package information for a given locator. Returns null if they cannot be retrieved. */ From d1f46ea601274c622ac2dd17bca1bf2d3a753371 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Thu, 6 Sep 2018 16:52:58 +0100 Subject: [PATCH 093/111] Exposes the "extensions" option to "resolveRequest" --- src/util/generate-pnp-map-api.tpl.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/util/generate-pnp-map-api.tpl.js b/src/util/generate-pnp-map-api.tpl.js index 604c8947a7..957e49cf45 100644 --- a/src/util/generate-pnp-map-api.tpl.js +++ b/src/util/generate-pnp-map-api.tpl.js @@ -455,7 +455,7 @@ exports.resolveUnqualified = function resolveUnqualified( * imports won't be computed correctly (they'll get resolved relative to "/tmp/" instead of "/tmp/foo/"). */ -exports.resolveRequest = function resolveRequest(request, issuer) { +exports.resolveRequest = function resolveRequest(request, issuer, {extensions} = {}) { let unqualifiedPath; try { @@ -479,7 +479,7 @@ exports.resolveRequest = function resolveRequest(request, issuer) { } try { - exports.resolveToUnqualified(request, realIssuer); + exports.resolveToUnqualified(request, realIssuer, {extensions}); } catch (error) { // If an error was thrown, the problem doesn't seem to come from a path not being normalized, so we // can just throw the original error which was legit. From 2d94b06c9710c4d680f1e70e849953fc1693422c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Thu, 6 Sep 2018 17:56:51 +0100 Subject: [PATCH 094/111] Renames yarn eject into yarn unplug --- .../pkg-tests/pkg-tests-specs/sources/pnp.js | 62 +++++++++---------- src/cli/commands/index.js | 4 +- src/cli/commands/{eject.js => unplug.js} | 8 +-- src/package-linker.js | 4 +- src/reporters/lang/en.js | 2 +- 5 files changed, 40 insertions(+), 40 deletions(-) rename src/cli/commands/{eject.js => unplug.js} (85%) diff --git a/packages/pkg-tests/pkg-tests-specs/sources/pnp.js b/packages/pkg-tests/pkg-tests-specs/sources/pnp.js index 825f4f6937..94435ed23a 100644 --- a/packages/pkg-tests/pkg-tests-specs/sources/pnp.js +++ b/packages/pkg-tests/pkg-tests-specs/sources/pnp.js @@ -851,7 +851,7 @@ module.exports = makeTemporaryEnv => { ); test( - `it should allow ejecting packages from a pnp installation`, + `it should allow unplugging packages from a pnp installation`, makeTemporaryEnv( { dependencies: { @@ -864,14 +864,14 @@ module.exports = makeTemporaryEnv => { }, async ({path, run, source}) => { await run(`install`); - await run(`eject`, `various-requires`); - await writeFile(`${path}/.pnp/ejected/various-requires-1.0.0/node_modules/various-requires/alternative-index.js`, `module.exports = "6 * 9";\n`); + await run(`unplug`, `various-requires`); + await writeFile(`${path}/.pnp/unplugged/various-requires-1.0.0/node_modules/various-requires/alternative-index.js`, `module.exports = "6 * 9";\n`); await expect(source(`require('various-requires/relative-require')`)).resolves.toMatch('6 * 9'); await expect(source(`require('no-deps/package.json')`)).resolves.toMatchObject({ name: `no-deps`, version: `1.0.0`, }); - expect(await fs.readdir(`${path}/.pnp/ejected`)).toEqual([ + expect(await fs.readdir(`${path}/.pnp/unplugged`)).toEqual([ 'various-requires-1.0.0' ]); }, @@ -879,7 +879,7 @@ module.exports = makeTemporaryEnv => { ); test( - `it should allow ejecting packages from a still uninstalled pnp installation`, + `it should allow unplugging packages from a still uninstalled pnp installation`, makeTemporaryEnv( { dependencies: { @@ -891,14 +891,14 @@ module.exports = makeTemporaryEnv => { plugNPlay: true, }, async ({path, run, source}) => { - await run(`eject`, `various-requires`); - await writeFile(`${path}/.pnp/ejected/various-requires-1.0.0/node_modules/various-requires/alternative-index.js`, `module.exports = "6 * 9";\n`); + await run(`unplug`, `various-requires`); + await writeFile(`${path}/.pnp/unplugged/various-requires-1.0.0/node_modules/various-requires/alternative-index.js`, `module.exports = "6 * 9";\n`); await expect(source(`require('various-requires/relative-require')`)).resolves.toMatch('6 * 9'); await expect(source(`require('no-deps/package.json')`)).resolves.toMatchObject({ name: `no-deps`, version: `1.0.0`, }); - expect(await fs.readdir(`${path}/.pnp/ejected`)).toEqual([ + expect(await fs.readdir(`${path}/.pnp/unplugged`)).toEqual([ 'various-requires-1.0.0' ]); }, @@ -906,7 +906,7 @@ module.exports = makeTemporaryEnv => { ); test( - `it should produce an error if ejecting with pnp disabled`, + `it should produce an error if unplugging with pnp disabled`, makeTemporaryEnv( { dependencies: { @@ -918,13 +918,13 @@ module.exports = makeTemporaryEnv => { plugNPlay: false, }, async ({path, run, source}) => { - await expect(run(`eject`, `various-requires`)).rejects.toBeTruthy(); + await expect(run(`unplug`, `various-requires`)).rejects.toBeTruthy(); }, ), ); test( - 'it should produce an error if ejecting with no packages in args', + 'it should produce an error if unplugging with no packages in args', makeTemporaryEnv( { dependencies: { @@ -936,7 +936,7 @@ module.exports = makeTemporaryEnv => { plugNPlay: true, }, async ({path, run, source}) => { - await expect(run(`eject`)).rejects.toMatchObject({ + await expect(run(`unplug`)).rejects.toMatchObject({ message: expect.stringContaining(`Not enough arguments, expected at least 1.`), }); }, @@ -944,7 +944,7 @@ module.exports = makeTemporaryEnv => { ); test( - `it should allow ejecting multiple (deep) packages from a pnp installation`, + `it should allow unplugging multiple (deep) packages from a pnp installation`, makeTemporaryEnv( { dependencies: { @@ -958,8 +958,8 @@ module.exports = makeTemporaryEnv => { }, async ({path, run, source}) => { await run(`install`); - await run(`eject`, `various-requires`, `no-deps`); - expect((await fs.readdir(`${path}/.pnp/ejected`)).sort()).toEqual( + await run(`unplug`, `various-requires`, `no-deps`); + expect((await fs.readdir(`${path}/.pnp/unplugged`)).sort()).toEqual( ['no-deps-1.0.0', 'no-deps-2.0.0', 'various-requires-1.0.0'].sort(), ); }, @@ -967,7 +967,7 @@ module.exports = makeTemporaryEnv => { ); test( - 'it should allow ejecting package (semver) ranges from a pnp installation', + 'it should allow unplugging package (semver) ranges from a pnp installation', makeTemporaryEnv( { dependencies: { @@ -981,8 +981,8 @@ module.exports = makeTemporaryEnv => { }, async ({path, run, source}) => { await run(`install`); - await run(`eject`, `various-requires`, `no-deps@^1.0.0`); - expect((await fs.readdir(`${path}/.pnp/ejected`)).sort()).toEqual([ + await run(`unplug`, `various-requires`, `no-deps@^1.0.0`); + expect((await fs.readdir(`${path}/.pnp/unplugged`)).sort()).toEqual([ 'no-deps-1.0.0', 'various-requires-1.0.0', ].sort()); @@ -1000,7 +1000,7 @@ module.exports = makeTemporaryEnv => { plugNPlay: true, }, async ({path, run, source}) => { - await run(`eject`, `no-deps`, `peer-deps`); + await run(`unplug`, `no-deps`, `peer-deps`); await expect( source(`require('provides-peer-deps-1-0-0') !== require('provides-peer-deps-2-0-0')`), @@ -1052,7 +1052,7 @@ module.exports = makeTemporaryEnv => { ) test( - `it should clear previous ejected folder on new pnp install`, + `it should clear previous unplugged folder on new pnp install`, makeTemporaryEnv( { dependencies: { @@ -1064,15 +1064,15 @@ module.exports = makeTemporaryEnv => { plugNPlay: true, }, async ({path, run, source}) => { - await run(`eject`, `various-requires`); + await run(`unplug`, `various-requires`); await run(`install`); - expect(await fs.readdir(`${path}/.pnp/ejected`)).toEqual([]); + expect(await fs.readdir(`${path}/.pnp/unplugged`)).toEqual([]); }, ), ); test( - `it should clear previous ejected folder on new eject`, + `it should clear previous unplugged folder on new eject`, makeTemporaryEnv( { dependencies: { @@ -1084,9 +1084,9 @@ module.exports = makeTemporaryEnv => { plugNPlay: true, }, async ({path, run, source}) => { - await run(`eject`, `various-requires`); - await run(`eject`, `no-deps`); - expect(await fs.readdir(`${path}/.pnp/ejected`)).toEqual([ + await run(`unplug`, `various-requires`); + await run(`unplug`, `no-deps`); + expect(await fs.readdir(`${path}/.pnp/unplugged`)).toEqual([ 'no-deps-1.0.0' ]); }, @@ -1094,7 +1094,7 @@ module.exports = makeTemporaryEnv => { ); test( - `it should not override an already ejected package`, + `it should not override an already unplugged package`, makeTemporaryEnv( { dependencies: { @@ -1107,15 +1107,15 @@ module.exports = makeTemporaryEnv => { }, async ({path, run, source}) => { await run(`install`); - await run(`eject`, `various-requires`); - await writeFile(`${path}/.pnp/ejected/various-requires-1.0.0/node_modules/various-requires/alternative-index.js`, `module.exports = "6 * 9";\n`); - await run(`eject`, `various-requires`, `no-deps`); + await run(`unplug`, `various-requires`); + await writeFile(`${path}/.pnp/unplugged/various-requires-1.0.0/node_modules/various-requires/alternative-index.js`, `module.exports = "6 * 9";\n`); + await run(`unplug`, `various-requires`, `no-deps`); await expect(source(`require('various-requires/relative-require')`)).resolves.toMatch('6 * 9'); await expect(source(`require('no-deps/package.json')`)).resolves.toMatchObject({ name: `no-deps`, version: `1.0.0`, }); - expect(await fs.readdir(`${path}/.pnp/ejected`)).toEqual([ + expect(await fs.readdir(`${path}/.pnp/unplugged`)).toEqual([ 'no-deps-1.0.0', 'various-requires-1.0.0', ]); diff --git a/src/cli/commands/index.js b/src/cli/commands/index.js index 1836e862b0..e162956ef4 100644 --- a/src/cli/commands/index.js +++ b/src/cli/commands/index.js @@ -14,7 +14,6 @@ import * as cache from './cache.js'; import * as check from './check.js'; import * as config from './config.js'; import * as create from './create.js'; -import * as eject from './eject.js'; import * as exec from './exec.js'; import * as generateLockEntry from './generate-lock-entry.js'; import * as global from './global.js'; @@ -37,6 +36,7 @@ import * as remove from './remove.js'; import * as run from './run.js'; import * as tag from './tag.js'; import * as team from './team.js'; +import * as unplug from './unplug.js'; import * as unlink from './unlink.js'; import * as upgrade from './upgrade.js'; import * as version from './version.js'; @@ -58,7 +58,6 @@ const commands = { config, create, dedupe: buildUseless("The dedupe command isn't necessary. `yarn install` will already dedupe."), - eject, exec, generateLockEntry, global, @@ -83,6 +82,7 @@ const commands = { run, tag, team, + unplug, unlink, upgrade, version, diff --git a/src/cli/commands/eject.js b/src/cli/commands/unplug.js similarity index 85% rename from src/cli/commands/eject.js rename to src/cli/commands/unplug.js index e701d6d392..197777fe30 100644 --- a/src/cli/commands/eject.js +++ b/src/cli/commands/unplug.js @@ -6,7 +6,7 @@ import Lockfile from '../../lockfile'; import {wrapLifecycle, Install} from './install.js'; import {MessageError} from '../../errors.js'; -export class Eject extends Install { +export class Unplug extends Install { constructor(args: Array, flags: Object, config: Config, reporter: Reporter, lockfile: Lockfile) { const workspaceRootIsCwd = config.cwd === config.lockfileFolder; const _flags = flags ? {...flags, workspaceRootIsCwd} : {workspaceRootIsCwd}; @@ -16,7 +16,7 @@ export class Eject extends Install { init(): Promise> { if (!this.config.plugnplayEnabled) { - throw new MessageError(this.reporter.lang('ejectPlugnplayDisabled')); + throw new MessageError(this.reporter.lang('unplugPlugnplayDisabled')); } return Install.prototype.init.call(this); } @@ -30,7 +30,7 @@ export function setFlags(commander: Object) { commander.description( 'Temporarily copies a package (with an optional @range suffix) outside of the global cache for debugging purposes', ); - commander.usage('eject [packages ...] [flags]'); + commander.usage('unplug [packages ...] [flags]'); } export async function run(config: Config, reporter: Reporter, flags: Object, args: Array): Promise { @@ -39,7 +39,7 @@ export async function run(config: Config, reporter: Reporter, flags: Object, arg } const lockfile = await Lockfile.fromDirectory(config.lockfileFolder, reporter); await wrapLifecycle(config, flags, async () => { - const install = new Eject(args, flags, config, reporter, lockfile); + const install = new Unplug(args, flags, config, reporter, lockfile); await install.init(); }); } diff --git a/src/package-linker.js b/src/package-linker.js index 529f8de61a..52f46d990c 100644 --- a/src/package-linker.js +++ b/src/package-linker.js @@ -281,7 +281,7 @@ export default class PackageLinker { dest = path.resolve( this.config.lockfileFolder, '.pnp', - 'ejected', + 'unplugged', `${pkg.name}-${pkg.version}`, 'node_modules', pkg.name, @@ -668,7 +668,7 @@ export default class PackageLinker { async delPrevEjectedModules(): Promise { try { - const ejectedPath = `${this.config.lockfileFolder}/.pnp/ejected`; + const ejectedPath = `${this.config.lockfileFolder}/.pnp/unplugged`; for (const currentlyEjectedPkg of await fs.readdir(ejectedPath)) { const pkgName = currentlyEjectedPkg.split('-').slice(0, -1).join('-'); const pkgVersion = currentlyEjectedPkg.split('-').pop(); diff --git a/src/reporters/lang/en.js b/src/reporters/lang/en.js index 7e076c8a0d..3a60f49940 100644 --- a/src/reporters/lang/en.js +++ b/src/reporters/lang/en.js @@ -355,7 +355,7 @@ const messages = { downloadGitWithoutCommit: 'Downloading the git repo $0 over plain git without a commit hash', downloadHTTPWithoutCommit: 'Downloading the git repo $0 over HTTP without a commit hash', - ejectPlugnplayDisabled: "Can only eject packages when Plug'n'Play is enabled", + unplugPlugnplayDisabled: "Packages can only be unplugged when Plug'n'Play is enabled.", packageInstalledWithBinaries: 'Installed $0 with binaries:', packageHasBinaries: '$0 has binaries:', From 6492fedab48ae997fd575753f1f1974a2db78e53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Fri, 7 Sep 2018 17:16:18 +0100 Subject: [PATCH 095/111] Tweaks yarn unplug --- .../pkg-tests/pkg-tests-specs/sources/pnp.js | 119 +++++++++++++----- packages/pkg-tests/yarn.test.js | 15 ++- src/cli/commands/unplug.js | 71 +++++++---- src/config.js | 56 ++++++++- src/package-linker.js | 57 +++------ src/reporters/lang/en.js | 2 +- 6 files changed, 219 insertions(+), 101 deletions(-) diff --git a/packages/pkg-tests/pkg-tests-specs/sources/pnp.js b/packages/pkg-tests/pkg-tests-specs/sources/pnp.js index 94435ed23a..34dac1cebb 100644 --- a/packages/pkg-tests/pkg-tests-specs/sources/pnp.js +++ b/packages/pkg-tests/pkg-tests-specs/sources/pnp.js @@ -848,7 +848,7 @@ module.exports = makeTemporaryEnv => { )(); }, ), - ); + ); test( `it should allow unplugging packages from a pnp installation`, @@ -865,15 +865,20 @@ module.exports = makeTemporaryEnv => { async ({path, run, source}) => { await run(`install`); await run(`unplug`, `various-requires`); - await writeFile(`${path}/.pnp/unplugged/various-requires-1.0.0/node_modules/various-requires/alternative-index.js`, `module.exports = "6 * 9";\n`); - await expect(source(`require('various-requires/relative-require')`)).resolves.toMatch('6 * 9'); + + const listing = await fs.readdir(`${path}/.pnp/unplugged`); + expect(listing).toHaveLength(1); + + await writeFile( + `${path}/.pnp/unplugged/${listing[0]}/node_modules/various-requires/alternative-index.js`, + `module.exports = "unplugged";\n`, + ); + + await expect(source(`require('various-requires/relative-require')`)).resolves.toMatch('unplugged'); await expect(source(`require('no-deps/package.json')`)).resolves.toMatchObject({ name: `no-deps`, version: `1.0.0`, }); - expect(await fs.readdir(`${path}/.pnp/unplugged`)).toEqual([ - 'various-requires-1.0.0' - ]); }, ), ); @@ -892,15 +897,20 @@ module.exports = makeTemporaryEnv => { }, async ({path, run, source}) => { await run(`unplug`, `various-requires`); - await writeFile(`${path}/.pnp/unplugged/various-requires-1.0.0/node_modules/various-requires/alternative-index.js`, `module.exports = "6 * 9";\n`); - await expect(source(`require('various-requires/relative-require')`)).resolves.toMatch('6 * 9'); + + const listing = await fs.readdir(`${path}/.pnp/unplugged`); + expect(listing).toHaveLength(1); + + await writeFile( + `${path}/.pnp/unplugged/${listing[0]}/node_modules/various-requires/alternative-index.js`, + `module.exports = "unplugged";\n`, + ); + + await expect(source(`require('various-requires/relative-require')`)).resolves.toMatch('unplugged'); await expect(source(`require('no-deps/package.json')`)).resolves.toMatchObject({ name: `no-deps`, version: `1.0.0`, }); - expect(await fs.readdir(`${path}/.pnp/unplugged`)).toEqual([ - 'various-requires-1.0.0' - ]); }, ), ); @@ -959,9 +969,8 @@ module.exports = makeTemporaryEnv => { async ({path, run, source}) => { await run(`install`); await run(`unplug`, `various-requires`, `no-deps`); - expect((await fs.readdir(`${path}/.pnp/unplugged`)).sort()).toEqual( - ['no-deps-1.0.0', 'no-deps-2.0.0', 'various-requires-1.0.0'].sort(), - ); + + await expect(fs.readdir(`${path}/.pnp/unplugged`)).resolves.toHaveLength(3); }, ), ); @@ -982,10 +991,8 @@ module.exports = makeTemporaryEnv => { async ({path, run, source}) => { await run(`install`); await run(`unplug`, `various-requires`, `no-deps@^1.0.0`); - expect((await fs.readdir(`${path}/.pnp/unplugged`)).sort()).toEqual([ - 'no-deps-1.0.0', - 'various-requires-1.0.0', - ].sort()); + + await expect(fs.readdir(`${path}/.pnp/unplugged`)).resolves.toHaveLength(2); }, ), ); @@ -1049,10 +1056,10 @@ module.exports = makeTemporaryEnv => { }); }, ), - ) + ); test( - `it should clear previous unplugged folder on new pnp install`, + `it shouldn't clear the unplugged folder when running an install`, makeTemporaryEnv( { dependencies: { @@ -1066,13 +1073,14 @@ module.exports = makeTemporaryEnv => { async ({path, run, source}) => { await run(`unplug`, `various-requires`); await run(`install`); - expect(await fs.readdir(`${path}/.pnp/unplugged`)).toEqual([]); + + await expect(fs.readdir(`${path}/.pnp/unplugged`)).resolves.toHaveLength(1); }, ), ); test( - `it should clear previous unplugged folder on new eject`, + `it shouldn't clear the unplugged folder when ejecting new packages`, makeTemporaryEnv( { dependencies: { @@ -1086,9 +1094,53 @@ module.exports = makeTemporaryEnv => { async ({path, run, source}) => { await run(`unplug`, `various-requires`); await run(`unplug`, `no-deps`); - expect(await fs.readdir(`${path}/.pnp/unplugged`)).toEqual([ - 'no-deps-1.0.0' - ]); + + await expect(fs.readdir(`${path}/.pnp/unplugged`)).resolves.toHaveLength(2); + }, + ), + ); + + test( + `it should clear the specified packages when using --clear`, + makeTemporaryEnv( + { + dependencies: { + [`no-deps`]: `1.0.0`, + [`various-requires`]: `1.0.0`, + }, + }, + { + plugNPlay: true, + }, + async ({path, run, source}) => { + await run(`unplug`, `various-requires`); + + await expect(fs.readdir(`${path}/.pnp/unplugged`)).resolves.toHaveLength(1); + + await run(`unplug`, `various-requires`, `--clear`); + + await expect(fs.exists(`${path}/.pnp/unplugged`)).resolves.toEqual(false); + }, + ), + ); + + test( + `it should clear the whole unplugged folder when using unplug --clear-all`, + makeTemporaryEnv( + { + dependencies: { + [`no-deps`]: `1.0.0`, + [`various-requires`]: `1.0.0`, + }, + }, + { + plugNPlay: true, + }, + async ({path, run, source}) => { + await run(`unplug`, `various-requires`); + await run(`unplug`, `--clear-all`); + + await expect(fs.exists(`${path}/.pnp/unplugged`)).resolves.toEqual(false); }, ), ); @@ -1108,17 +1160,22 @@ module.exports = makeTemporaryEnv => { async ({path, run, source}) => { await run(`install`); await run(`unplug`, `various-requires`); - await writeFile(`${path}/.pnp/unplugged/various-requires-1.0.0/node_modules/various-requires/alternative-index.js`, `module.exports = "6 * 9";\n`); + + const listing = await fs.readdir(`${path}/.pnp/unplugged`); + expect(listing).toHaveLength(1); + + await writeFile( + `${path}/.pnp/unplugged/${listing[0]}/node_modules/various-requires/alternative-index.js`, + `module.exports = "unplugged";\n`, + ); + await run(`unplug`, `various-requires`, `no-deps`); - await expect(source(`require('various-requires/relative-require')`)).resolves.toMatch('6 * 9'); + + await expect(source(`require('various-requires/relative-require')`)).resolves.toMatch('unplugged'); await expect(source(`require('no-deps/package.json')`)).resolves.toMatchObject({ name: `no-deps`, version: `1.0.0`, }); - expect(await fs.readdir(`${path}/.pnp/unplugged`)).toEqual([ - 'no-deps-1.0.0', - 'various-requires-1.0.0', - ]); }, ), ); diff --git a/packages/pkg-tests/yarn.test.js b/packages/pkg-tests/yarn.test.js index 96d88c02f7..d3727b592f 100644 --- a/packages/pkg-tests/yarn.test.js +++ b/packages/pkg-tests/yarn.test.js @@ -17,11 +17,11 @@ const { } = require(`pkg-tests-specs`); const pkgDriver = generatePkgDriver({ - runDriver: ( + async runDriver( path, [command, ...args], {cwd, projectFolder, registryUrl, plugNPlay, plugnplayShebang, plugnplayBlacklist}, - ) => { + ) { let beforeArgs = []; let middleArgs = []; @@ -33,7 +33,7 @@ const pkgDriver = generatePkgDriver({ middleArgs = [...middleArgs, `--cache-folder`, `${path}/.cache`]; } - return execFile( + const res = await execFile( process.execPath, [`${process.cwd()}/../../bin/yarn.js`, ...beforeArgs, command, ...middleArgs, ...args], { @@ -52,6 +52,15 @@ const pkgDriver = generatePkgDriver({ cwd: cwd || path, }, ); + + if (process.env.JEST_LOG_SPAWNS) { + console.log(`===== stdout:`); + console.log(res.stdout); + console.log(`===== stderr:`); + console.log(res.stderr); + } + + return res; }, }); diff --git a/src/cli/commands/unplug.js b/src/cli/commands/unplug.js index 197777fe30..0f62eb22bf 100644 --- a/src/cli/commands/unplug.js +++ b/src/cli/commands/unplug.js @@ -5,22 +5,9 @@ import type Config from '../../config.js'; import Lockfile from '../../lockfile'; import {wrapLifecycle, Install} from './install.js'; import {MessageError} from '../../errors.js'; +import * as fs from '../../util/fs.js'; -export class Unplug extends Install { - constructor(args: Array, flags: Object, config: Config, reporter: Reporter, lockfile: Lockfile) { - const workspaceRootIsCwd = config.cwd === config.lockfileFolder; - const _flags = flags ? {...flags, workspaceRootIsCwd} : {workspaceRootIsCwd}; - config.plugnplayEjected = args; - super(_flags, config, reporter, lockfile); - } - - init(): Promise> { - if (!this.config.plugnplayEnabled) { - throw new MessageError(this.reporter.lang('unplugPlugnplayDisabled')); - } - return Install.prototype.init.call(this); - } -} +const path = require('path'); export function hasWrapper(commander: Object): boolean { return true; @@ -31,15 +18,57 @@ export function setFlags(commander: Object) { 'Temporarily copies a package (with an optional @range suffix) outside of the global cache for debugging purposes', ); commander.usage('unplug [packages ...] [flags]'); + commander.option('--clear', 'Delete the selected packages'); + commander.option('--clear-all', 'Delete all unplugged packages'); } export async function run(config: Config, reporter: Reporter, flags: Object, args: Array): Promise { - if (!args.length) { + if (!config.plugnplayEnabled) { + throw new MessageError(reporter.lang('unplugDisabled')); + } + if (!args.length && !flags.clearAll) { throw new MessageError(reporter.lang('tooFewArguments', 1)); } - const lockfile = await Lockfile.fromDirectory(config.lockfileFolder, reporter); - await wrapLifecycle(config, flags, async () => { - const install = new Unplug(args, flags, config, reporter, lockfile); - await install.init(); - }); + if (args.length && flags.clearAll) { + throw new MessageError(reporter.lang('noArguments')); + } + + if (flags.clearAll) { + await clearAll(config); + } else if (flags.clear) { + await clearSome(config, new Set(args)); + } else { + const lockfile = await Lockfile.fromDirectory(config.lockfileFolder, reporter); + await wrapLifecycle(config, flags, async () => { + const install = new Install(flags, config, reporter, lockfile); + install.linker.unplugged = args; + await install.init(); + }); + } +} + +export async function clearSome(config: Config, filters: Set): Promise { + const unpluggedPackageFolders = await config.listUnpluggedPackageFolders(); + const removeList = []; + + for (const [unpluggedName, target] of unpluggedPackageFolders.entries()) { + const {name} = await fs.readJson(path.join(target, 'package.json')); + const toBeRemoved = filters.has(name); + + if (toBeRemoved) { + removeList.push(path.join(config.getUnpluggedPath(), unpluggedName)); + } + } + + if (removeList === unpluggedPackageFolders.size) { + await fs.unlink(config.getUnpluggedPath()); + } else { + for (const unpluggedPackagePath of removeList) { + await fs.unlink(unpluggedPackagePath); + } + } +} + +export async function clearAll(config: Config): Promise { + await fs.unlink(config.getUnpluggedPath()); } diff --git a/src/config.js b/src/config.js index bb2556ca4f..5e7666bff8 100644 --- a/src/config.js +++ b/src/config.js @@ -175,6 +175,7 @@ export default class Config { plugnplayShebang: ?string; plugnplayBlacklist: ?string; plugnplayEjected: Array; + plugnplayPurgeEjectedPackages: boolean; scriptsPrependNodePath: boolean; @@ -460,6 +461,7 @@ export default class Config { this.binLinks = !!opts.binLinks; this.updateChecksums = !!opts.updateChecksums; this.plugnplayEjected = []; + this.plugnplayPurgeEjectedPackages = false; this.ignorePlatform = !!opts.ignorePlatform; this.ignoreScripts = !!opts.ignoreScripts; @@ -485,13 +487,10 @@ export default class Config { } /** - * Generate an absolute module path. + * Generate a name suitable as unique filesystem identifier for the specified package. */ - generateModuleCachePath(pkg: ?PackageReference): string { - invariant(this.cacheFolder, 'No package root'); - invariant(pkg, 'Undefined package'); - + generateStablePackageName(pkg: PackageReference): string { let slug = pkg.name; slug = slug.replace(/[^@a-z0-9]+/g, '-'); @@ -515,7 +514,52 @@ export default class Config { slug += `-${hash}`; } - return path.join(this.cacheFolder, slug, `node_modules`, pkg.name); + return slug; + } + + /** + * Generate an absolute module path. + */ + + generateModuleCachePath(pkg: ?PackageReference): string { + invariant(this.cacheFolder, 'No package root'); + invariant(pkg, 'Undefined package'); + + const name = this.generateStablePackageName(pkg); + return path.join(this.cacheFolder, name, 'node_modules', pkg.name); + } + + /** + */ + + getUnpluggedPath(): string { + return path.join(this.lockfileFolder, '.pnp', 'unplugged'); + } + + /** + */ + + generatePackageUnpluggedPath(pkg: PackageReference): string { + const name = this.generateStablePackageName(pkg); + return path.join(this.getUnpluggedPath(), name, 'node_modules', pkg.name); + } + + /** + */ + + async listUnpluggedPackageFolders(): Promise> { + const unpluggedPackages = new Map(); + const unpluggedPath = this.getUnpluggedPath(); + + for (const unpluggedName of await fs.readdir(unpluggedPath)) { + const nmListing = await fs.readdir(path.join(unpluggedPath, unpluggedName, 'node_modules')); + invariant(nmListing.length === 1, 'A single folder should be in the unplugged directory'); + + const target = path.join(unpluggedPath, unpluggedName, `node_modules`, nmListing[0]); + unpluggedPackages.set(unpluggedName, target); + } + + return unpluggedPackages; } /** diff --git a/src/package-linker.js b/src/package-linker.js index 52f46d990c..deb62abbd2 100644 --- a/src/package-linker.js +++ b/src/package-linker.js @@ -1,6 +1,7 @@ /* @flow */ import type {Manifest} from './types.js'; +import type PackageReference from './package-reference.js'; import type PackageResolver from './package-resolver.js'; import type {Reporter} from './reporters/index.js'; import type Config from './config.js'; @@ -51,7 +52,7 @@ export default class PackageLinker { this.config = config; this.artifacts = {}; this.topLevelBinLinking = true; - this._alreadyEjected = new Set(); + this.unplugged = []; } artifacts: InstallArtifacts; @@ -59,8 +60,8 @@ export default class PackageLinker { resolver: PackageResolver; config: Config; topLevelBinLinking: boolean; + unplugged: Array; _treeHash: ?Map; - _alreadyEjected: Set; setArtifacts(artifacts: InstallArtifacts) { this.artifacts = artifacts; @@ -277,16 +278,11 @@ export default class PackageLinker { if (this.config.plugnplayEnabled) { ref.isPlugnplay = true; - if (this._isEjected(ref.name, ref.version)) { - dest = path.resolve( - this.config.lockfileFolder, - '.pnp', - 'unplugged', - `${pkg.name}-${pkg.version}`, - 'node_modules', - pkg.name, - ); - if (this._alreadyEjected.has(`${pkg.name}-${pkg.version}`)) { + if (await this._isUnplugged(ref)) { + dest = this.config.generatePackageUnpluggedPath(ref); + + // We don't skip the copy if the unplugged package isn't materialized yet + if (await fs.exists(dest)) { ref.addLocation(dest); continue; } @@ -666,26 +662,6 @@ export default class PackageLinker { } } - async delPrevEjectedModules(): Promise { - try { - const ejectedPath = `${this.config.lockfileFolder}/.pnp/unplugged`; - for (const currentlyEjectedPkg of await fs.readdir(ejectedPath)) { - const pkgName = currentlyEjectedPkg.split('-').slice(0, -1).join('-'); - const pkgVersion = currentlyEjectedPkg.split('-').pop(); - // eg. foo-bar-baz-1.5.2 (pkgName: foo-bar-baz, pkgVersion: 1.5.2) - if (this._isEjected(pkgName, pkgVersion)) { - this._alreadyEjected.add(currentlyEjectedPkg); - } else { - await fs.unlink(path.join(ejectedPath, currentlyEjectedPkg)); - } - } - } catch (err) { - if (err.code !== 'ENOENT') { - throw err; - } - } - } - _satisfiesPeerDependency(range: string, version: string): boolean { return range === '*' || satisfiesWithPrereleases(version, range, this.config.looseSemver); } @@ -707,13 +683,17 @@ export default class PackageLinker { } } - _isEjected(pkgName: string, pkgVersion: string): boolean { - // ejected module: temporarily (until next install) run a copy of this module from outside the global cache - // for debugging purposes - return this.config.plugnplayEjected.some(patternToEject => { + async _isUnplugged(ref: PackageReference): Promise { + // If an unplugged folder exists for the specified package, we simply use it + if (await fs.exists(this.config.generatePackageUnpluggedPath(ref))) { + return true; + } + + // Check whether the user explicitly requested for the package to be unplugged + return this.unplugged.some(patternToEject => { const {name, range, hasVersion} = normalizePattern(patternToEject); - const satisfiesSemver = hasVersion ? semver.satisfies(pkgVersion, range) : true; - return name === pkgName && satisfiesSemver; + const satisfiesSemver = hasVersion ? semver.satisfies(ref.version, range) : true; + return name === ref.name && satisfiesSemver; }); } @@ -723,7 +703,6 @@ export default class PackageLinker { {linkDuplicates, ignoreOptional}: {linkDuplicates: ?boolean, ignoreOptional: ?boolean} = {}, ): Promise { this.resolvePeerModules(); - await this.delPrevEjectedModules(); await this.copyModules(patterns, workspaceLayout, {linkDuplicates, ignoreOptional}); if (!this.config.plugnplayEnabled) { diff --git a/src/reporters/lang/en.js b/src/reporters/lang/en.js index 3a60f49940..eb977cab25 100644 --- a/src/reporters/lang/en.js +++ b/src/reporters/lang/en.js @@ -355,7 +355,7 @@ const messages = { downloadGitWithoutCommit: 'Downloading the git repo $0 over plain git without a commit hash', downloadHTTPWithoutCommit: 'Downloading the git repo $0 over HTTP without a commit hash', - unplugPlugnplayDisabled: "Packages can only be unplugged when Plug'n'Play is enabled.", + unplugDisabled: "Packages can only be unplugged when Plug'n'Play is enabled.", packageInstalledWithBinaries: 'Installed $0 with binaries:', packageHasBinaries: '$0 has binaries:', From f1c8a1b6f059b6bdc8ba9ba8293bc88c9fe641ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Mon, 10 Sep 2018 14:23:10 +0100 Subject: [PATCH 096/111] Removes packageMainEntry from the package information --- src/util/generate-pnp-map.js | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/util/generate-pnp-map.js b/src/util/generate-pnp-map.js index 12ef063e23..982b0b6ce7 100644 --- a/src/util/generate-pnp-map.js +++ b/src/util/generate-pnp-map.js @@ -15,7 +15,6 @@ const OFFLINE_CACHE_EXTENSION = `.zip`; type PackageInformation = {| packageLocation: string, - packageMainEntry: ?string, packageDependencies: Map, |}; @@ -36,15 +35,9 @@ function generateMaps(packageInformationStores: PackageInformationStores, blackl code += `let packageInformationStores = new Map([\n`; for (const [packageName, packageInformationStore] of packageInformationStores) { code += ` [${JSON.stringify(packageName)}, new Map([\n`; - for (const [ - packageReference, - {packageMainEntry, packageLocation, packageDependencies}, - ] of packageInformationStore) { + for (const [packageReference, {packageLocation, packageDependencies}] of packageInformationStore) { code += ` [${JSON.stringify(packageReference)}, {\n`; code += ` packageLocation: ${JSON.stringify(packageLocation)},\n`; - if (packageMainEntry) { - code += ` packageMainEntry: ${JSON.stringify(packageMainEntry)},\n`; - } code += ` packageDependencies: new Map([\n`; for (const [dependencyName, dependencyReference] of packageDependencies.entries()) { code += ` [${JSON.stringify(dependencyName)}, ${JSON.stringify(dependencyReference)}],\n`; @@ -333,7 +326,6 @@ async function getPackageInformationStores( } packageInformation = { - packageMainEntry: pkg.main, packageLocation: normalizeDirectoryPath(loc), packageDependencies: new Map(), }; @@ -396,7 +388,6 @@ async function getPackageInformationStores( } packageInformationStore.set(pkg.version, { - packageMainEntry: pkg.main, packageLocation: normalizeDirectoryPath(loc), packageDependencies: await visit(ref.dependencies, [name, pkg.version]), }); @@ -411,7 +402,6 @@ async function getPackageInformationStores( [ null, { - packageMainEntry: null, packageLocation: normalizeDirectoryPath(config.lockfileFolder), packageDependencies: await visit(seedPatterns), }, From d78961c0c49541915fc6b6551fe5bd6250084c4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Mon, 10 Sep 2018 16:16:53 +0100 Subject: [PATCH 097/111] Makes "unplug" print the list of unplugged packages --- .../pkg-tests/pkg-tests-specs/sources/pnp.js | 20 ------------------- src/cli/commands/unplug.js | 12 ++++++++--- src/config.js | 4 ++++ yarn.lock | 7 ++++++- 4 files changed, 19 insertions(+), 24 deletions(-) diff --git a/packages/pkg-tests/pkg-tests-specs/sources/pnp.js b/packages/pkg-tests/pkg-tests-specs/sources/pnp.js index 34dac1cebb..0fcc05d8ef 100644 --- a/packages/pkg-tests/pkg-tests-specs/sources/pnp.js +++ b/packages/pkg-tests/pkg-tests-specs/sources/pnp.js @@ -933,26 +933,6 @@ module.exports = makeTemporaryEnv => { ), ); - test( - 'it should produce an error if unplugging with no packages in args', - makeTemporaryEnv( - { - dependencies: { - [`no-deps`]: `1.0.0`, - [`various-requires`]: `1.0.0`, - }, - }, - { - plugNPlay: true, - }, - async ({path, run, source}) => { - await expect(run(`unplug`)).rejects.toMatchObject({ - message: expect.stringContaining(`Not enough arguments, expected at least 1.`), - }); - }, - ), - ); - test( `it should allow unplugging multiple (deep) packages from a pnp installation`, makeTemporaryEnv( diff --git a/src/cli/commands/unplug.js b/src/cli/commands/unplug.js index 0f62eb22bf..34381a9526 100644 --- a/src/cli/commands/unplug.js +++ b/src/cli/commands/unplug.js @@ -26,7 +26,7 @@ export async function run(config: Config, reporter: Reporter, flags: Object, arg if (!config.plugnplayEnabled) { throw new MessageError(reporter.lang('unplugDisabled')); } - if (!args.length && !flags.clearAll) { + if (!args.length && flags.clear) { throw new MessageError(reporter.lang('tooFewArguments', 1)); } if (args.length && flags.clearAll) { @@ -37,7 +37,7 @@ export async function run(config: Config, reporter: Reporter, flags: Object, arg await clearAll(config); } else if (flags.clear) { await clearSome(config, new Set(args)); - } else { + } else if (args.length > 0) { const lockfile = await Lockfile.fromDirectory(config.lockfileFolder, reporter); await wrapLifecycle(config, flags, async () => { const install = new Install(flags, config, reporter, lockfile); @@ -45,6 +45,12 @@ export async function run(config: Config, reporter: Reporter, flags: Object, arg await install.init(); }); } + + const unpluggedPackageFolders = await config.listUnpluggedPackageFolders(); + + for (const target of unpluggedPackageFolders.values()) { + reporter.log(target, {force: true}); + } } export async function clearSome(config: Config, filters: Set): Promise { @@ -60,7 +66,7 @@ export async function clearSome(config: Config, filters: Set): Promise Date: Fri, 14 Sep 2018 13:24:34 +0100 Subject: [PATCH 098/111] Unplugs postinstall packages automatically --- .../packages/no-deps-scripted-1.0.0/log.js | 1 + .../no-deps-scripted-1.0.0/package.json | 6 +- .../pkg-tests/pkg-tests-specs/package.json | 1 + .../pkg-tests/pkg-tests-specs/sources/pnp.js | 92 ++++++++++++++----- .../pkg-tests-specs/sources/script.js | 9 ++ src/package-linker.js | 9 +- 6 files changed, 91 insertions(+), 27 deletions(-) create mode 100644 packages/pkg-tests/pkg-tests-fixtures/packages/no-deps-scripted-1.0.0/log.js diff --git a/packages/pkg-tests/pkg-tests-fixtures/packages/no-deps-scripted-1.0.0/log.js b/packages/pkg-tests/pkg-tests-fixtures/packages/no-deps-scripted-1.0.0/log.js new file mode 100644 index 0000000000..e0a30c5dfa --- /dev/null +++ b/packages/pkg-tests/pkg-tests-fixtures/packages/no-deps-scripted-1.0.0/log.js @@ -0,0 +1 @@ +module.exports = []; diff --git a/packages/pkg-tests/pkg-tests-fixtures/packages/no-deps-scripted-1.0.0/package.json b/packages/pkg-tests/pkg-tests-fixtures/packages/no-deps-scripted-1.0.0/package.json index 327c56811d..621284f505 100644 --- a/packages/pkg-tests/pkg-tests-fixtures/packages/no-deps-scripted-1.0.0/package.json +++ b/packages/pkg-tests/pkg-tests-fixtures/packages/no-deps-scripted-1.0.0/package.json @@ -2,8 +2,8 @@ "name": "no-deps-scripted", "version": "1.0.0", "scripts": { - "preinstall": "echo preinstall >> log", - "install": "echo install >> log", - "postinstall": "echo postinstall >> log" + "preinstall": "echo 'module.exports.push(100);' >> log.js", + "install": "echo 'module.exports.push(200);' >> log.js", + "postinstall": "echo 'module.exports.push(300);' >> log.js; echo 'module.exports = '\"$RANDOM\"';' > rnd.js" } } diff --git a/packages/pkg-tests/pkg-tests-specs/package.json b/packages/pkg-tests/pkg-tests-specs/package.json index 1967b62856..5ef9b6ab96 100644 --- a/packages/pkg-tests/pkg-tests-specs/package.json +++ b/packages/pkg-tests/pkg-tests-specs/package.json @@ -3,6 +3,7 @@ "version": "1.0.0", "main": "./sources/index.js", "dependencies": { + "fs-extra": "^7.0.0", "pkg-tests-core": "1.0.0" } } diff --git a/packages/pkg-tests/pkg-tests-specs/sources/pnp.js b/packages/pkg-tests/pkg-tests-specs/sources/pnp.js index 0fcc05d8ef..d2c2271775 100644 --- a/packages/pkg-tests/pkg-tests-specs/sources/pnp.js +++ b/packages/pkg-tests/pkg-tests-specs/sources/pnp.js @@ -1,5 +1,6 @@ const cp = require('child_process'); -const fs = require('fs-extra'); +const {existsSync, statSync, stat, rename, readdir, remove} = require('fs-extra'); +const {relative, isAbsolute} = require('path'); const { fs: {createTemporaryFolder, readFile, readJson, writeFile, writeJson}, @@ -44,7 +45,7 @@ module.exports = makeTemporaryEnv => { makeTemporaryEnv({}, {plugNPlay: false}, async ({path, run, source}) => { await run(`install`); - expect(fs.existsSync(`${path}/.pnp.js`)).toEqual(false); + expect(existsSync(`${path}/.pnp.js`)).toEqual(false); }), ); @@ -58,14 +59,14 @@ module.exports = makeTemporaryEnv => { async ({path, run, source}) => { await run(`install`); - const beforeTime = (await fs.stat(`${path}/.pnp.js`)).mtimeMs; + const beforeTime = (await stat(`${path}/.pnp.js`)).mtimeMs; // Need to wait two seconds to be sure that the mtime will change await new Promise(resolve => setTimeout(resolve, 2000)); await run(`install`); - const afterTime = (await fs.stat(`${path}/.pnp.js`)).mtimeMs; + const afterTime = (await stat(`${path}/.pnp.js`)).mtimeMs; expect(afterTime).toEqual(beforeTime); }, @@ -82,7 +83,7 @@ module.exports = makeTemporaryEnv => { async ({path, run, source}) => { await run(`install`); - const beforeTime = (await fs.stat(`${path}/.pnp.js`)).mtimeMs; + const beforeTime = (await stat(`${path}/.pnp.js`)).mtimeMs; await writeJson(`${path}/package.json`, { dependencies: { @@ -95,7 +96,7 @@ module.exports = makeTemporaryEnv => { await run(`install`); - const afterTime = (await fs.stat(`${path}/.pnp.js`)).mtimeMs; + const afterTime = (await stat(`${path}/.pnp.js`)).mtimeMs; expect(afterTime).not.toEqual(beforeTime); }, @@ -557,7 +558,7 @@ module.exports = makeTemporaryEnv => { async ({path, run, source}) => { await run(`install`); - expect(fs.existsSync(`${path}/.pnp.js`)).toEqual(true); + expect(existsSync(`${path}/.pnp.js`)).toEqual(true); }, ), ); @@ -604,7 +605,7 @@ module.exports = makeTemporaryEnv => { async ({path, run, source}) => { await run(`install`); - expect(fs.statSync(`${path}/.pnp.js`).mode & 0o111).toEqual(0o111); + expect(statSync(`${path}/.pnp.js`).mode & 0o111).toEqual(0o111); const result = JSON.parse(cp.execFileSync(`${path}/.pnp.js`, [`no-deps`, `${path}/`], {encoding: `utf-8`})); @@ -633,7 +634,7 @@ module.exports = makeTemporaryEnv => { async ({path, run, source}) => { await run(`install`); - expect(fs.statSync(`${path}/.pnp.js`).mode & 0o111).toEqual(0o111); + expect(statSync(`${path}/.pnp.js`).mode & 0o111).toEqual(0o111); const result = JSON.parse(cp.execFileSync(`${path}/.pnp.js`, [`fs`, `${path}/`], {encoding: `utf-8`})); @@ -657,7 +658,7 @@ module.exports = makeTemporaryEnv => { async ({path, run, source}) => { await run(`install`); - expect(fs.statSync(`${path}/.pnp.js`).mode & 0o111).toEqual(0o111); + expect(statSync(`${path}/.pnp.js`).mode & 0o111).toEqual(0o111); const result = JSON.parse( cp.execFileSync(`${path}/.pnp.js`, [`doesnt-exists`, `${path}/`], {encoding: `utf-8`}), @@ -802,8 +803,8 @@ module.exports = makeTemporaryEnv => { async ({path: path2, run: run2, source: source2}) => { // Move the install artifacts into a new location // If the .pnp.js file references absolute paths, they will stop working - await fs.rename(`${path}/.cache`, `${path2}/.cache`); - await fs.rename(`${path}/.pnp.js`, `${path2}/.pnp.js`); + await rename(`${path}/.cache`, `${path2}/.cache`); + await rename(`${path}/.pnp.js`, `${path2}/.pnp.js`); await expect(source2(`require('no-deps')`)).resolves.toMatchObject({ name: `no-deps`, @@ -866,7 +867,7 @@ module.exports = makeTemporaryEnv => { await run(`install`); await run(`unplug`, `various-requires`); - const listing = await fs.readdir(`${path}/.pnp/unplugged`); + const listing = await readdir(`${path}/.pnp/unplugged`); expect(listing).toHaveLength(1); await writeFile( @@ -898,7 +899,7 @@ module.exports = makeTemporaryEnv => { async ({path, run, source}) => { await run(`unplug`, `various-requires`); - const listing = await fs.readdir(`${path}/.pnp/unplugged`); + const listing = await readdir(`${path}/.pnp/unplugged`); expect(listing).toHaveLength(1); await writeFile( @@ -950,7 +951,7 @@ module.exports = makeTemporaryEnv => { await run(`install`); await run(`unplug`, `various-requires`, `no-deps`); - await expect(fs.readdir(`${path}/.pnp/unplugged`)).resolves.toHaveLength(3); + await expect(readdir(`${path}/.pnp/unplugged`)).resolves.toHaveLength(3); }, ), ); @@ -972,7 +973,7 @@ module.exports = makeTemporaryEnv => { await run(`install`); await run(`unplug`, `various-requires`, `no-deps@^1.0.0`); - await expect(fs.readdir(`${path}/.pnp/unplugged`)).resolves.toHaveLength(2); + await expect(readdir(`${path}/.pnp/unplugged`)).resolves.toHaveLength(2); }, ), ); @@ -1054,7 +1055,7 @@ module.exports = makeTemporaryEnv => { await run(`unplug`, `various-requires`); await run(`install`); - await expect(fs.readdir(`${path}/.pnp/unplugged`)).resolves.toHaveLength(1); + await expect(readdir(`${path}/.pnp/unplugged`)).resolves.toHaveLength(1); }, ), ); @@ -1075,7 +1076,7 @@ module.exports = makeTemporaryEnv => { await run(`unplug`, `various-requires`); await run(`unplug`, `no-deps`); - await expect(fs.readdir(`${path}/.pnp/unplugged`)).resolves.toHaveLength(2); + await expect(readdir(`${path}/.pnp/unplugged`)).resolves.toHaveLength(2); }, ), ); @@ -1095,11 +1096,11 @@ module.exports = makeTemporaryEnv => { async ({path, run, source}) => { await run(`unplug`, `various-requires`); - await expect(fs.readdir(`${path}/.pnp/unplugged`)).resolves.toHaveLength(1); + await expect(readdir(`${path}/.pnp/unplugged`)).resolves.toHaveLength(1); await run(`unplug`, `various-requires`, `--clear`); - await expect(fs.exists(`${path}/.pnp/unplugged`)).resolves.toEqual(false); + expect(existsSync(`${path}/.pnp/unplugged`)).toEqual(false); }, ), ); @@ -1120,7 +1121,7 @@ module.exports = makeTemporaryEnv => { await run(`unplug`, `various-requires`); await run(`unplug`, `--clear-all`); - await expect(fs.exists(`${path}/.pnp/unplugged`)).resolves.toEqual(false); + expect(existsSync(`${path}/.pnp/unplugged`)).toEqual(false); }, ), ); @@ -1141,7 +1142,7 @@ module.exports = makeTemporaryEnv => { await run(`install`); await run(`unplug`, `various-requires`); - const listing = await fs.readdir(`${path}/.pnp/unplugged`); + const listing = await readdir(`${path}/.pnp/unplugged`); expect(listing).toHaveLength(1); await writeFile( @@ -1159,5 +1160,52 @@ module.exports = makeTemporaryEnv => { }, ), ); + + test( + `it should automatically eject packages with postinstall scripts`, + makeTemporaryEnv( + { + dependencies: {[`no-deps-scripted`]: `1.0.0`}, + }, + {plugNPlay: true}, + async ({path, run, source}) => { + await run(`install`); + + const resolution = await source(`require.resolve('no-deps-scripted')`); + const cacheRelativeResolution = relative(`${path}/.cache`, resolution); + + expect( + cacheRelativeResolution && + !cacheRelativeResolution.startsWith(`..${path.sep}`) && + !isAbsolute(cacheRelativeResolution), + ); + }, + ), + ); + + test( + `it should not cache the postinstall artifacts`, + makeTemporaryEnv( + { + dependencies: {[`no-deps-scripted`]: `1.0.0`}, + }, + {plugNPlay: true}, + async ({path, run, source}) => { + await run(`install`); + + const rndBefore = await source(`require('no-deps-scripted/rnd.js')`); + + await remove(`${path}/.pnp`); + await remove(`${path}/.pnp.js`); + + await run(`install`); + + const rndAfter = await source(`require('no-deps-scripted/rnd.js')`); + + // It might fail once every blue moon, when the two random numbers are equal + expect(rndAfter).not.toEqual(rndBefore); + }, + ), + ); }); }; diff --git a/packages/pkg-tests/pkg-tests-specs/sources/script.js b/packages/pkg-tests/pkg-tests-specs/sources/script.js index 15beb47201..999d6c452c 100644 --- a/packages/pkg-tests/pkg-tests-specs/sources/script.js +++ b/packages/pkg-tests/pkg-tests-specs/sources/script.js @@ -194,5 +194,14 @@ module.exports = (makeTemporaryEnv: PackageDriver) => { }); }), ); + + test( + `it should run install scripts during the install`, + makeTemporaryEnv({dependencies: {[`no-deps-scripted`]: `1.0.0`}}, async ({path, run, source}) => { + await run(`install`); + + await expect(source(`require('no-deps-scripted/log.js')`)).resolves.toEqual([100, 200, 300]); + }), + ); }); }; diff --git a/src/package-linker.js b/src/package-linker.js index deb62abbd2..de68fa6c0b 100644 --- a/src/package-linker.js +++ b/src/package-linker.js @@ -278,7 +278,7 @@ export default class PackageLinker { if (this.config.plugnplayEnabled) { ref.isPlugnplay = true; - if (await this._isUnplugged(ref)) { + if (await this._isUnplugged(pkg, ref)) { dest = this.config.generatePackageUnpluggedPath(ref); // We don't skip the copy if the unplugged package isn't materialized yet @@ -683,12 +683,17 @@ export default class PackageLinker { } } - async _isUnplugged(ref: PackageReference): Promise { + async _isUnplugged(pkg: Manifest, ref: PackageReference): Promise { // If an unplugged folder exists for the specified package, we simply use it if (await fs.exists(this.config.generatePackageUnpluggedPath(ref))) { return true; } + // If the package has a postinstall script, we also eject it (otherwise they would run into the cache) + if (pkg.scripts && (pkg.scripts.preinstall || pkg.scripts.install || pkg.scripts.postinstall)) { + return true; + } + // Check whether the user explicitly requested for the package to be unplugged return this.unplugged.some(patternToEject => { const {name, range, hasVersion} = normalizePattern(patternToEject); From 41a9743071037277f7da988df30f8200389040f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Mon, 24 Sep 2018 11:35:02 +0100 Subject: [PATCH 099/111] Renames things --- __tests__/commands/install/bin-links.js | 2 +- __tests__/package-resolver.js | 2 +- package.json | 3 --- .../pkg-tests/pkg-tests-specs/sources/pnp.js | 6 +++--- src/config.js | 18 +++++++++--------- src/package-linker.js | 6 +++--- src/util/generate-pnp-map-api.tpl.js | 4 ++-- 7 files changed, 19 insertions(+), 22 deletions(-) diff --git a/__tests__/commands/install/bin-links.js b/__tests__/commands/install/bin-links.js index 4b85e0e25d..851b72f37d 100644 --- a/__tests__/commands/install/bin-links.js +++ b/__tests__/commands/install/bin-links.js @@ -210,7 +210,7 @@ describe('with nohoist', () => { }); describe('with focus', () => { - test.skip('focus points bin links to the shallowly installed packages', (): Promise => { + test('focus points bin links to the shallowly installed packages', (): Promise => { return runInstall( {binLinks: true, focus: true}, {source: 'published-monorepo', cwd: '/packages/example-yarn-workspace-1'}, diff --git a/__tests__/package-resolver.js b/__tests__/package-resolver.js index b188b3637a..269c1b614d 100644 --- a/__tests__/package-resolver.js +++ b/__tests__/package-resolver.js @@ -13,7 +13,7 @@ jasmine.DEFAULT_TIMEOUT_INTERVAL = 90000; const path = require('path'); -// regexp which verifies that cache path contains semver + hash +// regexp which verifies that the cache path contains a path component ending with semver + hash const cachePathRe = /-\d+\.\d+\.\d+-[\dabcdef]{40}[\\\/]/; async function createEnv(configOptions): Object { diff --git a/package.json b/package.json index 549ff63760..520153562c 100644 --- a/package.json +++ b/package.json @@ -150,8 +150,5 @@ "commitizen": { "path": "./node_modules/cz-conventional-changelog" } - }, - "installConfig": { - "pnp": true } } diff --git a/packages/pkg-tests/pkg-tests-specs/sources/pnp.js b/packages/pkg-tests/pkg-tests-specs/sources/pnp.js index d2c2271775..5319d211b9 100644 --- a/packages/pkg-tests/pkg-tests-specs/sources/pnp.js +++ b/packages/pkg-tests/pkg-tests-specs/sources/pnp.js @@ -979,7 +979,7 @@ module.exports = makeTemporaryEnv => { ); test( - 'it should properly eject a package with peer dependencies', + 'it should properly unplug a package with peer dependencies', makeTemporaryEnv( { dependencies: {[`provides-peer-deps-1-0-0`]: `1.0.0`, [`provides-peer-deps-2-0-0`]: `1.0.0`}, @@ -1061,7 +1061,7 @@ module.exports = makeTemporaryEnv => { ); test( - `it shouldn't clear the unplugged folder when ejecting new packages`, + `it shouldn't clear the unplugged folder when unplugging new packages`, makeTemporaryEnv( { dependencies: { @@ -1162,7 +1162,7 @@ module.exports = makeTemporaryEnv => { ); test( - `it should automatically eject packages with postinstall scripts`, + `it should automatically unplug packages with postinstall scripts`, makeTemporaryEnv( { dependencies: {[`no-deps-scripted`]: `1.0.0`}, diff --git a/src/config.js b/src/config.js index f03eefb536..b33bb33185 100644 --- a/src/config.js +++ b/src/config.js @@ -174,8 +174,8 @@ export default class Config { plugnplayEnabled: boolean; plugnplayShebang: ?string; plugnplayBlacklist: ?string; - plugnplayEjected: Array; - plugnplayPurgeEjectedPackages: boolean; + plugnplayUnplugged: Array; + plugnplayPurgeUnpluggedPackages: boolean; scriptsPrependNodePath: boolean; @@ -460,8 +460,8 @@ export default class Config { this.offline = !!opts.offline; this.binLinks = !!opts.binLinks; this.updateChecksums = !!opts.updateChecksums; - this.plugnplayEjected = []; - this.plugnplayPurgeEjectedPackages = false; + this.plugnplayUnplugged = []; + this.plugnplayPurgeUnpluggedPackages = false; this.ignorePlatform = !!opts.ignorePlatform; this.ignoreScripts = !!opts.ignoreScripts; @@ -490,7 +490,7 @@ export default class Config { * Generate a name suitable as unique filesystem identifier for the specified package. */ - generateStablePackageName(pkg: PackageReference): string { + generateUniquePackageSlug(pkg: PackageReference): string { let slug = pkg.name; slug = slug.replace(/[^@a-z0-9]+/g, '-'); @@ -525,8 +525,8 @@ export default class Config { invariant(this.cacheFolder, 'No package root'); invariant(pkg, 'Undefined package'); - const name = this.generateStablePackageName(pkg); - return path.join(this.cacheFolder, name, 'node_modules', pkg.name); + const slug = this.generateUniquePackageSlug(pkg); + return path.join(this.cacheFolder, slug, 'node_modules', pkg.name); } /** @@ -540,8 +540,8 @@ export default class Config { */ generatePackageUnpluggedPath(pkg: PackageReference): string { - const name = this.generateStablePackageName(pkg); - return path.join(this.getUnpluggedPath(), name, 'node_modules', pkg.name); + const slug = this.generateUniquePackageSlug(pkg); + return path.join(this.getUnpluggedPath(), slug, 'node_modules', pkg.name); } /** diff --git a/src/package-linker.js b/src/package-linker.js index de68fa6c0b..c0f69d921a 100644 --- a/src/package-linker.js +++ b/src/package-linker.js @@ -689,14 +689,14 @@ export default class PackageLinker { return true; } - // If the package has a postinstall script, we also eject it (otherwise they would run into the cache) + // If the package has a postinstall script, we also unplug it (otherwise they would run into the cache) if (pkg.scripts && (pkg.scripts.preinstall || pkg.scripts.install || pkg.scripts.postinstall)) { return true; } // Check whether the user explicitly requested for the package to be unplugged - return this.unplugged.some(patternToEject => { - const {name, range, hasVersion} = normalizePattern(patternToEject); + return this.unplugged.some(patternToUnplug => { + const {name, range, hasVersion} = normalizePattern(patternToUnplug); const satisfiesSemver = hasVersion ? semver.satisfies(ref.version, range) : true; return name === ref.name && satisfiesSemver; }); diff --git a/src/util/generate-pnp-map-api.tpl.js b/src/util/generate-pnp-map-api.tpl.js index 64a7ed57ad..f8cc76018b 100644 --- a/src/util/generate-pnp-map-api.tpl.js +++ b/src/util/generate-pnp-map-api.tpl.js @@ -67,7 +67,7 @@ function blacklistCheck(locator) { throw makeError( `BLACKLISTED`, [ - `A package has been resolved through a blacklisted path - this is usually caused by one of your tool calling`, + `A package has been resolved through a blacklisted path - this is usually caused by one of your tools calling`, `"realpath" on the return value of "require.resolve". Since the returned values use symlinks to disambiguate`, `peer dependencies, they must be passed untransformed to "require".`, ].join(` `), @@ -210,7 +210,7 @@ function applyNodeExtensionResolution(unqualifiedPath, {extensions}) { * Ideally it would be nice to be able to avoid this, since it causes useless allocations * and cannot be cached efficiently (we recompute the nodeModulePaths every time). * - * Fortunately, this should only affect the fallback, and there hopefully shouldn't have a + * Fortunately, this should only affect the fallback, and there hopefully shouldn't be a * lot of them. */ From 02bd204397048c08d387e123c00a444b12c3782e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Mon, 24 Sep 2018 11:41:54 +0100 Subject: [PATCH 100/111] Adds a warning on Windows to notify that PnP settings are ignored at the moment --- src/config.js | 13 +++++++++---- src/reporters/lang/en.js | 3 +++ 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/config.js b/src/config.js index b33bb33185..63cb4f62ba 100644 --- a/src/config.js +++ b/src/config.js @@ -381,10 +381,7 @@ export default class Config { const manifest = await this.maybeReadManifest(this.cwd); const plugnplayByEnv = this.getOption('plugnplay-override'); - if (process.platform === 'win32') { - this.plugnplayEnabled = false; - this.plugnplayPersist = false; - } else if (plugnplayByEnv != null) { + if (plugnplayByEnv != null) { this.plugnplayEnabled = plugnplayByEnv !== 'false' && plugnplayByEnv !== '0'; this.plugnplayPersist = false; } else if (opts.enablePnp || opts.disablePnp) { @@ -398,6 +395,14 @@ export default class Config { this.plugnplayEnabled = false; } + if (process.platform === 'win32') { + if (this.plugnplayEnabled) { + this.reporter.warn(this.reporter.lang('plugnplayWindowsSupport')); + } + this.plugnplayEnabled = false; + this.plugnplayPersist = false; + } + this.plugnplayShebang = String(this.getOption('plugnplay-shebang')) || '/usr/bin/env node'; this.plugnplayBlacklist = String(this.getOption('plugnplay-blacklist') || '') || null; diff --git a/src/reporters/lang/en.js b/src/reporters/lang/en.js index eb977cab25..03b4739491 100644 --- a/src/reporters/lang/en.js +++ b/src/reporters/lang/en.js @@ -357,6 +357,9 @@ const messages = { unplugDisabled: "Packages can only be unplugged when Plug'n'Play is enabled.", + plugnplayWindowsSupport: + "Plug'n'Play is ignored on Windows for now - contributions welcome! https://github.com/yarnpkg/yarn/issues/6402", + packageInstalledWithBinaries: 'Installed $0 with binaries:', packageHasBinaries: '$0 has binaries:', packageHasNoBinaries: '$0 has no binaries', From e7c7aa13e16c26b35513d603084927511418ca54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Mon, 24 Sep 2018 11:43:33 +0100 Subject: [PATCH 101/111] Fixes the default shebang --- src/config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config.js b/src/config.js index 63cb4f62ba..4374375b9b 100644 --- a/src/config.js +++ b/src/config.js @@ -403,7 +403,7 @@ export default class Config { this.plugnplayPersist = false; } - this.plugnplayShebang = String(this.getOption('plugnplay-shebang')) || '/usr/bin/env node'; + this.plugnplayShebang = String(this.getOption('plugnplay-shebang') || '') || '/usr/bin/env node'; this.plugnplayBlacklist = String(this.getOption('plugnplay-blacklist') || '') || null; this.workspacesEnabled = this.getOption('workspaces-experimental') !== false; From 7cd35f1ba5eb2ffc69fb4477b02b310ed8306e23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Mon, 24 Sep 2018 12:17:09 +0100 Subject: [PATCH 102/111] Exports pnpapi --- .../pkg-tests/pkg-tests-specs/sources/pnp.js | 15 +++++++++++++++ src/util/generate-pnp-map-api.tpl.js | 16 ++++++++++------ 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/packages/pkg-tests/pkg-tests-specs/sources/pnp.js b/packages/pkg-tests/pkg-tests-specs/sources/pnp.js index 5319d211b9..7ef06f1c84 100644 --- a/packages/pkg-tests/pkg-tests-specs/sources/pnp.js +++ b/packages/pkg-tests/pkg-tests-specs/sources/pnp.js @@ -520,6 +520,21 @@ module.exports = makeTemporaryEnv => { ), ); + test( + `it should export the PnP API through the 'pnpapi' name`, + makeTemporaryEnv( + {dependencies: {[`no-deps`]: `1.0.0`}}, + { + plugNPlay: true, + }, + async ({path, run, source}) => { + await run(`install`); + + await expect(source(`typeof require('pnpapi').VERSIONS.std`)).resolves.toEqual(`number`); + }, + ), + ); + test( `it should not update the installConfig.pnp field of the package.json when installing with an environment override`, makeTemporaryEnv( diff --git a/src/util/generate-pnp-map-api.tpl.js b/src/util/generate-pnp-map-api.tpl.js index f8cc76018b..55013fa9a5 100644 --- a/src/util/generate-pnp-map-api.tpl.js +++ b/src/util/generate-pnp-map-api.tpl.js @@ -25,7 +25,7 @@ const isDirRegExp = /\/$/; const topLevelLocator = {name: null, reference: null}; const blacklistedLocator = {name: NaN, reference: NaN}; -const moduleShims = new Map(); +const pnpModule = module; /** * Used to disable the resolution hooks (for when we want to fallback to the previous resolution - we then need @@ -254,6 +254,12 @@ function callNativeResolution(request, issuer) { exports.VERSIONS = {std: 1}; +/** + * Useful when used together with getPackageInformation to fetch information about the top-level package. + */ + +exports.topLevel = {name: null, reference: null}; + /** * Gets the package information for a given locator. Returns null if they cannot be retrieved. */ @@ -560,12 +566,10 @@ exports.setup = function setup() { } } - // We allow to shim modules, which is useful for packages such as `resolve` - - const shim = moduleShims.get(request); + // The 'pnpapi' name is reserved to return the PnP api currently in use by the program - if (shim) { - return shim; + if (request === `pnpapi`) { + return pnpModule.exports; } // Request `Module._resolveFilename` (ie. `resolveRequest`) to tell us which file we should load From d9a71042ba4bed1793196c6fae9ec70f4cb59814 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Mon, 24 Sep 2018 13:26:16 +0100 Subject: [PATCH 103/111] Reworks the resolve shim to only affect liftoff --- src/util/generate-pnp-map-api.tpl.js | 112 +++++++++++++++++++-------- 1 file changed, 81 insertions(+), 31 deletions(-) diff --git a/src/util/generate-pnp-map-api.tpl.js b/src/util/generate-pnp-map-api.tpl.js index 55013fa9a5..82713aef53 100644 --- a/src/util/generate-pnp-map-api.tpl.js +++ b/src/util/generate-pnp-map-api.tpl.js @@ -11,6 +11,7 @@ const StringDecoder = require('string_decoder'); const ignorePattern = $$BLACKLIST ? new RegExp($$BLACKLIST) : null; const builtinModules = new Set(Module.builtinModules || Object.keys(process.binding('natives'))); +const patchedModules = new Map(); // Splits a require request into its components, or return null if the request is a file path const pathRegExp = /^(?!\.{0,2}(?:\/|$))((?:@[^\/]+\/)?[^\/]+)\/?(.*|)$/; @@ -292,10 +293,10 @@ exports.getPackageInformation = function getPackageInformation({name, reference} * imports won't be computed correctly (they'll get resolved relative to "/tmp/" instead of "/tmp/foo/"). */ -exports.resolveToUnqualified = function resolveToUnqualified(request, issuer) { +exports.resolveToUnqualified = function resolveToUnqualified(request, issuer, {considerBuiltins = true} = {}) { // Bailout if the request is a native module - if (builtinModules.has(request)) { + if (considerBuiltins && builtinModules.has(request)) { return null; } @@ -472,11 +473,11 @@ exports.resolveUnqualified = function resolveUnqualified( * imports won't be computed correctly (they'll get resolved relative to "/tmp/" instead of "/tmp/foo/"). */ -exports.resolveRequest = function resolveRequest(request, issuer, {extensions} = {}) { +exports.resolveRequest = function resolveRequest(request, issuer, {considerBuiltins, extensions} = {}) { let unqualifiedPath; try { - unqualifiedPath = exports.resolveToUnqualified(request, issuer); + unqualifiedPath = exports.resolveToUnqualified(request, issuer, {considerBuiltins}); } catch (originalError) { // If we get a BUILTIN_NODE_RESOLUTION_FAIL error there, it means that we've had to use the builtin node // resolution, which usually shouldn't happen. It might be because the user is trying to require something @@ -609,6 +610,12 @@ exports.setup = function setup() { } } + // Some modules might have to be patched for compatibility purposes + + if (patchedModules.has(request)) { + module.exports = patchedModules.get(request)(module.exports); + } + return module.exports; }; @@ -663,42 +670,85 @@ exports.setupCompatibilityLayer = () => { return stack[2].getFileName(); }; - const resolveSyncShim = (request, options = {}) => { - let basedir = options.basedir || path.dirname(getCaller()); - basedir = basedir.replace(/\/?$/, '/'); + // We need to shim the "resolve" module, because Liftoff uses it in order to find the location + // of the module in the dependency tree. And Liftoff is used to power Gulp, which doesn't work + // at all unless modulePath is set, which we cannot configure from any other way than through + // the Liftoff pipeline (the key isn't whitelisted for env or cli options). - return exports.resolveRequest(request, basedir); - }; + patchedModules.set('resolve', resolve => { + const mustBeShimmed = caller => { + const callerLocator = exports.findPackageLocator(caller); - const resolveShim = (request, options, callback) => { - if (typeof options === 'function') { - callback = options; - options = {}; - } + return callerLocator && callerLocator.name === 'liftoff'; + }; + + const attachCallerToOptions = (caller, options) => { + if (!options.basedir) { + options.basedir = path.dirname(caller); + }; + }; - // We need to compute it here because otherwise resolveSyncShim will read the wrong stacktrace entry - let basedir = options.basedir || path.dirname(getCaller()); - basedir = basedir.replace(/\/?$/, '/'); + const resolveSyncShim = (request, {basedir}) => { + return exports.resolveRequest(request, basedir, { + considerBuiltins: false, + }); + }; - setImmediate(() => { - let error; - let result; + const resolveShim = (request, options, callback) => { + setImmediate(() => { + let error; + let result; - try { - result = resolveShim.sync(request, Object.assign(options, {basedir})); - } catch (thrown) { - error = thrown; + try { + result = resolveSyncShim(request, options); + } catch (thrown) { + error = thrown; + } + + callback(error, result); + }); + }; + + const isCoreShim = request => { + return builtinModules.has(request); + }; + + return Object.assign((request, options, callback) => { + if (typeof options === 'function') { + callback = options; + options = {}; + } else if (!options) { + options = {}; } - callback(error, result); - }); - }; + const caller = getCaller(); + attachCallerToOptions(caller, options); - const isCoreShim = request => { - return builtinModules.has(request); - }; + if (mustBeShimmed(caller)) { + return resolveShim(request, options, callback); + } else { + return realResolve.sync(request, options, callback); + } + }, { + sync: (request, options) => { + if (!options) { + options = {}; + } - moduleShims.set('resolve', Object.assign(resolveShim, {sync: resolveSyncShim, isCore: isCoreShim})); + const caller = getCaller(); + attachCallerToOptions(caller, options); + + if (mustBeShimmed(caller)) { + return resolveSyncShim(request, options); + } else { + return realResolve.sync(request, options); + } + }, + isCore: request => { + return realResolve.isCore(request); + } + }); + }); }; if (module.parent && module.parent.id === 'internal/preload') { From 77ffbbd3aafc83fae1f4303ca18aaaecd0ad152e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Mon, 24 Sep 2018 13:29:43 +0100 Subject: [PATCH 104/111] Guards the pnp file against fs extensions --- src/util/generate-pnp-map-api.tpl.js | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/util/generate-pnp-map-api.tpl.js b/src/util/generate-pnp-map-api.tpl.js index 82713aef53..a8fda40f7a 100644 --- a/src/util/generate-pnp-map-api.tpl.js +++ b/src/util/generate-pnp-map-api.tpl.js @@ -3,7 +3,10 @@ /* eslint-disable max-len, flowtype/require-valid-file-annotation, flowtype/require-return-type */ /* global packageInformationStores, $$BLACKLIST, $$SETUP_STATIC_TABLES */ -const fs = require('fs'); +// Used for the resolveUnqualified part of the resolution (ie resolving folder/index.js & file extensions) +// Deconstructed so that they aren't affected by any fs monkeypatching occuring later during the execution +const {statSync, lstatSync, readlinkSync, readFileSync, existsSync, realpathSync} = require('fs'); + const Module = require('module'); const path = require('path'); const StringDecoder = require('string_decoder'); @@ -122,7 +125,7 @@ function applyNodeExtensionResolution(unqualifiedPath, {extensions}) { let stat; try { - stat = fs.statSync(unqualifiedPath); + stat = statSync(unqualifiedPath); } catch (error) {} // If the file exists and is a file, we can stop right there @@ -140,8 +143,8 @@ function applyNodeExtensionResolution(unqualifiedPath, {extensions}) { // we would lose the information that would tell us what are the dependencies of pkg-with-peers relative to its // ancestors. - if (fs.lstatSync(unqualifiedPath).isSymbolicLink()) { - unqualifiedPath = path.normalize(path.resolve(path.dirname(unqualifiedPath), fs.readlinkSync(unqualifiedPath))); + if (lstatSync(unqualifiedPath).isSymbolicLink()) { + unqualifiedPath = path.normalize(path.resolve(path.dirname(unqualifiedPath), readlinkSync(unqualifiedPath))); } return unqualifiedPath; @@ -153,7 +156,7 @@ function applyNodeExtensionResolution(unqualifiedPath, {extensions}) { let pkgJson; try { - pkgJson = JSON.parse(fs.readFileSync(`${unqualifiedPath}/package.json`, 'utf-8')); + pkgJson = JSON.parse(readFileSync(`${unqualifiedPath}/package.json`, 'utf-8')); } catch (error) {} let nextUnqualifiedPath; @@ -177,7 +180,7 @@ function applyNodeExtensionResolution(unqualifiedPath, {extensions}) { return `${unqualifiedPath}${extension}`; }) .find(candidateFile => { - return fs.existsSync(candidateFile); + return existsSync(candidateFile); }); if (qualifiedPath) { @@ -192,7 +195,7 @@ function applyNodeExtensionResolution(unqualifiedPath, {extensions}) { return `${unqualifiedPath}/index${extension}`; }) .find(candidateFile => { - return fs.existsSync(candidateFile); + return existsSync(candidateFile); }); if (indexPath) { @@ -488,7 +491,7 @@ exports.resolveRequest = function resolveRequest(request, issuer, {considerBuilt let realIssuer; try { - realIssuer = fs.realpathSync(issuer); + realIssuer = realpathSync(issuer); } catch (error) {} if (realIssuer) { From 6309d1f5e0328f09b10233603d115477d8b45d62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Mon, 24 Sep 2018 13:51:45 +0100 Subject: [PATCH 105/111] Fixes the resolve shim --- src/util/generate-pnp-map-api.tpl.js | 61 ++++++++++++++-------------- 1 file changed, 30 insertions(+), 31 deletions(-) diff --git a/src/util/generate-pnp-map-api.tpl.js b/src/util/generate-pnp-map-api.tpl.js index a8fda40f7a..956b8d5c15 100644 --- a/src/util/generate-pnp-map-api.tpl.js +++ b/src/util/generate-pnp-map-api.tpl.js @@ -678,7 +678,7 @@ exports.setupCompatibilityLayer = () => { // at all unless modulePath is set, which we cannot configure from any other way than through // the Liftoff pipeline (the key isn't whitelisted for env or cli options). - patchedModules.set('resolve', resolve => { + patchedModules.set('resolve', realResolve => { const mustBeShimmed = caller => { const callerLocator = exports.findPackageLocator(caller); @@ -688,7 +688,7 @@ exports.setupCompatibilityLayer = () => { const attachCallerToOptions = (caller, options) => { if (!options.basedir) { options.basedir = path.dirname(caller); - }; + } }; const resolveSyncShim = (request, {basedir}) => { @@ -712,29 +712,12 @@ exports.setupCompatibilityLayer = () => { }); }; - const isCoreShim = request => { - return builtinModules.has(request); - }; - - return Object.assign((request, options, callback) => { - if (typeof options === 'function') { - callback = options; - options = {}; - } else if (!options) { - options = {}; - } - - const caller = getCaller(); - attachCallerToOptions(caller, options); - - if (mustBeShimmed(caller)) { - return resolveShim(request, options, callback); - } else { - return realResolve.sync(request, options, callback); - } - }, { - sync: (request, options) => { - if (!options) { + return Object.assign( + (request, options, callback) => { + if (typeof options === 'function') { + callback = options; + options = {}; + } else if (!options) { options = {}; } @@ -742,15 +725,31 @@ exports.setupCompatibilityLayer = () => { attachCallerToOptions(caller, options); if (mustBeShimmed(caller)) { - return resolveSyncShim(request, options); + return resolveShim(request, options, callback); } else { - return realResolve.sync(request, options); + return realResolve.sync(request, options, callback); } }, - isCore: request => { - return realResolve.isCore(request); - } - }); + { + sync: (request, options) => { + if (!options) { + options = {}; + } + + const caller = getCaller(); + attachCallerToOptions(caller, options); + + if (mustBeShimmed(caller)) { + return resolveSyncShim(request, options); + } else { + return realResolve.sync(request, options); + } + }, + isCore: request => { + return realResolve.isCore(request); + }, + }, + ); }); }; From 84358aa507c7f1a8f59d49912dfa16ac757b78eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Mon, 24 Sep 2018 13:54:37 +0100 Subject: [PATCH 106/111] Fixes a broken test --- __tests__/commands/install/bin-links.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/__tests__/commands/install/bin-links.js b/__tests__/commands/install/bin-links.js index 851b72f37d..d56f596c02 100644 --- a/__tests__/commands/install/bin-links.js +++ b/__tests__/commands/install/bin-links.js @@ -219,7 +219,7 @@ describe('with focus', () => { true, ); expect(await linkAt(config, 'node_modules', '.bin', 'example-yarn-workspace-2')).toEqual( - '../example-yarn-workspace-2/index.js', + '../../../example-yarn-workspace-2/index.js', ); }, ); From e1559bbb89f534be4de1e0f09f6590ff6b16791b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Mon, 24 Sep 2018 13:56:45 +0100 Subject: [PATCH 107/111] Re-enables the focus tests --- __tests__/commands/install/focus.js | 34 ++++++++++++++--------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/__tests__/commands/install/focus.js b/__tests__/commands/install/focus.js index 579ee9db2e..4279b2cd18 100644 --- a/__tests__/commands/install/focus.js +++ b/__tests__/commands/install/focus.js @@ -10,7 +10,7 @@ jasmine.DEFAULT_TIMEOUT_INTERVAL = 150000; const path = require('path'); -test.skip('focus does not work from a non-workspaces project', async (): Promise => { +test.concurrent('focus does not work from a non-workspaces project', async (): Promise => { let error = ''; const reporter = new reporters.ConsoleReporter({}); try { @@ -21,7 +21,7 @@ test.skip('focus does not work from a non-workspaces project', async (): Promise expect(error).toContain(reporter.lang('workspacesFocusRootCheck')); }); -test.skip('focus does not work from the root of a workspaces project', async (): Promise => { +test.concurrent('focus does not work from the root of a workspaces project', async (): Promise => { let error = ''; const reporter = new reporters.ConsoleReporter({}); try { @@ -32,7 +32,7 @@ test.skip('focus does not work from the root of a workspaces project', async (): expect(error).toContain(reporter.lang('workspacesFocusRootCheck')); }); -test.skip('focus does a normal workspace installation', (): Promise => { +test.concurrent('focus does a normal workspace installation', (): Promise => { return runInstall( {focus: true}, {source: 'published-monorepo', cwd: '/packages/example-yarn-workspace-1'}, @@ -49,7 +49,7 @@ test.skip('focus does a normal workspace installation', (): Promise => { ); }); -test.skip('focus shallowly installs sibling workspaces under target', (): Promise => { +test.concurrent('focus shallowly installs sibling workspaces under target', (): Promise => { return runInstall( {focus: true}, {source: 'published-monorepo', cwd: '/packages/example-yarn-workspace-1'}, @@ -64,7 +64,7 @@ test.skip('focus shallowly installs sibling workspaces under target', (): Promis ); }); -test.skip('focus should not bail out early after an un-focused install', (): Promise => { +test.concurrent('focus should not bail out early after an un-focused install', (): Promise => { return runInstall({}, 'published-monorepo', async (config, reporter) => { const oldCwd = config.cwd; @@ -81,7 +81,7 @@ test.skip('focus should not bail out early after an un-focused install', (): Pro }); }); -test.skip('repeated focused installs should bail out early', (): Promise => { +test.concurrent('repeated focused installs should bail out early', (): Promise => { return runInstall( {focus: true}, {source: 'published-monorepo', cwd: '/packages/example-yarn-workspace-1'}, @@ -100,7 +100,7 @@ test.skip('repeated focused installs should bail out early', (): Promise = ); }); -test.skip('switching directories for focused installs should fail integrity checks and reinstall', (): Promise< +test.concurrent('switching directories for focused installs should fail integrity checks and reinstall', (): Promise< void, > => { return runInstall( @@ -122,7 +122,7 @@ test.skip('switching directories for focused installs should fail integrity chec ); }); -test.skip( +test.concurrent( 'focus shallowly installs anything that a sibling needed to shallowly install underneath that sibling', (): Promise => { return runInstall( @@ -138,7 +138,7 @@ test.skip( }, ); -test.skip("focus does not shallowly install a sibling's dev dependencies", (): Promise => { +test.concurrent("focus does not shallowly install a sibling's dev dependencies", (): Promise => { return runInstall( {focus: true}, {source: 'published-monorepo', cwd: '/packages/example-yarn-workspace-4'}, @@ -150,7 +150,7 @@ test.skip("focus does not shallowly install a sibling's dev dependencies", (): P ); }); -test.skip("focus runs shallow dependencies' postinstall scripts", (): Promise => { +test.concurrent("focus runs shallow dependencies' postinstall scripts", (): Promise => { return runInstall( {focus: true}, {source: 'published-monorepo', cwd: '/packages/example-yarn-workspace-4'}, @@ -162,7 +162,7 @@ test.skip("focus runs shallow dependencies' postinstall scripts", (): Promise => { +test.concurrent('focus installs transitive dependencies shallowly', (): Promise => { return runInstall( {focus: true}, {source: 'published-monorepo', cwd: '/packages/example-yarn-workspace-4'}, @@ -174,7 +174,7 @@ test.skip('focus installs transitive dependencies shallowly', (): Promise ); }); -test.skip( +test.concurrent( 'focus does not install transitive devdependencies shallowly (but does install non-transitive devdeps)', (): Promise => { return runInstall( @@ -199,7 +199,7 @@ test.skip( }, ); -test.skip( +test.concurrent( 'focus does not shallowly install current version of sibling if another version is specified in package.json', (): Promise => { return runInstall( @@ -215,7 +215,7 @@ test.skip( }, ); -test.skip('focus works correctly when focusing on a scoped package', (): Promise => { +test.concurrent('focus works correctly when focusing on a scoped package', (): Promise => { return runInstall({focus: true}, {source: 'focus-scoped', cwd: '/packages/scoped'}, async (config, reporter) => { const packageFile = await fs.readFile( path.join(config.cwd, 'node_modules', 'example-yarn-workspace-2', 'package.json'), @@ -225,7 +225,7 @@ test.skip('focus works correctly when focusing on a scoped package', (): Promise }); describe('nohoist', () => { - test.skip('focus installs nohoist dependencies shallowly', (): Promise => { + test.concurrent('focus installs nohoist dependencies shallowly', (): Promise => { return runInstall( {focus: true}, {source: 'focus-nohoist', cwd: '/packages/example-yarn-workspace-1'}, @@ -238,7 +238,7 @@ describe('nohoist', () => { ); }); - test.skip('focus does not do nested shallow installs of transitive nohoist packages', (): Promise => { + test.concurrent('focus does not do nested shallow installs of transitive nohoist packages', (): Promise => { return runInstall( {focus: true}, {source: 'focus-nohoist', cwd: '/packages/example-yarn-workspace-3'}, @@ -255,7 +255,7 @@ describe('nohoist', () => { ); }); - test.skip( + test.concurrent( 'focus installs the correct version when a package is nohoist but differs from the workspace version', (): Promise => { return runInstall( From 4325ca1b97a93eeb3697425beef9d56e2dcc4635 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Mon, 24 Sep 2018 14:15:58 +0100 Subject: [PATCH 108/111] Stops relying on bash for test scripts --- .../packages/no-deps-scripted-1.0.0/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/pkg-tests/pkg-tests-fixtures/packages/no-deps-scripted-1.0.0/package.json b/packages/pkg-tests/pkg-tests-fixtures/packages/no-deps-scripted-1.0.0/package.json index 621284f505..294c8b4d37 100644 --- a/packages/pkg-tests/pkg-tests-fixtures/packages/no-deps-scripted-1.0.0/package.json +++ b/packages/pkg-tests/pkg-tests-fixtures/packages/no-deps-scripted-1.0.0/package.json @@ -4,6 +4,6 @@ "scripts": { "preinstall": "echo 'module.exports.push(100);' >> log.js", "install": "echo 'module.exports.push(200);' >> log.js", - "postinstall": "echo 'module.exports.push(300);' >> log.js; echo 'module.exports = '\"$RANDOM\"';' > rnd.js" + "postinstall": "echo 'module.exports.push(300);' >> log.js; echo 'module.exports = '\"$(node -p 'Math.floor(Math.random() * 512000)')\"';' > rnd.js" } } From 48328a60bf927715d6cd3ad888886e9d32e3d741 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Mon, 24 Sep 2018 16:10:24 +0100 Subject: [PATCH 109/111] Fixes nohoist --- src/package-hoister.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/package-hoister.js b/src/package-hoister.js index 1f5c7e9e6b..7df285936f 100644 --- a/src/package-hoister.js +++ b/src/package-hoister.js @@ -973,7 +973,8 @@ export class NohoistResolver { }; _makePath(...args: Array): string { const parts = args.map(s => (s === this._wsRootPackageName ? WS_ROOT_ALIAS : s)); - return parts.join('/'); + const result = parts.join('/'); + return result[0] === '/' ? result : '/' + result; } _isTopPackage = (info: HoistManifest): boolean => { const parentParts = info.parts.slice(0, -1); From f17f25ef433a2c0033898b60d3bc26a333c7b347 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Mon, 24 Sep 2018 16:10:54 +0100 Subject: [PATCH 110/111] Revert "Fixes a broken test" This reverts commit 84358aa507c7f1a8f59d49912dfa16ac757b78eb. --- __tests__/commands/install/bin-links.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/__tests__/commands/install/bin-links.js b/__tests__/commands/install/bin-links.js index d56f596c02..851b72f37d 100644 --- a/__tests__/commands/install/bin-links.js +++ b/__tests__/commands/install/bin-links.js @@ -219,7 +219,7 @@ describe('with focus', () => { true, ); expect(await linkAt(config, 'node_modules', '.bin', 'example-yarn-workspace-2')).toEqual( - '../../../example-yarn-workspace-2/index.js', + '../example-yarn-workspace-2/index.js', ); }, ); From 2cf11d4ba18984a9890525e79bdd1916700b47c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Mon, 24 Sep 2018 17:36:44 +0100 Subject: [PATCH 111/111] Ensures that the getPackageInformation function returns an absolute path --- src/util/generate-pnp-map.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/generate-pnp-map.js b/src/util/generate-pnp-map.js index 982b0b6ce7..c3d81d7919 100644 --- a/src/util/generate-pnp-map.js +++ b/src/util/generate-pnp-map.js @@ -37,7 +37,7 @@ function generateMaps(packageInformationStores: PackageInformationStores, blackl code += ` [${JSON.stringify(packageName)}, new Map([\n`; for (const [packageReference, {packageLocation, packageDependencies}] of packageInformationStore) { code += ` [${JSON.stringify(packageReference)}, {\n`; - code += ` packageLocation: ${JSON.stringify(packageLocation)},\n`; + code += ` packageLocation: path.resolve(__dirname, ${JSON.stringify(packageLocation)}),\n`; code += ` packageDependencies: new Map([\n`; for (const [dependencyName, dependencyReference] of packageDependencies.entries()) { code += ` [${JSON.stringify(dependencyName)}, ${JSON.stringify(dependencyReference)}],\n`;