diff --git a/.circleci/config.yml b/.circleci/config.yml index 0a2704fe2c..d0a4dabd5a 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -79,11 +79,6 @@ build_machine_environment: &build_machine_environment # the mess of temp directories that Meteor makes. METEOR_SAVE_TMPDIRS: 1 - # Disable the optimistic caching of file watchers, which incurs a slight - # polling delay which is less than ideal in a CI environment where file - # watchers should be plentiful. - METEOR_DISABLE_OPTIMISTIC_CACHING: 1 - # Skip these tests on every test run. # For readability, this is a regex wrapped across multiple lines in quotes. SELF_TEST_EXCLUDE: "\ diff --git a/History.md b/History.md index 4f9e859f33..10a9ac8557 100644 --- a/History.md +++ b/History.md @@ -1,5 +1,14 @@ ## v.NEXT +* Meteor now supports `.meteorignore` files, which cause the build system + to ignore certain files and directories using the same pattern syntax as + [`.gitignore` files](https://git-scm.com/docs/gitignore). These files + may appear in any directory of your app or package, specifying rules for + the directory tree below them. Of course, `.meteorignore` files are also + fully integrated with Meteor's file watching system, so they can be + added, removed, or modified during development. + [Feature request #5](https://github.com/meteor/meteor-feature-requests/issues/5) + * DDP's `connection.onReconnect = func` feature has been deprecated. This functionality was previously supported as a way to set a function to be called as the first step of reconnecting. This approach has proven to be diff --git a/meteor b/meteor index 8661fb2933..af4236e800 100755 --- a/meteor +++ b/meteor @@ -1,6 +1,6 @@ #!/usr/bin/env bash -BUNDLE_VERSION=4.8.35 +BUNDLE_VERSION=4.8.36 # OS Check. Put here because here is where we download the precompiled # bundles that are arch specific. diff --git a/scripts/dev-bundle-tool-package.js b/scripts/dev-bundle-tool-package.js index 022f9d1f67..9b63682bc5 100644 --- a/scripts/dev-bundle-tool-package.js +++ b/scripts/dev-bundle-tool-package.js @@ -44,6 +44,7 @@ var packageJson = { "moment": "2.8.4", "rimraf": "2.6.1", "glob": "7.0.6", + ignore: "3.3.5", // XXX: When we update this, see if it fixes this Github issue: // https://github.com/jgm/CommonMark/issues/276 . If it does, remove the // workaround from the tool. diff --git a/tools/fs/optimistic.js b/tools/fs/optimistic.js index f54b61f58f..eb596a8fbf 100644 --- a/tools/fs/optimistic.js +++ b/tools/fs/optimistic.js @@ -5,7 +5,9 @@ import { watch } from "./safe-watcher.js"; import { sha1 } from "./watch.js"; import { pathSep, + pathDirname, pathIsAbsolute, + pathJoin, statOrNull, lstat, readFile, @@ -142,27 +144,17 @@ function maybeDependOnNodeModules(path) { } } -let npmDepCount = 0; - -// Called by any optimistic function that receives a */node_modules/* path -// as its first argument, so that we can later bulk-invalidate the results -// of those calls if the contents of the node_modules directory change. -// Note that this strategy will not detect changes within subdirectories -// of this node_modules directory, but that's ok because the use case we -// care about is adding or removing npm packages. -const dependOnNodeModules = wrap(nodeModulesDir => { - assert(pathIsAbsolute(nodeModulesDir)); - assert(nodeModulesDir.endsWith(pathSep + "node_modules")); +let dependOnDirectorySalt = 0; +const dependOnDirectory = wrap(dir => { // Always return something different to prevent optimism from // second-guessing the dirtiness of this function. - return ++npmDepCount; - + return ++dependOnDirectorySalt; }, { - subscribe(nodeModulesDir) { + subscribe(dir) { let watcher = watch( - nodeModulesDir, - () => dependOnNodeModules.dirty(nodeModulesDir), + dir, + () => dependOnDirectory.dirty(dir), ); return function () { @@ -174,19 +166,52 @@ const dependOnNodeModules = wrap(nodeModulesDir => { } }); +// Called when an optimistic function detects the given file does not +// exist, but needs to return null or false rather than throwing an +// exception. When/if the file is eventually created, we might only get a +// file change notification for the parent directory, so it's important to +// depend on the parent directory using this function, so that we don't +// cache the unsuccessful result forever. +function dependOnParentDirectory(path) { + const parentDir = pathDirname(path); + if (parentDir !== path) { + dependOnDirectory(parentDir); + } +} + +// Called by any optimistic function that receives a */node_modules/* path +// as its first argument, so that we can later bulk-invalidate the results +// of those calls if the contents of the node_modules directory change. +// Note that this strategy will not detect changes within subdirectories +// of this node_modules directory, but that's ok because the use case we +// care about is adding or removing npm packages. +const dependOnNodeModules = wrap(nodeModulesDir => { + assert(pathIsAbsolute(nodeModulesDir)); + assert(nodeModulesDir.endsWith(pathSep + "node_modules")); + return dependOnDirectory(nodeModulesDir); +}); + // Invalidate all optimistic results derived from paths involving the // given node_modules directory. export function dirtyNodeModulesDirectory(nodeModulesDir) { dependOnNodeModules.dirty(nodeModulesDir); } -export const optimisticStatOrNull = makeOptimistic("statOrNull", statOrNull); +export const optimisticStatOrNull = makeOptimistic("statOrNull", path => { + const result = statOrNull(path); + if (result === null) { + dependOnParentDirectory(path); + } + return result; +}); + export const optimisticLStat = makeOptimistic("lstat", lstat); export const optimisticLStatOrNull = makeOptimistic("lstatOrNull", path => { try { return optimisticLStat(path); } catch (e) { if (e.code !== "ENOENT") throw e; + dependOnParentDirectory(path); return null; } }); @@ -203,6 +228,8 @@ export const optimisticHashOrNull = makeOptimistic("hashOrNull", (...args) => { } } + dependOnParentDirectory(args[0]); + return null; }); @@ -213,6 +240,7 @@ makeOptimistic("readJsonOrNull", (path, options) => { } catch (e) { if (e.code === "ENOENT") { + dependOnParentDirectory(path); return null; } @@ -225,11 +253,26 @@ makeOptimistic("readJsonOrNull", (path, options) => { } }); +export const optimisticReadMeteorIgnore = wrap(dir => { + const meteorIgnorePath = pathJoin(dir, ".meteorignore"); + const meteorIgnoreStat = optimisticStatOrNull(meteorIgnorePath); + + if (meteorIgnoreStat && + meteorIgnoreStat.isFile()) { + return require("ignore")().add( + optimisticReadFile(meteorIgnorePath, "utf8") + ); + } + + return null; +}); + const optimisticIsSymbolicLink = wrap(path => { try { return lstat(path).isSymbolicLink(); } catch (e) { if (e.code !== "ENOENT") throw e; + dependOnParentDirectory(path); return false; } }, { diff --git a/tools/fs/safe-watcher.js b/tools/fs/safe-watcher.js index 9c2eedbd39..98865ef265 100644 --- a/tools/fs/safe-watcher.js +++ b/tools/fs/safe-watcher.js @@ -3,6 +3,7 @@ import { Profile } from "../tool-env/profile.js"; import { statOrNull, pathDirname, + pathResolve, convertToOSPath, convertToStandardPath, watchFile, @@ -160,18 +161,17 @@ function startNewWatcher(absPath) { safeUnwatch(); } - // This is a no-op if we're not watching the file. - unwatchFile(absPath, watchFileWrapper); + // Since we're about to restart the stat-based file watcher, we don't + // want to miss any of its events because of the lastWatcherEventTime + // throttling that it attempts to do. + lastWatcherEventTime = 0; // We use files.watchFile in addition to watcher.watch as a fail-safe // to detect file changes even on network file systems. However // (unless the user disabled watcher or this watcher call failed), we // use a relatively long default polling interval of 5000ms to save // CPU cycles. - watchFile(absPath, { - persistent: false, - interval: getPollingInterval(), - }, watchFileWrapper); + statWatch(absPath, getPollingInterval(), watchFileWrapper); } function watchFileWrapper(...args) { @@ -250,6 +250,68 @@ export function closeAllWatchers() { }); } +const statWatchers = Object.create(null); + +function statWatch(absPath, interval, callback) { + const oldWatcher = statWatchers[absPath]; + + while (oldWatcher) { + // Make sure this callback no longer appears among the listeners for + // this StatWatcher. + const countBefore = oldWatcher.stat.listenerCount("change"); + + // This removes at most one occurrence of the callback from the + // listeners list... + oldWatcher.stat.removeListener("change", callback); + + // ... so we have to keep calling it until the first time + // it removes nothing. + if (oldWatcher.stat.listenerCount("change") === countBefore) { + break; + } + } + + // This doesn't actually call newStat.start again if there's already a + // watcher for this file, so it won't change any interval previously + // specified. In the rare event that the interval needs to change, we + // manually stop and restart the StatWatcher below. + const newStat = watchFile(absPath, { + persistent: false, // never persistent + interval, + }, callback); + + if (! oldWatcher) { + const newWatcher = { + stat: newStat, + interval, + }; + + newStat.on("stop", () => { + if (statWatchers[absPath] === newWatcher) { + delete statWatchers[absPath]; + } + }); + + return statWatchers[absPath] = newWatcher; + } + + // These should be identical at this point, but just in case. + oldWatcher.stat = newStat; + + // If the interval needs to be changed, manually stop and restart the + // StatWatcher using lower-level methods than unwatchFile and watchFile. + if (oldWatcher.interval !== interval) { + oldWatcher.stat.stop(); + oldWatcher.stat.start( + convertToOSPath(pathResolve(absPath)), + false, // never persistent + oldWatcher.interval = interval, + ); + } + + return oldWatcher; +} + function watchLibraryWatch(absPath, callback) { if (WATCHER_ENABLED) { try { diff --git a/tools/isobuild/build-plugin.js b/tools/isobuild/build-plugin.js index ff305b3d55..cafd77c4f6 100644 --- a/tools/isobuild/build-plugin.js +++ b/tools/isobuild/build-plugin.js @@ -208,6 +208,10 @@ export class SourceProcessorSet { }); } + if (filename === ".meteorignore") { + return new SourceClassification("meteor-ignore"); + } + // Now check to see if a plugin registered for an extension. We prefer // longer extensions. const parts = filename.split('.'); @@ -303,8 +307,14 @@ class SourceClassification { legacyIsTemplate, arch, } = {}) { - const knownTypes = ['extension', 'filename', 'legacy-handler', 'wrong-arch', - 'unmatched']; + const knownTypes = [ + 'extension', + 'filename', + 'legacy-handler', + 'wrong-arch', + 'unmatched', + 'meteor-ignore', + ]; if (knownTypes.indexOf(type) === -1) { throw Error(`Unknown SourceClassification type ${ type }`); } diff --git a/tools/isobuild/compiler.js b/tools/isobuild/compiler.js index 08e693e102..ef51393802 100644 --- a/tools/isobuild/compiler.js +++ b/tools/isobuild/compiler.js @@ -562,6 +562,13 @@ api.addAssets('${relPath}', 'client').`); Console.nudge(true); + if (classification.type === "meteor-ignore") { + // Return after watching .meteorignore files but before adding them + // as resources to be processed by compiler plugins. To see how + // these files are handled, see PackageSource#_findSources. + return; + } + if (contents === null) { // It really sucks to put this check here, since this isn't publish // code... @@ -765,9 +772,12 @@ function runLinters({inputSourceArch, isopackCache, sources, classification.type === 'unmatched') { return; } - // We shouldn't ever add a legacy handler and we're not hardcoding JS for - // linters, so we should always have SourceProcessor if anything matches. - if (! classification.sourceProcessors) { + + // We shouldn't ever add a legacy handler and we're not hardcoding JS + // for linters, so we should always have SourceProcessor if anything + // matches, unless this is a .meteorignore file. + if (classification.type !== "meteor-ignore" && + ! classification.sourceProcessors) { throw Error( `Unexpected classification for ${ relPath }: ${ classification.type }`); } @@ -776,6 +786,14 @@ function runLinters({inputSourceArch, isopackCache, sources, const {hash, contents} = watch.readAndWatchFileWithHash( watchSet, files.pathResolve(inputSourceArch.sourceRoot, relPath)); + + if (classification.type === "meteor-ignore") { + // Return after watching .meteorignore files but before adding them + // as resources to be processed by compiler plugins. To see how + // these files are handled, see PackageSource#_findSources. + return; + } + const wrappedSource = { relPath, contents, hash, fileOptions, arch: inputSourceArch.arch, diff --git a/tools/isobuild/package-source.js b/tools/isobuild/package-source.js index cbe085d4a5..14d2a2b0d2 100644 --- a/tools/isobuild/package-source.js +++ b/tools/isobuild/package-source.js @@ -32,6 +32,7 @@ import { optimisticReadFile, optimisticHashOrNull, optimisticStatOrNull, + optimisticReadMeteorIgnore, } from "../fs/optimistic.js"; // XXX: This is a medium-term hack, to avoid having the user set a package name @@ -67,6 +68,7 @@ var loadOrderSort = function (sourceProcessorSet, arch) { case 'wrong-arch': case 'unmatched': + case 'meteor-ignore': return false; default: @@ -994,9 +996,14 @@ _.extend(PackageSource.prototype, { const sourceReadOptions = sourceProcessorSet.appReadDirectoryOptions(arch); + // Adding, removing, or modifying a .meteorignore file should trigger + // a rebuild with the new rules applied. + sourceReadOptions.names.push(".meteorignore"); + // Ignore files starting with dot (unless they are explicitly in - // 'names'). + // sourceReadOptions.names, e.g. .meteorignore, added above). sourceReadOptions.exclude.push(/^\./); + // Ignore the usual ignorable files. sourceReadOptions.exclude.push(...ignoreFiles); @@ -1059,6 +1066,8 @@ _.extend(PackageSource.prototype, { return baseCacheKey + "\0" + dir; } + const dotMeteorIgnoreFiles = Object.create(null); + function find(dir, depth, inNodeModules) { // Remove trailing slash. dir = dir.replace(/\/$/, ""); @@ -1076,6 +1085,14 @@ _.extend(PackageSource.prototype, { return []; } + const absDir = files.pathJoin(self.sourceRoot, dir); + if (! inNodeModules) { + const ignore = optimisticReadMeteorIgnore(absDir); + if (ignore) { + dotMeteorIgnoreFiles[dir] = ignore; + } + } + const readOptions = inNodeModules ? nodeModulesReadOptions : sourceReadOptions; @@ -1092,6 +1109,36 @@ _.extend(PackageSource.prototype, { : topLevelExcludes }); + Object.keys(dotMeteorIgnoreFiles).forEach(ignoreDir => { + const ignore = dotMeteorIgnoreFiles[ignoreDir]; + + function removeIgnoredFilesFrom(array) { + let target = 0; + + array.forEach(item => { + let relPath = files.pathRelative(ignoreDir, item); + + if (! relPath.startsWith("..")) { + if (item.endsWith("/")) { + // The trailing slash is discarded by files.pathRelative. + relPath += "/"; + } + + if (ignore.ignores(relPath)) { + return; + } + } + + array[target++] = item; + }); + + array.length = target; + } + + removeIgnoredFilesFrom(sources); + removeIgnoredFilesFrom(subdirectories); + }); + let nodeModulesDir; subdirectories.forEach(subdir => { @@ -1112,6 +1159,9 @@ _.extend(PackageSource.prototype, { } }); + // Don't apply any .meteorignore rules to files inside node_modules. + delete dotMeteorIgnoreFiles[dir]; + if (isApp && nodeModulesDir && (! inNodeModules || sources.length > 0)) { diff --git a/tools/tests/apps/meteor-ignore/.gitignore b/tools/tests/apps/meteor-ignore/.gitignore new file mode 100644 index 0000000000..40b878db5b --- /dev/null +++ b/tools/tests/apps/meteor-ignore/.gitignore @@ -0,0 +1 @@ +node_modules/ \ No newline at end of file diff --git a/tools/tests/apps/meteor-ignore/.meteor/.finished-upgraders b/tools/tests/apps/meteor-ignore/.meteor/.finished-upgraders new file mode 100644 index 0000000000..910574ce2d --- /dev/null +++ b/tools/tests/apps/meteor-ignore/.meteor/.finished-upgraders @@ -0,0 +1,17 @@ +# This file contains information which helps Meteor properly upgrade your +# app when you run 'meteor update'. You should check it into version control +# with your project. + +notices-for-0.9.0 +notices-for-0.9.1 +0.9.4-platform-file +notices-for-facebook-graph-api-2 +1.2.0-standard-minifiers-package +1.2.0-meteor-platform-split +1.2.0-cordova-changes +1.2.0-breaking-changes +1.3.0-split-minifiers-package +1.4.0-remove-old-dev-bundle-link +1.4.1-add-shell-server-package +1.4.3-split-account-service-packages +1.5-add-dynamic-import-package diff --git a/tools/tests/apps/meteor-ignore/.meteor/.gitignore b/tools/tests/apps/meteor-ignore/.meteor/.gitignore new file mode 100644 index 0000000000..4083037423 --- /dev/null +++ b/tools/tests/apps/meteor-ignore/.meteor/.gitignore @@ -0,0 +1 @@ +local diff --git a/tools/tests/apps/meteor-ignore/.meteor/.id b/tools/tests/apps/meteor-ignore/.meteor/.id new file mode 100644 index 0000000000..4b458953bb --- /dev/null +++ b/tools/tests/apps/meteor-ignore/.meteor/.id @@ -0,0 +1,7 @@ +# This file contains a token that is unique to your project. +# Check it into your repository along with the rest of this directory. +# It can be used for purposes such as: +# - ensuring you don't accidentally deploy one app on top of another +# - providing package authors with aggregated statistics + +z1q9vs1ilju2.upauxu4iy59o diff --git a/tools/tests/apps/meteor-ignore/.meteor/packages b/tools/tests/apps/meteor-ignore/.meteor/packages new file mode 100644 index 0000000000..4e4f1624c6 --- /dev/null +++ b/tools/tests/apps/meteor-ignore/.meteor/packages @@ -0,0 +1,17 @@ +# Meteor packages used by this project, one per line. +# Check this file (and the other files in this directory) into your repository. +# +# 'meteor add' and 'meteor remove' will edit this file for you, +# but you can also edit it by hand. + +meteor-base # Packages every Meteor app needs to have +mobile-experience # Packages for a great mobile UX +static-html # Define static page content in .html files +reactive-var # Reactive variable for tracker +tracker # Meteor's client-side reactive programming library + +standard-minifier-css # CSS minifier run for production mode +standard-minifier-js # JS minifier run for production mode +es5-shim # ECMAScript 5 compatibility for older browsers +ecmascript # Enable ECMAScript2015+ syntax in app code +shell-server # Server-side component of the `meteor shell` command diff --git a/tools/tests/apps/meteor-ignore/.meteor/platforms b/tools/tests/apps/meteor-ignore/.meteor/platforms new file mode 100644 index 0000000000..efeba1b50c --- /dev/null +++ b/tools/tests/apps/meteor-ignore/.meteor/platforms @@ -0,0 +1,2 @@ +server +browser diff --git a/tools/tests/apps/meteor-ignore/.meteor/release b/tools/tests/apps/meteor-ignore/.meteor/release new file mode 100644 index 0000000000..621e94f0ec --- /dev/null +++ b/tools/tests/apps/meteor-ignore/.meteor/release @@ -0,0 +1 @@ +none diff --git a/tools/tests/apps/meteor-ignore/.meteor/versions b/tools/tests/apps/meteor-ignore/.meteor/versions new file mode 100644 index 0000000000..2a0c9c4a0e --- /dev/null +++ b/tools/tests/apps/meteor-ignore/.meteor/versions @@ -0,0 +1,64 @@ +allow-deny@1.0.9 +autoupdate@1.3.12 +babel-compiler@6.20.0 +babel-runtime@1.0.1 +base64@1.0.10 +binary-heap@1.0.10 +blaze-tools@1.0.10 +boilerplate-generator@1.2.0 +caching-compiler@1.1.9 +caching-html-compiler@1.1.2 +callback-hook@1.0.10 +check@1.2.5 +ddp@1.3.1 +ddp-client@2.1.3 +ddp-common@1.2.9 +ddp-server@2.0.2 +diff-sequence@1.0.7 +dynamic-import@0.1.3 +ecmascript@0.8.2 +ecmascript-runtime@0.4.1 +ecmascript-runtime-client@0.4.3 +ecmascript-runtime-server@0.4.1 +ejson@1.0.14 +es5-shim@4.6.15 +geojson-utils@1.0.10 +hot-code-push@1.0.4 +html-tools@1.0.11 +htmljs@1.0.11 +http@1.2.12 +id-map@1.0.9 +launch-screen@1.1.1 +livedata@1.0.18 +logging@1.1.17 +meteor@1.7.2 +meteor-base@1.1.0 +minifier-css@1.2.16 +minifier-js@2.1.3 +minimongo@1.3.1 +mobile-experience@1.0.5 +mobile-status-bar@1.0.14 +modules@0.10.0 +modules-runtime@0.8.0 +mongo@1.2.2 +mongo-dev-server@1.0.1 +mongo-id@1.0.6 +npm-mongo@2.2.30 +ordered-dict@1.0.9 +promise@0.9.0 +random@1.0.10 +reactive-var@1.0.11 +reload@1.1.11 +retry@1.0.9 +routepolicy@1.0.12 +shell-server@0.2.4 +spacebars-compiler@1.1.3 +standard-minifier-css@1.3.5 +standard-minifier-js@2.1.1 +static-html@1.2.2 +templating-tools@1.1.2 +tracker@1.1.3 +underscore@1.0.10 +url@1.1.0 +webapp@1.3.19 +webapp-hashing@1.0.9 diff --git a/tools/tests/apps/meteor-ignore/a.js b/tools/tests/apps/meteor-ignore/a.js new file mode 100644 index 0000000000..8a1d00f709 --- /dev/null +++ b/tools/tests/apps/meteor-ignore/a.js @@ -0,0 +1 @@ +require("/imports/registry.js").add(module.id); diff --git a/tools/tests/apps/meteor-ignore/b.js b/tools/tests/apps/meteor-ignore/b.js new file mode 100644 index 0000000000..8a1d00f709 --- /dev/null +++ b/tools/tests/apps/meteor-ignore/b.js @@ -0,0 +1 @@ +require("/imports/registry.js").add(module.id); diff --git a/tools/tests/apps/meteor-ignore/imports/registry.js b/tools/tests/apps/meteor-ignore/imports/registry.js new file mode 100644 index 0000000000..7dea8ddb80 --- /dev/null +++ b/tools/tests/apps/meteor-ignore/imports/registry.js @@ -0,0 +1,11 @@ +const ids = []; + +export function add(id) { + ids.push(id); +} + +Meteor.startup(() => { + ids.sort().forEach(id => { + console.log(id); + }); +}); diff --git a/tools/tests/apps/meteor-ignore/lib/e.js b/tools/tests/apps/meteor-ignore/lib/e.js new file mode 100644 index 0000000000..8a1d00f709 --- /dev/null +++ b/tools/tests/apps/meteor-ignore/lib/e.js @@ -0,0 +1 @@ +require("/imports/registry.js").add(module.id); diff --git a/tools/tests/apps/meteor-ignore/lib/f.js b/tools/tests/apps/meteor-ignore/lib/f.js new file mode 100644 index 0000000000..8a1d00f709 --- /dev/null +++ b/tools/tests/apps/meteor-ignore/lib/f.js @@ -0,0 +1 @@ +require("/imports/registry.js").add(module.id); diff --git a/tools/tests/apps/meteor-ignore/main.js b/tools/tests/apps/meteor-ignore/main.js new file mode 100644 index 0000000000..8a1d00f709 --- /dev/null +++ b/tools/tests/apps/meteor-ignore/main.js @@ -0,0 +1 @@ +require("/imports/registry.js").add(module.id); diff --git a/tools/tests/apps/meteor-ignore/package-lock.json b/tools/tests/apps/meteor-ignore/package-lock.json new file mode 100644 index 0000000000..f8c2fe01f1 --- /dev/null +++ b/tools/tests/apps/meteor-ignore/package-lock.json @@ -0,0 +1,603 @@ +{ + "name": "meteor-ignore", + "requires": true, + "lockfileVersion": 1, + "dependencies": { + "babel-runtime": { + "version": "7.0.0-beta.1", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-7.0.0-beta.1.tgz", + "integrity": "sha512-fFvXG9uqIwtkaLVymtS3oHnjzhdEC8Yb5Da9swQ+Ur9xCpkJlVOENyHMCVnLCO7XwDKtkUtvn/LeufKdwKd3uw==", + "requires": { + "core-js": "2.5.1", + "regenerator-runtime": "0.11.0" + } + }, + "core-js": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.1.tgz", + "integrity": "sha1-rmh03GaTd4m4B1T/VCjfZoGcpQs=" + }, + "meteor-node-stubs": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/meteor-node-stubs/-/meteor-node-stubs-0.2.11.tgz", + "integrity": "sha1-cV5Owc6IgkiylgThbQkiVrDLfjQ=", + "requires": { + "assert": "1.4.1", + "browserify-zlib": "0.1.4", + "buffer": "4.9.1", + "console-browserify": "1.1.0", + "constants-browserify": "1.0.0", + "crypto-browserify": "3.11.0", + "domain-browser": "1.1.7", + "events": "1.1.1", + "http-browserify": "1.7.0", + "https-browserify": "0.0.1", + "os-browserify": "0.2.1", + "path-browserify": "0.0.0", + "process": "0.11.9", + "punycode": "1.4.1", + "querystring-es3": "0.2.1", + "readable-stream": "git+https://github.com/meteor/readable-stream.git#2e9112d7d31a2af6e0682db0e18679b1e5fd4694", + "stream-browserify": "2.0.1", + "string_decoder": "1.0.1", + "timers-browserify": "1.4.2", + "tty-browserify": "0.0.0", + "url": "0.11.0", + "util": "0.10.3", + "vm-browserify": "0.0.4" + }, + "dependencies": { + "Base64": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/Base64/-/Base64-0.2.1.tgz", + "integrity": "sha1-ujpCMHCOGGcFBl5mur3Uw1z2ACg=" + }, + "asn1.js": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.9.0.tgz", + "integrity": "sha1-9xoSQ/PnnUbXsH1/v0gk7nOvBUo=", + "requires": { + "bn.js": "4.11.6", + "inherits": "2.0.1", + "minimalistic-assert": "1.0.0" + } + }, + "assert": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/assert/-/assert-1.4.1.tgz", + "integrity": "sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE=", + "requires": { + "util": "0.10.3" + } + }, + "balanced-match": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz", + "integrity": "sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg=" + }, + "base64-js": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.2.0.tgz", + "integrity": "sha1-o5mS1yNYSBGYK+XikLtqU9hnAPE=" + }, + "bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha1-UzRK2xRhehP26N0s4okF0cC6MhU=" + }, + "brace-expansion": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.7.tgz", + "integrity": "sha1-Pv/DxQ4ABTH7cg6v+A8K6O8jz1k=", + "requires": { + "balanced-match": "0.4.2", + "concat-map": "0.0.1" + } + }, + "brorand": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.0.6.tgz", + "integrity": "sha1-QChwa5FfkfezSaLgvzw3YDnSFuU=" + }, + "browserify-aes": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.0.6.tgz", + "integrity": "sha1-Xncl297x/Vkw1OurSFZ85FHEigo=", + "requires": { + "buffer-xor": "1.0.3", + "cipher-base": "1.0.3", + "create-hash": "1.1.2", + "evp_bytestokey": "1.0.0", + "inherits": "2.0.1" + } + }, + "browserify-cipher": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.0.tgz", + "integrity": "sha1-mYgkSHS/XtTijalWZtzWasj8Njo=", + "requires": { + "browserify-aes": "1.0.6", + "browserify-des": "1.0.0", + "evp_bytestokey": "1.0.0" + } + }, + "browserify-des": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.0.tgz", + "integrity": "sha1-2qJ3cXRwki7S/hhZQRihdUOXId0=", + "requires": { + "cipher-base": "1.0.3", + "des.js": "1.0.0", + "inherits": "2.0.1" + } + }, + "browserify-rsa": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", + "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", + "requires": { + "bn.js": "4.11.6", + "randombytes": "2.0.3" + } + }, + "browserify-sign": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.0.tgz", + "integrity": "sha1-EHc5EMPCBtVCCkaq2GlPgguFlo8=", + "requires": { + "bn.js": "4.11.6", + "browserify-rsa": "4.0.1", + "create-hash": "1.1.2", + "create-hmac": "1.1.4", + "elliptic": "6.3.2", + "inherits": "2.0.1", + "parse-asn1": "5.0.0" + } + }, + "browserify-zlib": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.1.4.tgz", + "integrity": "sha1-uzX4pRn2AOD6a4SFJByXnQFB+y0=", + "requires": { + "pako": "0.2.9" + } + }, + "buffer": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", + "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", + "requires": { + "base64-js": "1.2.0", + "ieee754": "1.1.8", + "isarray": "1.0.0" + } + }, + "buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=" + }, + "cipher-base": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.3.tgz", + "integrity": "sha1-7qvxlEGc6QDaMBjCB9IS8qbfCgc=", + "requires": { + "inherits": "2.0.1" + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "console-browserify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", + "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=", + "requires": { + "date-now": "0.1.4" + } + }, + "constants-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", + "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=" + }, + "create-ecdh": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.0.tgz", + "integrity": "sha1-iIxyNZbN92EvZJgjPuvXo1MBc30=", + "requires": { + "bn.js": "4.11.6", + "elliptic": "6.3.2" + } + }, + "create-hash": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.1.2.tgz", + "integrity": "sha1-USEAYte7dHn2xlu0GpIgix1hq60=", + "requires": { + "cipher-base": "1.0.3", + "inherits": "2.0.1", + "ripemd160": "1.0.1", + "sha.js": "2.4.8" + } + }, + "create-hmac": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.4.tgz", + "integrity": "sha1-0/tLolPriz9W456i+8uK90e9MXA=", + "requires": { + "create-hash": "1.1.2", + "inherits": "2.0.1" + } + }, + "crypto-browserify": { + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.11.0.tgz", + "integrity": "sha1-NlKgkGq5sqfgw85mpAjpV6JIVSI=", + "requires": { + "browserify-cipher": "1.0.0", + "browserify-sign": "4.0.0", + "create-ecdh": "4.0.0", + "create-hash": "1.1.2", + "create-hmac": "1.1.4", + "diffie-hellman": "5.0.2", + "inherits": "2.0.1", + "pbkdf2": "3.0.9", + "public-encrypt": "4.0.0", + "randombytes": "2.0.3" + } + }, + "date-now": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", + "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=" + }, + "des.js": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.0.tgz", + "integrity": "sha1-wHTS4qpqipoH29YfmhXCzYPsjsw=", + "requires": { + "inherits": "2.0.1", + "minimalistic-assert": "1.0.0" + } + }, + "diffie-hellman": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.2.tgz", + "integrity": "sha1-tYNXOScM/ias9jIJn97SoH8gnl4=", + "requires": { + "bn.js": "4.11.6", + "miller-rabin": "4.0.0", + "randombytes": "2.0.3" + } + }, + "domain-browser": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.1.7.tgz", + "integrity": "sha1-hnqksJP6oF8d4IwG9NeyH9+GmLw=" + }, + "elliptic": { + "version": "6.3.2", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.3.2.tgz", + "integrity": "sha1-5MgeCCnPCmWrcOmYuCMnI7XBvEg=", + "requires": { + "bn.js": "4.11.6", + "brorand": "1.0.6", + "hash.js": "1.0.3", + "inherits": "2.0.1" + } + }, + "events": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", + "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=" + }, + "evp_bytestokey": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.0.tgz", + "integrity": "sha1-SXtmrZ/vZc18CKYYCCS6FHa2blM=", + "requires": { + "create-hash": "1.1.2" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.1", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "hash.js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.0.3.tgz", + "integrity": "sha1-EzL/ABVsCg/92CNgE9B7d6BFFXM=", + "requires": { + "inherits": "2.0.1" + } + }, + "http-browserify": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/http-browserify/-/http-browserify-1.7.0.tgz", + "integrity": "sha1-M3la3nLfiKz7/TZ3PO/tp2RzWyA=", + "requires": { + "Base64": "0.2.1", + "inherits": "2.0.1" + } + }, + "https-browserify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-0.0.1.tgz", + "integrity": "sha1-P5E2XKvmC3ftDruiS0VOPgnZWoI=" + }, + "ieee754": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.8.tgz", + "integrity": "sha1-vjPUCsEO8ZJnAfbwii2G+/0a0+Q=" + }, + "indexof": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", + "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=" + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } + }, + "inherits": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=" + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "miller-rabin": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.0.tgz", + "integrity": "sha1-SmL7HUKTPAVYOYL0xxb2+55sbT0=", + "requires": { + "bn.js": "4.11.6", + "brorand": "1.0.6" + } + }, + "minimalistic-assert": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz", + "integrity": "sha1-cCvi3aazf0g2vLP121ZkG2Sh09M=" + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "1.1.7" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1.0.2" + } + }, + "os-browserify": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.2.1.tgz", + "integrity": "sha1-Y/xMzuXS13Y9Jrv4YBB45sLgBE8=" + }, + "pako": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", + "integrity": "sha1-8/dSL073gjSNqBYbrZ7P1Rv4OnU=" + }, + "parse-asn1": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.0.0.tgz", + "integrity": "sha1-NQYPbVAV03Yox3D04JGgtaJ4vCM=", + "requires": { + "asn1.js": "4.9.0", + "browserify-aes": "1.0.6", + "create-hash": "1.1.2", + "evp_bytestokey": "1.0.0", + "pbkdf2": "3.0.9" + } + }, + "path-browserify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.0.tgz", + "integrity": "sha1-oLhwcpquIUAFt9UDLsLLuw+0RRo=" + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "pbkdf2": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.9.tgz", + "integrity": "sha1-8sSyWmAAWLPDdzwIbDfbvuH/5pM=", + "requires": { + "create-hmac": "1.1.4" + } + }, + "process": { + "version": "0.11.9", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.9.tgz", + "integrity": "sha1-e9WtIapiU+fahoImTx4R0RwDGME=" + }, + "process-nextick-args": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", + "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=" + }, + "public-encrypt": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.0.tgz", + "integrity": "sha1-OfaZ86RlYN1eusvKaTyvfGXBjMY=", + "requires": { + "bn.js": "4.11.6", + "browserify-rsa": "4.0.1", + "create-hash": "1.1.2", + "parse-asn1": "5.0.0", + "randombytes": "2.0.3" + } + }, + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" + }, + "querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=" + }, + "querystring-es3": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", + "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=" + }, + "randombytes": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.3.tgz", + "integrity": "sha1-Z0yZdgkBw8QRJ3GjHlIdw0nMCew=" + }, + "readable-stream": { + "version": "git+https://github.com/meteor/readable-stream.git#2e9112d7d31a2af6e0682db0e18679b1e5fd4694", + "requires": { + "inherits": "2.0.1", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "safe-buffer": "5.0.1", + "string_decoder": "1.0.1", + "util-deprecate": "1.0.2" + } + }, + "rimraf": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.1.tgz", + "integrity": "sha1-wjOOxkPfeht/5cVPqG9XQopV8z0=", + "requires": { + "glob": "7.1.2" + } + }, + "ripemd160": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-1.0.1.tgz", + "integrity": "sha1-k6S71JQrxXS2mo+lfHHeEOzKfW4=" + }, + "safe-buffer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.0.1.tgz", + "integrity": "sha1-0mPKVGls2KMGtcplUekt5XkY++c=" + }, + "sha.js": { + "version": "2.4.8", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.8.tgz", + "integrity": "sha1-NwaMLEdra69ALRSknGf1l5IfY08=", + "requires": { + "inherits": "2.0.1" + } + }, + "stream-browserify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.1.tgz", + "integrity": "sha1-ZiZu5fm9uZQKTkUUyvtDu3Hlyds=", + "requires": { + "inherits": "2.0.1", + "readable-stream": "git+https://github.com/meteor/readable-stream.git#2e9112d7d31a2af6e0682db0e18679b1e5fd4694" + } + }, + "string_decoder": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.1.tgz", + "integrity": "sha1-YuIA8DmVWmgQ2N8KM//A8BNmLZg=", + "requires": { + "safe-buffer": "5.0.1" + } + }, + "timers-browserify": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-1.4.2.tgz", + "integrity": "sha1-ycWLV1voQHN1y14kYtrO50NZ9B0=", + "requires": { + "process": "0.11.9" + } + }, + "tty-browserify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", + "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=" + }, + "url": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", + "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", + "requires": { + "punycode": "1.3.2", + "querystring": "0.2.0" + }, + "dependencies": { + "punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" + } + } + }, + "util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", + "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", + "requires": { + "inherits": "2.0.1" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "vm-browserify": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz", + "integrity": "sha1-XX6kW7755Kb/ZflUOOCofDV9WnM=", + "requires": { + "indexof": "0.0.1" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + } + } + }, + "regenerator-runtime": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.0.tgz", + "integrity": "sha512-/aA0kLeRb5N9K0d4fw7ooEbI+xDe+DKD499EQqygGqeS8N3xto15p09uY2xj7ixP81sNPXvRLnAQIqdVStgb1A==" + } + } +} diff --git a/tools/tests/apps/meteor-ignore/package.json b/tools/tests/apps/meteor-ignore/package.json new file mode 100644 index 0000000000..4797086153 --- /dev/null +++ b/tools/tests/apps/meteor-ignore/package.json @@ -0,0 +1,11 @@ +{ + "name": "meteor-ignore", + "private": true, + "scripts": { + "start": "meteor run" + }, + "dependencies": { + "babel-runtime": "^7.0.0-beta.0", + "meteor-node-stubs": "~0.2.4" + } +} diff --git a/tools/tests/apps/meteor-ignore/server/c.js b/tools/tests/apps/meteor-ignore/server/c.js new file mode 100644 index 0000000000..0c5700298f --- /dev/null +++ b/tools/tests/apps/meteor-ignore/server/c.js @@ -0,0 +1,2 @@ +require("/imports/registry.js").add(module.id); +require("./d.js"); diff --git a/tools/tests/apps/meteor-ignore/server/d.js b/tools/tests/apps/meteor-ignore/server/d.js new file mode 100644 index 0000000000..8a1d00f709 --- /dev/null +++ b/tools/tests/apps/meteor-ignore/server/d.js @@ -0,0 +1 @@ +require("/imports/registry.js").add(module.id); diff --git a/tools/tests/meteor-ignore.js b/tools/tests/meteor-ignore.js new file mode 100644 index 0000000000..e779752bd8 --- /dev/null +++ b/tools/tests/meteor-ignore.js @@ -0,0 +1,75 @@ +const selftest = require("../tool-testing/selftest.js"); +const Sandbox = selftest.Sandbox; + +selftest.define(".meteorignore", function () { + const s = new Sandbox(); + + s.createApp("myapp", "meteor-ignore"); + s.cd("myapp"); + + let run = s.run(); + run.waitSecs(30); + run.match("/a.js"); + run.match("/b.js"); + run.match("/lib/e.js"); + run.match("/lib/f.js"); + run.match("/main.js"); + run.match("/server/c.js"); + run.match("/server/d.js"); + run.match("App running at"); + + s.write("server/.meteorignore", "c.*"); + run.waitSecs(10); + run.match("/a.js"); + run.match("/b.js"); + run.match("/lib/e.js"); + run.match("/lib/f.js"); + run.match("/main.js"); + run.match("/server/d.js"); + run.match("restarted"); + + s.write(".meteorignore", "server/d.js"); + run.waitSecs(10); + run.match("/a.js"); + run.match("/b.js"); + run.match("/lib/e.js"); + run.match("/lib/f.js"); + run.match("/main.js"); + run.match("restarted"); + + s.write("lib/.meteorignore", "*.js\n!e.*"); + run.waitSecs(10); + run.match("/a.js"); + run.match("/b.js"); + run.match("/lib/e.js"); + run.match("/main.js"); + run.match("restarted"); + + s.write(".meteorignore", "lib/**"); + run.waitSecs(10); + run.match("/a.js"); + run.match("/b.js"); + run.match("/main.js"); + run.match("/server/d.js"); + run.match("restarted"); + + s.write(".meteorignore", "/*.js\nlib"); + run.waitSecs(10); + run.match("/server/d.js"); + run.match("restarted"); + + s.unlink(".meteorignore"); + s.unlink("lib/.meteorignore"); + s.unlink("server/.meteorignore"); + run.waitSecs(10); + run.match("/a.js"); + run.match("/b.js"); + run.match("/lib/e.js"); + run.match("/lib/f.js"); + run.match("/main.js"); + run.match("/server/c.js"); + run.match("/server/d.js"); + run.match("restarted"); + + run.stop(); +});