diff --git a/History.md b/History.md index ee30411c1dc..7707f66f220 100644 --- a/History.md +++ b/History.md @@ -1,5 +1,22 @@ ## v.NEXT +* Applications may now specify client and server entry point modules in a + newly-supported `"meteor"` section of `package.json`: + ```js + "meteor": { + "mainModule": { + "client": "client/main.js", + "server": "server/main.js" + } + } + ``` + When specified, these entry points override Meteor's default module + loading semantics, rendering `imports` directories unnecessary. If + `mainModule` is left unspecified for either client or server, the + default rules will apply for that architecture, as before. + [Feature #135](https://github.com/meteor/meteor-feature-requests/issues/135) + [PR #9690](https://github.com/meteor/meteor/pull/9690) + * The `reify` npm package has been updated to version 0.14.2. * The `meteor-babel` npm package has been updated to version diff --git a/tools/isobuild/compiler-plugin.js b/tools/isobuild/compiler-plugin.js index 39756afd124..a528c8bcbb3 100644 --- a/tools/isobuild/compiler-plugin.js +++ b/tools/isobuild/compiler-plugin.js @@ -591,7 +591,7 @@ class ResourceSlot { return fileOptions && fileOptions[name]; } - _isLazy(options) { + _isLazy(options, isJavaScript) { let lazy = this._getOption("lazy", options); if (typeof lazy === "boolean") { @@ -607,18 +607,36 @@ class ResourceSlot { return false; } - const splitPath = this.inputResource.path.split(files.pathSep); - const isInImports = splitPath.indexOf("imports") >= 0; + const runningTests = global.testCommandMetadata && + (global.testCommandMetadata.isTest || + global.testCommandMetadata.isAppTest); - if (global.testCommandMetadata && - (global.testCommandMetadata.isTest || - global.testCommandMetadata.isAppTest)) { - // test files should always be included, if we're running app - // tests. - return isInImports && !isTestFilePath(this.inputResource.path); - } else { - return isInImports; + if (runningTests && + isTestFilePath(this.inputResource.path)) { + // Test files are never lazy if we're running tests. + return false; + } + + if (isJavaScript) { + // PackageSource#_inferFileOptions (in package-source.js) sets the + // mainModule option to false to indicate a meteor.mainModule was + // configured for this architecture, but this module was not it. + // It's important to wait until this point (ResourceSlot#_isLazy) to + // make the final call, because we can finally tell whether the + // output resource is JavaScript or not (non-JS resources are not + // affected by the meteor.mainModule option). + const mainModule = this._getOption("mainModule", options); + if (typeof mainModule === "boolean") { + return ! mainModule; + } } + + // In other words, the imports directory remains relevant for non-JS + // resources, and for JS resources in the absence of an explicit + // meteor.mainModule configuration in package.json. + const splitPath = this.inputResource.path.split(files.pathSep); + const isInImports = splitPath.indexOf("imports") >= 0; + return isInImports; } addStylesheet(options) { @@ -637,7 +655,7 @@ class ResourceSlot { targetPath, servePath: self.packageSourceBatch.unibuild.pkg._getServePath(targetPath), hash: sha1(data), - lazy: this._isLazy(options), + lazy: this._isLazy(options, false), }; if (useMeteorInstall && resource.lazy) { @@ -711,7 +729,7 @@ class ResourceSlot { sourceMap: options.sourceMap, // intentionally preserve a possible `undefined` value for files // in apps, rather than convert it into `false` via `!!` - lazy: self._isLazy(options), + lazy: self._isLazy(options, true), bare: !! self._getOption("bare", options), mainModule: !! self._getOption("mainModule", options), }); @@ -739,7 +757,7 @@ class ResourceSlot { servePath: self.packageSourceBatch.unibuild.pkg._getServePath( options.path), hash: sha1(options.data), - lazy: self._isLazy(options), + lazy: self._isLazy(options, false), }); } @@ -763,7 +781,7 @@ class ResourceSlot { self.outputResources.push({ type: options.section, data: Buffer.from(files.convertToStandardLineEndings(options.data), 'utf8'), - lazy: self._isLazy(options), + lazy: self._isLazy(options, false), }); } diff --git a/tools/isobuild/package-api.js b/tools/isobuild/package-api.js index 1bd236889a5..c0f58852d38 100644 --- a/tools/isobuild/package-api.js +++ b/tools/isobuild/package-api.js @@ -48,7 +48,7 @@ function toArchArray (arch) { // 'client' -> 'web' // 'server' -> 'os' // '*' -> '*' -function mapWhereToArch (where) { +export function mapWhereToArch(where) { if (where === 'server') { return 'os'; } else if (where === 'client') { diff --git a/tools/isobuild/package-source.js b/tools/isobuild/package-source.js index 1fdad7561aa..ab41420d88c 100644 --- a/tools/isobuild/package-source.js +++ b/tools/isobuild/package-source.js @@ -837,7 +837,10 @@ _.extend(PackageSource.prototype, { constraint: constraint.constraintString }); }); - var projectWatchSet = projectContext.getProjectWatchSet(); + const projectWatchSet = projectContext.getProjectWatchSet(); + const mainModulesByArch = + projectContext.meteorConfig.getMainModulesByArch(); + projectWatchSet.merge(projectContext.meteorConfig.watchSet); _.each(compiler.ALL_ARCHES, function (arch) { // We don't need to build a Cordova SourceArch if there are no Cordova @@ -847,6 +850,9 @@ _.extend(PackageSource.prototype, { return; } + const mainModule = projectContext.meteorConfig + .getMainModuleForArch(arch, mainModulesByArch); + // XXX what about /web.browser/* etc, these directories could also // be for specific client targets. @@ -867,20 +873,42 @@ _.extend(PackageSource.prototype, { isApp: true, }; + // If this architecture has a mainModule defined in + // package.json, it's an error if _findSources doesn't find that + // module. If no mainModule is defined, anything goes. + let missingMainModule = !! mainModule; + + const sources = self._findSources(findOptions).sort( + loadOrderSort(sourceProcessorSet, arch) + ).map(relPath => { + if (relPath === mainModule) { + missingMainModule = false; + } + + const fileOptions = self._inferFileOptions(relPath, { + arch, + isApp: true, + mainModule, + }); + + return { + relPath, + fileOptions, + }; + }); + + if (missingMainModule) { + buildmessage.error([ + "Could not find mainModule for '" + arch + "' architecture: " + mainModule, + 'Check the "meteor" section of your package.json file?' + ].join("\n")); + } + + const assets = self._findAssets(findOptions); + return { - sources: self._findSources(findOptions).sort( - loadOrderSort(sourceProcessorSet, arch) - ).map(relPath => { - return { - relPath, - fileOptions: self._inferFileOptions(relPath, { - arch, - isApp: true, - }), - }; - }), - - assets: self._findAssets(findOptions), + sources, + assets, }; } }); @@ -919,7 +947,11 @@ _.extend(PackageSource.prototype, { } }), - _inferFileOptions(relPath, {arch, isApp}) { + _inferFileOptions(relPath, { + arch, + isApp, + mainModule, + }) { const fileOptions = {}; const isTest = global.testCommandMetadata && global.testCommandMetadata.isTest; @@ -974,6 +1006,17 @@ _.extend(PackageSource.prototype, { } } + if (isApp && mainModule) { + if (relPath === mainModule) { + fileOptions.lazy = false; + fileOptions.mainModule = true; + } else if (typeof fileOptions.lazy === "undefined") { + // Used in ResourceSlot#_isLazy (in compiler-plugin.js) to make a + // final determination of whether the file should be lazy. + fileOptions.mainModule = false; + } + } + return fileOptions; }, diff --git a/tools/project-context.js b/tools/project-context.js index 095ca9a83d0..5eb25b43fdc 100644 --- a/tools/project-context.js +++ b/tools/project-context.js @@ -17,6 +17,17 @@ var watch = require('./fs/watch.js'); var Profile = require('./tool-env/profile.js').Profile; import { KNOWN_ISOBUILD_FEATURE_PACKAGES } from './isobuild/compiler.js'; +import { + optimisticReadJsonOrNull, + optimisticHashOrNull, +} from "./fs/optimistic.js"; + +import { + mapWhereToArch, +} from "./isobuild/package-api.js"; + +import Resolver from "./isobuild/resolver.js"; + // The ProjectContext represents all the context associated with an app: // metadata files in the `.meteor` directory, the choice of package versions // used by it, etc. Any time you want to work with an app, create a @@ -363,6 +374,13 @@ _.extend(ProjectContext.prototype, { }); if (buildmessage.jobHasMessages()) return; + + self.meteorConfig = new MeteorConfig({ + appDirectory: self.projectDir, + }); + if (buildmessage.jobHasMessages()) { + return; + } }); self._completedStage = STAGE.READ_PROJECT_METADATA; @@ -1580,3 +1598,100 @@ _.extend(exports.FinishedUpgraders.prototype, { files.appendFile(self.filename, appendText); } }); + +export class MeteorConfig { + constructor({ + appDirectory, + }) { + this.appDirectory = appDirectory; + this.packageJsonPath = files.pathJoin(appDirectory, "package.json"); + this.watchSet = new watch.WatchSet; + this._resolversByArch = Object.create(null); + } + + _ensureInitialized() { + if (! _.has(this, "_config")) { + const json = optimisticReadJsonOrNull(this.packageJsonPath); + this._config = json && json.meteor || null; + this.watchSet.addFile( + this.packageJsonPath, + optimisticHashOrNull(this.packageJsonPath) + ); + } + + return this._config; + } + + // General utility for querying the "meteor" section of package.json. + // TODO Implement an API for setting these values? + get(...keys) { + let config = this._ensureInitialized(); + if (config) { + keys.every(key => { + if (config && _.has(config, key)) { + config = config[key]; + return true; + } + }); + return config; + } + } + + // Call this first if you plan to call getMainModuleForArch multiple + // times, so that you can avoid repeating this work each time. + getMainModulesByArch(arch) { + const configMainModule = this.get("mainModule"); + const mainModulesByArch = Object.create(null); + + if (configMainModule) { + if (typeof configMainModule === "string") { + // If packageJson.meteor.mainModule is a string, use that string + // as the mainModule for all architectures. + mainModulesByArch["os"] = configMainModule; + mainModulesByArch["web"] = configMainModule; + } else if (typeof configMainModule === "object") { + // If packageJson.meteor.mainModule is an object, use its + // properties to select a mainModule for each architecture. + Object.keys(configMainModule).forEach(where => { + mainModulesByArch[mapWhereToArch(where)] = configMainModule[where]; + }); + } + } + + return mainModulesByArch; + } + + // Given an architecture like web.browser, get the best mainModule for + // that architecture. For example, if this.config.mainModule.client is + // defined, then because mapWhereToArch("client") === "web", and "web" + // matches web.browser, return this.config.mainModule.client. + getMainModuleForArch( + arch, + mainModulesByArch = this.getMainModulesByArch(), + ) { + const mainMatch = archinfo.mostSpecificMatch( + arch, Object.keys(mainModulesByArch)); + + if (mainMatch) { + if (! this._resolversByArch[arch]) { + this._resolversByArch[arch] = new Resolver({ + sourceRoot: this.appDirectory, + targetArch: arch, + }); + } + + // Use a Resolver to allow the mainModule strings to omit .js or + // .json file extensions, and to enable resolving directories + // containing package.json or index.js files. + const res = this._resolversByArch[arch].resolve( + // Only relative paths are allowed (not top-level packages). + "./" + files.pathNormalize(mainModulesByArch[mainMatch]), + this.packageJsonPath + ); + + if (res && typeof res === "object") { + return files.pathRelative(this.appDirectory, res.path); + } + } + } +} diff --git a/tools/tests/app-config.js b/tools/tests/app-config.js new file mode 100644 index 00000000000..d6acbd7e8e7 --- /dev/null +++ b/tools/tests/app-config.js @@ -0,0 +1,110 @@ +var selftest = require('../tool-testing/selftest.js'); +var Sandbox = selftest.Sandbox; + +selftest.define("mainModule", function () { + const s = new Sandbox(); + s.createApp("app-config-mainModule", "app-config"); + s.cd("app-config-mainModule"); + + const run = s.run( + "test", + "--full-app", + "--driver-package", "dispatch:mocha-phantomjs" + ); + + run.waitSecs(60); + run.match("App running at"); + + function check(mainModule) { + const json = JSON.parse(s.read("package.json")); + + let shouldWrite = true; + if (typeof mainModule === "undefined") { + if ("meteor" in json) { + delete json.meteor; + } else { + shouldWrite = false; + } + } else { + json.meteor = { mainModule }; + } + + if (shouldWrite) { + s.write("package.json", JSON.stringify(json, null, 2) + "\n"); + } + + run.waitSecs(10); + run.match("SERVER FAILURES: 0"); + run.match("CLIENT FAILURES: 0"); + } + + check(); + + check(null); + + check("oyez"); + + check({}); + + check({ + client: "a", + os: "bc", + }); + + check({ + client: "b.js", + server: "abc", + }); + + check({ + client: "./c", + server: "/ac", + }); + + check({ + server: "./a", + web: "ab", + }); + + check({ + client: "ac.js", + os: "a", + }); + + check({ + web: "bc", + server: "a", + }); + + check({ + server: "b.js", + client: "abc", + }); + + check({ + client: "abc", + }); + + check({ + server: "b.js", + }); + + check({ + client: "/ac", + server: "./c", + }); + + check({ + os: "ab", + client: "./a", + }); + + check({ + server: "ac.js", + web: "a", + }); + + check(null); + + check(); +}); diff --git a/tools/tests/apps/app-config/.gitignore b/tools/tests/apps/app-config/.gitignore new file mode 100644 index 00000000000..c2658d7d1b3 --- /dev/null +++ b/tools/tests/apps/app-config/.gitignore @@ -0,0 +1 @@ +node_modules/ diff --git a/tools/tests/apps/app-config/.meteor/.finished-upgraders b/tools/tests/apps/app-config/.meteor/.finished-upgraders new file mode 100644 index 00000000000..910574ce2df --- /dev/null +++ b/tools/tests/apps/app-config/.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/app-config/.meteor/.gitignore b/tools/tests/apps/app-config/.meteor/.gitignore new file mode 100644 index 00000000000..40830374235 --- /dev/null +++ b/tools/tests/apps/app-config/.meteor/.gitignore @@ -0,0 +1 @@ +local diff --git a/tools/tests/apps/app-config/.meteor/.id b/tools/tests/apps/app-config/.meteor/.id new file mode 100644 index 00000000000..a7468fe68d0 --- /dev/null +++ b/tools/tests/apps/app-config/.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 + +h9uim8gzzdn7.vu1xo1jmqcme diff --git a/tools/tests/apps/app-config/.meteor/packages b/tools/tests/apps/app-config/.meteor/packages new file mode 100644 index 00000000000..46098f7d48b --- /dev/null +++ b/tools/tests/apps/app-config/.meteor/packages @@ -0,0 +1,14 @@ +# 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 +static-html # Define static page content in .html files +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 +less # Support .less files for defining CSS styles diff --git a/tools/tests/apps/app-config/.meteor/platforms b/tools/tests/apps/app-config/.meteor/platforms new file mode 100644 index 00000000000..efeba1b50c7 --- /dev/null +++ b/tools/tests/apps/app-config/.meteor/platforms @@ -0,0 +1,2 @@ +server +browser diff --git a/tools/tests/apps/app-config/.meteor/release b/tools/tests/apps/app-config/.meteor/release new file mode 100644 index 00000000000..621e94f0ec9 --- /dev/null +++ b/tools/tests/apps/app-config/.meteor/release @@ -0,0 +1 @@ +none diff --git a/tools/tests/apps/app-config/.meteor/versions b/tools/tests/apps/app-config/.meteor/versions new file mode 100644 index 00000000000..8b323e2c759 --- /dev/null +++ b/tools/tests/apps/app-config/.meteor/versions @@ -0,0 +1,66 @@ +allow-deny@1.1.0 +autoupdate@1.4.0 +babel-compiler@7.0.5 +babel-runtime@1.2.2 +base64@1.0.11 +binary-heap@1.0.10 +blaze-tools@1.0.10 +boilerplate-generator@1.5.0 +caching-compiler@1.1.11 +caching-html-compiler@1.1.2 +callback-hook@1.1.0 +check@1.3.0 +ddp@1.4.0 +ddp-client@2.3.1 +ddp-common@1.4.0 +ddp-server@2.1.2 +diff-sequence@1.1.0 +dispatch:mocha-browser@0.0.4 +dynamic-import@0.3.0 +ecmascript@0.10.5 +ecmascript-runtime@0.5.0 +ecmascript-runtime-client@0.6.2 +ecmascript-runtime-server@0.5.0 +ejson@1.1.0 +es5-shim@4.7.3 +geojson-utils@1.0.10 +hot-code-push@1.0.4 +html-tools@1.0.11 +htmljs@1.0.11 +http@1.4.0 +id-map@1.1.0 +less@2.7.12 +livedata@1.0.18 +logging@1.1.19 +meteor@1.8.3 +meteor-base@1.3.0 +minifier-css@1.3.1 +minifier-js@2.3.3 +minimongo@1.4.3 +modules@0.11.5 +modules-runtime@0.9.2 +mongo@1.4.4 +mongo-dev-server@1.1.0 +mongo-id@1.0.6 +npm-mongo@2.2.33 +ordered-dict@1.1.0 +practicalmeteor:mocha-core@1.0.1 +promise@0.10.2 +random@1.1.0 +reload@1.2.0 +retry@1.1.0 +routepolicy@1.0.12 +server-render@0.3.0 +shell-server@0.3.1 +shim-common@0.1.0 +socket-stream-client@0.1.0 +spacebars-compiler@1.1.3 +standard-minifier-css@1.4.1 +standard-minifier-js@2.3.2 +static-html@1.2.2 +templating-tools@1.1.2 +tracker@1.2.0 +underscore@1.0.10 +url@1.2.0 +webapp@1.5.0 +webapp-hashing@1.0.9 diff --git a/tools/tests/apps/app-config/a.js b/tools/tests/apps/app-config/a.js new file mode 100644 index 00000000000..508c569e069 --- /dev/null +++ b/tools/tests/apps/app-config/a.js @@ -0,0 +1,2 @@ +import { report } from "./tests.js"; +report(module.id); diff --git a/tools/tests/apps/app-config/ab.js b/tools/tests/apps/app-config/ab.js new file mode 100644 index 00000000000..a4c5b255682 --- /dev/null +++ b/tools/tests/apps/app-config/ab.js @@ -0,0 +1,2 @@ +import "./a.js"; +import "./b.js"; diff --git a/tools/tests/apps/app-config/abc.js b/tools/tests/apps/app-config/abc.js new file mode 100644 index 00000000000..07d1effb8f8 --- /dev/null +++ b/tools/tests/apps/app-config/abc.js @@ -0,0 +1,2 @@ +import "./ab.js"; +import "./c.js"; diff --git a/tools/tests/apps/app-config/ac.js b/tools/tests/apps/app-config/ac.js new file mode 100644 index 00000000000..7dc139edf8e --- /dev/null +++ b/tools/tests/apps/app-config/ac.js @@ -0,0 +1,2 @@ +import "./a.js"; +import "./c.js"; diff --git a/tools/tests/apps/app-config/b.js b/tools/tests/apps/app-config/b.js new file mode 100644 index 00000000000..508c569e069 --- /dev/null +++ b/tools/tests/apps/app-config/b.js @@ -0,0 +1,2 @@ +import { report } from "./tests.js"; +report(module.id); diff --git a/tools/tests/apps/app-config/bc.js b/tools/tests/apps/app-config/bc.js new file mode 100644 index 00000000000..402dc1115af --- /dev/null +++ b/tools/tests/apps/app-config/bc.js @@ -0,0 +1,2 @@ +import "./b.js"; +import "./c.js"; diff --git a/tools/tests/apps/app-config/c.js b/tools/tests/apps/app-config/c.js new file mode 100644 index 00000000000..508c569e069 --- /dev/null +++ b/tools/tests/apps/app-config/c.js @@ -0,0 +1,2 @@ +import { report } from "./tests.js"; +report(module.id); diff --git a/tools/tests/apps/app-config/client/main.css b/tools/tests/apps/app-config/client/main.css new file mode 100644 index 00000000000..5b5a91897d9 --- /dev/null +++ b/tools/tests/apps/app-config/client/main.css @@ -0,0 +1,3 @@ +body { + font-weight: 700; +} diff --git a/tools/tests/apps/app-config/client/main.html b/tools/tests/apps/app-config/client/main.html new file mode 100644 index 00000000000..c0e549e6376 --- /dev/null +++ b/tools/tests/apps/app-config/client/main.html @@ -0,0 +1,14 @@ + + app-config + + + +

Welcome to Meteor!

+

Learn Meteor!

+ + diff --git a/tools/tests/apps/app-config/client/main.js b/tools/tests/apps/app-config/client/main.js new file mode 100644 index 00000000000..bebaa30ed8c --- /dev/null +++ b/tools/tests/apps/app-config/client/main.js @@ -0,0 +1,2 @@ +import { report } from "../tests.js"; +report(module.id); diff --git a/tools/tests/apps/app-config/client/main.less b/tools/tests/apps/app-config/client/main.less new file mode 100644 index 00000000000..579899c6d3a --- /dev/null +++ b/tools/tests/apps/app-config/client/main.less @@ -0,0 +1,3 @@ +body { + background: #add8e6; +} diff --git a/tools/tests/apps/app-config/package-lock.json b/tools/tests/apps/app-config/package-lock.json new file mode 100644 index 00000000000..82fe1359d14 --- /dev/null +++ b/tools/tests/apps/app-config/package-lock.json @@ -0,0 +1,683 @@ +{ + "name": "app-config", + "requires": true, + "lockfileVersion": 1, + "dependencies": { + "@babel/runtime": { + "version": "7.0.0-beta.40", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.0.0-beta.40.tgz", + "integrity": "sha512-vIM68NUCWauZJTFoVUG1lggva1I8FLB9zFKwWG7Xjin4FkHpEKJv2y4x1DGVPVt93S5/zHSBj1bXYEuxOkFGzg==", + "requires": { + "core-js": "2.5.3", + "regenerator-runtime": "0.11.1" + } + }, + "core-js": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.3.tgz", + "integrity": "sha1-isw4NFgk8W2DZbfJtCWRaOjtYD4=" + }, + "meteor-node-stubs": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/meteor-node-stubs/-/meteor-node-stubs-0.3.2.tgz", + "integrity": "sha512-l93SS/HutbqBRJODO2m7hup8cYI2acF5bB39+ZvP2BX8HMmCSCXeFH7v0sr4hD7zrVvHQA5UqS0pcDYKn0VM6g==", + "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.1", + "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.10", + "punycode": "1.4.1", + "querystring-es3": "0.2.1", + "readable-stream": "git+https://github.com/meteor/readable-stream.git#d64a64aa6061b9b6855feff4d09e58fb3b2e4502", + "stream-browserify": "2.0.1", + "string_decoder": "1.0.3", + "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.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.9.1.tgz", + "integrity": "sha1-SLokC0WpKA6UdImQull9IWYX/UA=", + "requires": { + "bn.js": "4.11.8", + "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": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "base64-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.2.1.tgz", + "integrity": "sha512-dwVUVIXsBZXwTuwnXI9RK8sBmgq09NDHzyR9SAph9eqk76gKK2JSQmZARC2zRC81JC2QTtxD0ARU5qTS25gIGw==" + }, + "bn.js": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", + "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==" + }, + "brace-expansion": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", + "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", + "requires": { + "balanced-match": "1.0.0", + "concat-map": "0.0.1" + } + }, + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" + }, + "browserify-aes": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.1.0.tgz", + "integrity": "sha512-W2bIMLYoZ9oow7TyePpMJk9l9LY7O3R61a/68bVCDOtnJynnwe3ZeW2IzzSkrQnPKNdJrxVDn3ALZNisSBwb7g==", + "requires": { + "buffer-xor": "1.0.3", + "cipher-base": "1.0.4", + "create-hash": "1.1.3", + "evp_bytestokey": "1.0.3", + "inherits": "2.0.1", + "safe-buffer": "5.1.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.1.0", + "browserify-des": "1.0.0", + "evp_bytestokey": "1.0.3" + } + }, + "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.4", + "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.8", + "randombytes": "2.0.5" + } + }, + "browserify-sign": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz", + "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=", + "requires": { + "bn.js": "4.11.8", + "browserify-rsa": "4.0.1", + "create-hash": "1.1.3", + "create-hmac": "1.1.6", + "elliptic": "6.4.0", + "inherits": "2.0.1", + "parse-asn1": "5.1.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.1", + "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.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "requires": { + "inherits": "2.0.1", + "safe-buffer": "5.1.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.8", + "elliptic": "6.4.0" + } + }, + "create-hash": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.1.3.tgz", + "integrity": "sha1-YGBCrIuSYnUPSDyt2rD1gZFy2P0=", + "requires": { + "cipher-base": "1.0.4", + "inherits": "2.0.1", + "ripemd160": "2.0.1", + "sha.js": "2.4.9" + } + }, + "create-hmac": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.6.tgz", + "integrity": "sha1-rLniIaThe9sHbpBlfEK5PjcmzwY=", + "requires": { + "cipher-base": "1.0.4", + "create-hash": "1.1.3", + "inherits": "2.0.1", + "ripemd160": "2.0.1", + "safe-buffer": "5.1.1", + "sha.js": "2.4.9" + } + }, + "crypto-browserify": { + "version": "3.11.1", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.11.1.tgz", + "integrity": "sha512-Na7ZlwCOqoaW5RwUK1WpXws2kv8mNhWdTlzob0UXulk6G9BDbyiJaGTYBIX61Ozn9l1EPPJpICZb4DaOpT9NlQ==", + "requires": { + "browserify-cipher": "1.0.0", + "browserify-sign": "4.0.4", + "create-ecdh": "4.0.0", + "create-hash": "1.1.3", + "create-hmac": "1.1.6", + "diffie-hellman": "5.0.2", + "inherits": "2.0.1", + "pbkdf2": "3.0.14", + "public-encrypt": "4.0.0", + "randombytes": "2.0.5" + } + }, + "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.8", + "miller-rabin": "4.0.1", + "randombytes": "2.0.5" + } + }, + "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.4.0", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.0.tgz", + "integrity": "sha1-ysmvh2LIWDYYcAPI3+GT5eLq5d8=", + "requires": { + "bn.js": "4.11.8", + "brorand": "1.1.0", + "hash.js": "1.1.3", + "hmac-drbg": "1.0.1", + "inherits": "2.0.1", + "minimalistic-assert": "1.0.0", + "minimalistic-crypto-utils": "1.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.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "requires": { + "md5.js": "1.3.4", + "safe-buffer": "5.1.1" + } + }, + "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-base": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-2.0.2.tgz", + "integrity": "sha1-ZuodhW206KVHDK32/OI65SRO8uE=", + "requires": { + "inherits": "2.0.1" + } + }, + "hash.js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz", + "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==", + "requires": { + "inherits": "2.0.3", + "minimalistic-assert": "1.0.0" + }, + "dependencies": { + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + } + } + }, + "hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "requires": { + "hash.js": "1.1.3", + "minimalistic-assert": "1.0.0", + "minimalistic-crypto-utils": "1.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=" + }, + "md5.js": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.4.tgz", + "integrity": "sha1-6b296UogpawYsENA/Fdk1bCdkB0=", + "requires": { + "hash-base": "3.0.4", + "inherits": "2.0.1" + }, + "dependencies": { + "hash-base": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", + "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", + "requires": { + "inherits": "2.0.1", + "safe-buffer": "5.1.1" + } + } + } + }, + "miller-rabin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "requires": { + "bn.js": "4.11.8", + "brorand": "1.1.0" + } + }, + "minimalistic-assert": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz", + "integrity": "sha1-cCvi3aazf0g2vLP121ZkG2Sh09M=" + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" + }, + "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.8" + } + }, + "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.1.0", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.0.tgz", + "integrity": "sha1-N8T5t+06tlx0gXtfJICTf7+XxxI=", + "requires": { + "asn1.js": "4.9.1", + "browserify-aes": "1.1.0", + "create-hash": "1.1.3", + "evp_bytestokey": "1.0.3", + "pbkdf2": "3.0.14" + } + }, + "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.14", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.14.tgz", + "integrity": "sha512-gjsZW9O34fm0R7PaLHRJmLLVfSoesxztjPjE9o6R+qtVJij90ltg1joIovN9GKrRW3t1PzhDDG3UMEMFfZ+1wA==", + "requires": { + "create-hash": "1.1.3", + "create-hmac": "1.1.6", + "ripemd160": "2.0.1", + "safe-buffer": "5.1.1", + "sha.js": "2.4.9" + } + }, + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=" + }, + "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.8", + "browserify-rsa": "4.0.1", + "create-hash": "1.1.3", + "parse-asn1": "5.1.0", + "randombytes": "2.0.5" + } + }, + "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.5", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.5.tgz", + "integrity": "sha512-8T7Zn1AhMsQ/HI1SjcCfT/t4ii3eAqco3yOcSzS4mozsOz69lHLsoMXmF9nZgnFanYscnSlUSgs8uZyKzpE6kg==", + "requires": { + "safe-buffer": "5.1.1" + } + }, + "readable-stream": { + "version": "git+https://github.com/meteor/readable-stream.git#d64a64aa6061b9b6855feff4d09e58fb3b2e4502", + "requires": { + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "safe-buffer": "5.1.1", + "string_decoder": "1.0.3", + "util-deprecate": "1.0.2" + }, + "dependencies": { + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + } + } + }, + "rimraf": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", + "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", + "requires": { + "glob": "7.1.2" + } + }, + "ripemd160": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.1.tgz", + "integrity": "sha1-D0WEKVxTo2KK9+bXmsohzlfRxuc=", + "requires": { + "hash-base": "2.0.2", + "inherits": "2.0.1" + } + }, + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" + }, + "sha.js": { + "version": "2.4.9", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.9.tgz", + "integrity": "sha512-G8zektVqbiPHrylgew9Zg1VRB1L/DtXNUVAM6q4QLy8NE3qtHlFXTf8VLL4k1Yl6c7NMjtZUTdXV+X44nFaT6A==", + "requires": { + "inherits": "2.0.1", + "safe-buffer": "5.1.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#d64a64aa6061b9b6855feff4d09e58fb3b2e4502" + } + }, + "string_decoder": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "requires": { + "safe-buffer": "5.1.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.10" + } + }, + "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.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" + } + } +} diff --git a/tools/tests/apps/app-config/package.json b/tools/tests/apps/app-config/package.json new file mode 100644 index 00000000000..eeb7e1bb759 --- /dev/null +++ b/tools/tests/apps/app-config/package.json @@ -0,0 +1,11 @@ +{ + "name": "app-config", + "private": true, + "scripts": { + "start": "meteor run" + }, + "dependencies": { + "@babel/runtime": "^7.0.0-beta.36", + "meteor-node-stubs": "^0.3.2" + } +} diff --git a/tools/tests/apps/app-config/server/main.js b/tools/tests/apps/app-config/server/main.js new file mode 100644 index 00000000000..bebaa30ed8c --- /dev/null +++ b/tools/tests/apps/app-config/server/main.js @@ -0,0 +1,2 @@ +import { report } from "../tests.js"; +report(module.id); diff --git a/tools/tests/apps/app-config/tests.js b/tools/tests/apps/app-config/tests.js new file mode 100644 index 00000000000..0882961844f --- /dev/null +++ b/tools/tests/apps/app-config/tests.js @@ -0,0 +1,97 @@ +import assert from "assert"; + +const ids = []; +export function report(id) { + ids.push(id); +} + +const startupPromise = new Promise(resolve => { + Meteor.startup(resolve); +}); + +describe("meteor.mainModule", () => { + // These tests test the consequences of having various meteor.mainModule + // configurations in package.json. + const config = require("./package.json").meteor; + + if (Meteor.isClient) { + it("always loads static HTML", () => { + assert.strictEqual( + document.getElementsByTagName("h1").item(0).innerText, + "Welcome to Meteor!" + ); + + assert.strictEqual( + document.getElementsByTagName("h2").item(0).innerText, + "Learn Meteor!" + ); + + const listItems = document + .getElementById("meteor-reading-list") + .getElementsByTagName("li"); + assert.strictEqual(listItems.length, 4); + }); + + it("always loads CSS resources", () => { + let { fontWeight } = getComputedStyle(document.body); + assert(fontWeight === "bold" || + fontWeight === "700", + fontWeight); + }); + + it("always loads LESS styles", () => { + assert.strictEqual( + getComputedStyle(document.body)["background-color"], + "rgb(173, 216, 230)" // #add8e6 + ); + }); + } + + it("loads the right files", async () => { + await startupPromise; + + function checkNoMainModule() { + assert.deepEqual(ids, [ + "/a.js", + "/b.js", + "/c.js", + Meteor.isClient + ? "/client/main.js" + : "/server/main.js" + ]); + } + + if (! config || + ! config.mainModule) { + return checkNoMainModule(); + } + + let mainId; + + if (Meteor.isClient) { + mainId = + config.mainModule.client || + config.mainModule.web; + console.log("client config:", config); + } else if (Meteor.isServer) { + mainId = + config.mainModule.server || + config.mainModule.os; + console.log("server config:", config); + } + + if (! mainId) { + return checkNoMainModule(); + } + + const absId = require.resolve("./" + mainId); + const basename = absId.split("/").pop(); + const name = basename.split(".", 1)[0]; + const chars = name.split(""); + + assert.deepEqual( + ids, + chars.map(ch => "/" + ch + ".js"), + ); + }); +});