diff --git a/.circleci/config.yml b/.circleci/config.yml index 38c0968f0e..0a2704fe2c 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -67,7 +67,7 @@ build_machine_environment: &build_machine_environment machine: true environment: # This multiplier scales the waitSecs for selftests. - TIMEOUT_SCALE_FACTOR: 4 + TIMEOUT_SCALE_FACTOR: 8 # These, mostly overlapping, flags ensure that CircleCI is as pretty as # possible for a non-interactive environment. See also: --headless. @@ -124,13 +124,13 @@ jobs: name: Get Ready command: | eval $PRE_TEST_COMMANDS; - ./meteor --help - # shouldn't take longer than 5 minutes - no_output_timeout: 5m + ./meteor --get-ready + # shouldn't take longer than 20 minutes + no_output_timeout: 20m # Clear dev_bundle/.npm to ensure consistent test runs. - run: name: Clear npm cache - command: ./meteor npm cache clear + command: ./meteor npm cache clear --force # Since PhantomJS has been removed from dev_bundle/lib/node_modules # (#6905), but self-test still needs it, install it now. - run: @@ -164,6 +164,9 @@ jobs: <<: *run_env_change - attach_workspace: at: . + - run: + name: "Print environment" + command: printenv - run: name: "Running warehouse self-tests" command: | @@ -197,6 +200,9 @@ jobs: <<: *run_env_change - attach_workspace: at: . + - run: + name: "Print environment" + command: printenv - run: name: "Running self-test (1): A-Com" command: | @@ -231,6 +237,9 @@ jobs: <<: *run_env_change - attach_workspace: at: . + - run: + name: "Print environment" + command: printenv - run: name "Running self-test (2): Con-K" command: | @@ -265,6 +274,9 @@ jobs: <<: *run_env_change - attach_workspace: at: . + - run: + name: "Print environment" + command: printenv - run: name: "Running self-test (3): L-O" command: | @@ -299,6 +311,9 @@ jobs: <<: *run_env_change - attach_workspace: at: . + - run: + name: "Print environment" + command: printenv - run: name: "Running self-test (4): P" command: | @@ -333,6 +348,9 @@ jobs: <<: *run_env_change - attach_workspace: at: . + - run: + name: "Print environment" + command: printenv - run: name: "Running self-test (5): Run" command: | @@ -367,10 +385,13 @@ jobs: <<: *run_env_change - attach_workspace: at: . + - run: + name: "Print environment" + command: printenv - run: name: "Running self-test (6): R-S" command: | - eval "$PRE_TEST_COMMANDS"; + eval $PRE_TEST_COMMANDS; ./meteor self-test \ --exclude "${SELF_TEST_EXCLUDE}" \ --headless \ @@ -401,6 +422,9 @@ jobs: <<: *run_env_change - attach_workspace: at: . + - run: + name: "Print environment" + command: printenv - run: name: "Running self-test (7): Sp-Z" command: | diff --git a/History.md b/History.md index 34d91c088a..eecbea7d8c 100644 --- a/History.md +++ b/History.md @@ -20,6 +20,82 @@ using `for...of` loops, spread operator, `yield*`, and destructuring assignments. [PR #8888](https://github.com/meteor/meteor/pull/8888) +## v1.5.2, TBD + +* Node 4.8.4 has been patched to include + https://github.com/nodejs/node/pull/14829, an important PR implemented + by our own @abernix (:tada:), which fixes a faulty backport of garbage + collection-related logic in V8 that was causing occasional segmentation + faults during Meteor development and testing, ever since Node 4.6.2 + (Meteor 1.4.2.3). When Node 4.8.5 is officially released with these + changes, we will immediately publish a small follow-up release. + [Issue #8648](https://github.com/meteor/meteor/issues/8648) + +* When Meteor writes to watched files during the build process, it no + longer relies on file watchers to detect the change and invalidate the + optimistic file system cache, which should fix a number of problems + related by the symptom of endless rebuilding. + [Issue #8988](https://github.com/meteor/meteor/issues/8988) + [Issue #8942](https://github.com/meteor/meteor/issues/8942) + [PR #9007](https://github.com/meteor/meteor/pull/9007) + +* The `cordova-lib` npm package has been updated to 7.0.1, along with + cordova-android (6.2.3) and cordova-ios (4.4.0), and various plugins. + [PR #8919](https://github.com/meteor/meteor/pull/8919) resolves the + umbrella [issue #8686](https://github.com/meteor/meteor/issues/8686), as + well as several Android build issues: + [#8408](https://github.com/meteor/meteor/issues/8408), + [#8424](https://github.com/meteor/meteor/issues/8424), and + [#8464](https://github.com/meteor/meteor/issues/8464). + +* The [`boilerplate-generator`](https://github.com/meteor/meteor/tree/release-1.5.2/packages/boilerplate-generator) + package responsible for generating initial HTML documents for Meteor + apps has been refactored by @stevenhao to avoid using the + `spacebars`-related packages, which means it is now possible to remove + Blaze as a dependency from the server as well as the client. + [PR #8820](https://github.com/meteor/meteor/pull/8820) + +* The `meteor-babel` package has been upgraded to version 0.23.1. + +* The `reify` npm package has been upgraded to version 0.12.0, which + includes a minor breaking + [change](https://github.com/benjamn/reify/commit/8defc645e556429283e0b522fd3afababf6525ea) + that correctly skips exports named `default` in `export * from "module"` + declarations. If you have any wrapper modules that re-export another + module's exports using `export * from "./wrapped/module"`, and the + wrapped module has a `default` export that you want to be included, you + should now explicitly re-export `default` using a second declaration: + ```js + export * from "./wrapped/module"; + export { default } "./wrapped/module"; + ``` + +* The `meteor-promise` package has been upgraded to version 0.8.5, + and the `promise` polyfill package has been upgraded to 8.0.1. + +* The `semver` npm package has been upgraded to version 5.3.0. + [PR #8859](https://github.com/meteor/meteor/pull/8859) + +* The `faye-websocket` npm package has been upgraded to version 0.11.1, + and its dependency `websocket-driver` has been upgraded to a version + containing [this fix](https://github.com/faye/websocket-driver-node/issues/21), + thanks to [@sdarnell](https://github.com/sdarnell). + [meteor-feature-requests#160](https://github.com/meteor/meteor-feature-requests/issues/160) + +* The `uglify-js` npm package has been upgraded to version 3.0.28. + +* Thanks to PRs [#8960](https://github.com/meteor/meteor/pull/8960) and + [#9018](https://github.com/meteor/meteor/pull/9018) by @GeoffreyBooth, a + [`coffeescript-compiler`](https://github.com/meteor/meteor/tree/release-1.5.2/packages/non-core/coffeescript-compiler) + package has been extracted from the `coffeescript` package, similar to + how the `babel-compiler` package is separate from the `ecmascript` + package, so that other packages (such as + [`vue-coffee`](https://github.com/meteor-vue/vue-meteor/tree/master/packages/vue-coffee)) + can make use of `coffeescript-compiler`. All `coffeescript`-related + packages have been moved to + [`packages/non-core`](https://github.com/meteor/meteor/tree/release-1.5.2/packages/non-core), + so that they can be published independently from Meteor releases. + * `meteor list --tree` can now be used to list all transitive package dependencies (and versions) in an application. Weakly referenced dependencies can also be listed by using the `--weak` option. For more information, run @@ -50,12 +126,22 @@ [Issue #5121](https://github.com/meteor/meteor/issues/5121) [PR #8917](https://github.com/meteor/meteor/pull/8917) +* The `"env"` field is now supported in `.babelrc` files. + [PR #8963](https://github.com/meteor/meteor/pull/8963) + * Files contained by `client/compatibility/` directories or added with `api.addFiles(files, ..., { bare: true })` are now evaluated before importing modules with `require`, which may be a breaking change if you depend on the interleaving of `bare` files with eager module evaluation. [PR #8972](https://github.com/meteor/meteor/pull/8972) +* When `meteor test-packages` runs in a browser, uncaught exceptions will + now be displayed above the test results, along with the usual summary of + test failures, in case those uncaught errors have something to do with + later test failures. + [Issue #4979](https://github.com/meteor/meteor/issues/4979) + [PR #9034](https://github.com/meteor/meteor/pull/9034) + ## v1.5.1, 2017-07-12 * Node has been upgraded to version 4.8.4. diff --git a/meteor b/meteor index dcbbf84a68..8661fb2933 100755 --- a/meteor +++ b/meteor @@ -1,6 +1,6 @@ #!/usr/bin/env bash -BUNDLE_VERSION=4.8.30 +BUNDLE_VERSION=4.8.35 # OS Check. Put here because here is where we download the precompiled # bundles that are arch specific. diff --git a/packages/accounts-password/password_server.js b/packages/accounts-password/password_server.js index b088b0aafd..93af180f05 100644 --- a/packages/accounts-password/password_server.js +++ b/packages/accounts-password/password_server.js @@ -546,17 +546,17 @@ Meteor.methods({forgotPassword: function (options) { Accounts.sendResetPasswordEmail(user._id, caseSensitiveEmail); }}); -// send the user an email with a link that when opened allows the user -// to set a new password, without the old password. - /** - * @summary Send an email with a link the user can use to reset their password. + * @summary Generates a reset token and saves it into the database. * @locus Server - * @param {String} userId The id of the user to send email to. - * @param {String} [email] Optional. Which address of the user's to send the email to. This address must be in the user's `emails` list. Defaults to the first email in the list. + * @param {String} userId The id of the user to generate the reset token for. + * @param {String} email Which address of the user to generate the reset token for. This address must be in the user's `emails` list. If `null`, defaults to the first email in the list. + * @param {String} reason `resetPassword` or `enrollAccount`. + * @param {Object} [extraTokenData] Optional additional data to be added into the token record. + * @returns {Object} Object with {email, user, token} values. * @importFromPackage accounts-base */ -Accounts.sendResetPasswordEmail = function (userId, email) { +Accounts.generateResetToken = function (userId, email, reason, extraTokenData) { // Make sure the user exists, and email is one of their addresses. var user = Meteor.users.findOne(userId); if (!user) { @@ -574,44 +574,146 @@ Accounts.sendResetPasswordEmail = function (userId, email) { } var token = Random.secret(); - var when = new Date(); var tokenRecord = { token: token, email: email, - when: when, - reason: 'reset' + when: new Date() }; - Meteor.users.update(userId, {$set: { - "services.password.reset": tokenRecord + + if (reason === 'resetPassword') { + tokenRecord.reason = 'reset'; + } else if (reason === 'enrollAccount') { + tokenRecord.reason = 'enroll'; + } else if (reason) { + // fallback so that this function can be used for unknown reasons as well + tokenRecord.reason = reason; + } + + if (extraTokenData) { + _.extend(tokenRecord, extraTokenData); + } + + Meteor.users.update({_id: user._id}, {$set: { + 'services.password.reset': tokenRecord }}); + // before passing to template, update user object with new token Meteor._ensure(user, 'services', 'password').reset = tokenRecord; - var resetPasswordUrl = Accounts.urls.resetPassword(token); + return {email, user, token}; +}; - var options = { - to: email, - from: Accounts.emailTemplates.resetPassword.from - ? Accounts.emailTemplates.resetPassword.from(user) - : Accounts.emailTemplates.from, - subject: Accounts.emailTemplates.resetPassword.subject(user) - }; - - if (typeof Accounts.emailTemplates.resetPassword.text === 'function') { - options.text = - Accounts.emailTemplates.resetPassword.text(user, resetPasswordUrl); +/** + * @summary Generates an e-mail verification token and saves it into the database. + * @locus Server + * @param {String} userId The id of the user to generate the e-mail verification token for. + * @param {String} email Which address of the user to generate the e-mail verification token for. This address must be in the user's `emails` list. If `null`, defaults to the first unverified email in the list. + * @param {Object} [extraTokenData] Optional additional data to be added into the token record. + * @returns {Object} Object with {email, user, token} values. + * @importFromPackage accounts-base + */ +Accounts.generateVerificationToken = function (userId, email, extraTokenData) { + // Make sure the user exists, and email is one of their addresses. + var user = Meteor.users.findOne(userId); + if (!user) { + handleError("Can't find user"); } - if (typeof Accounts.emailTemplates.resetPassword.html === 'function') { - options.html = - Accounts.emailTemplates.resetPassword.html(user, resetPasswordUrl); + // pick the first unverified email if we weren't passed an email. + if (!email) { + var emailRecord = _.find(user.emails || [], function (e) { return !e.verified; }); + email = (emailRecord || {}).address; + + if (!email) { + handleError("That user has no unverified email addresses."); + } + } + + // make sure we have a valid email + if (!email || !_.contains(_.pluck(user.emails || [], 'address'), email)) { + handleError("No such email for user."); + } + + var token = Random.secret(); + var tokenRecord = { + token: token, + // TODO: This should probably be renamed to "email" to match reset token record. + address: email, + when: new Date() + }; + + if (extraTokenData) { + _.extend(tokenRecord, extraTokenData); + } + + Meteor.users.update({_id: user._id}, {$push: { + 'services.email.verificationTokens': tokenRecord + }}); + + // before passing to template, update user object with new token + Meteor._ensure(user, 'services', 'email'); + if (!user.services.email.verificationTokens) { + user.services.email.verificationTokens = []; + } + user.services.email.verificationTokens.push(tokenRecord); + + return {email, user, token}; +}; + +/** + * @summary Creates options for email sending for reset password and enroll account emails. + * You can use this function when customizing a reset password or enroll account email sending. + * @locus Server + * @param {Object} email Which address of the user's to send the email to. + * @param {Object} user The user object to generate options for. + * @param {String} url URL to which user is directed to confirm the email. + * @param {String} reason `resetPassword` or `enrollAccount`. + * @returns {Object} Options which can be passed to `Email.send`. + * @importFromPackage accounts-base + */ +Accounts.generateOptionsForEmail = function (email, user, url, reason) { + var options = { + to: email, + from: Accounts.emailTemplates[reason].from + ? Accounts.emailTemplates[reason].from(user) + : Accounts.emailTemplates.from, + subject: Accounts.emailTemplates[reason].subject(user) + }; + + if (typeof Accounts.emailTemplates[reason].text === 'function') { + options.text = Accounts.emailTemplates[reason].text(user, url); + } + + if (typeof Accounts.emailTemplates[reason].html === 'function') { + options.html = Accounts.emailTemplates[reason].html(user, url); } if (typeof Accounts.emailTemplates.headers === 'object') { options.headers = Accounts.emailTemplates.headers; } + return options; +}; + +// send the user an email with a link that when opened allows the user +// to set a new password, without the old password. + +/** + * @summary Send an email with a link the user can use to reset their password. + * @locus Server + * @param {String} userId The id of the user to send email to. + * @param {String} [email] Optional. Which address of the user's to send the email to. This address must be in the user's `emails` list. Defaults to the first email in the list. + * @param {Object} [extraTokenData] Optional additional data to be added into the token record. + * @returns {Object} Object with {email, user, token, url, options} values. + * @importFromPackage accounts-base + */ +Accounts.sendResetPasswordEmail = function (userId, email, extraTokenData) { + const {email: realEmail, user, token} = + Accounts.generateResetToken(userId, email, 'resetPassword', extraTokenData); + const url = Accounts.urls.resetPassword(token); + const options = Accounts.generateOptionsForEmail(realEmail, user, url, 'resetPassword'); Email.send(options); + return {email: realEmail, user, token, url, options}; }; // send the user an email informing them that their account was created, with @@ -627,65 +729,17 @@ Accounts.sendResetPasswordEmail = function (userId, email) { * @locus Server * @param {String} userId The id of the user to send email to. * @param {String} [email] Optional. Which address of the user's to send the email to. This address must be in the user's `emails` list. Defaults to the first email in the list. + * @param {Object} [extraTokenData] Optional additional data to be added into the token record. + * @returns {Object} Object with {email, user, token, url, options} values. * @importFromPackage accounts-base */ -Accounts.sendEnrollmentEmail = function (userId, email) { - // XXX refactor! This is basically identical to sendResetPasswordEmail. - - // Make sure the user exists, and email is in their addresses. - var user = Meteor.users.findOne(userId); - if (!user) { - throw new Error("Can't find user"); - } - // pick the first email if we weren't passed an email. - if (!email && user.emails && user.emails[0]) { - email = user.emails[0].address; - } - // make sure we have a valid email - if (!email || !_.contains(_.pluck(user.emails || [], 'address'), email)) { - throw new Error("No such email for user."); - } - - var token = Random.secret(); - var when = new Date(); - var tokenRecord = { - token: token, - email: email, - when: when, - reason: 'enroll' - }; - Meteor.users.update(userId, {$set: { - "services.password.reset": tokenRecord - }}); - - // before passing to template, update user object with new token - Meteor._ensure(user, 'services', 'password').reset = tokenRecord; - - var enrollAccountUrl = Accounts.urls.enrollAccount(token); - - var options = { - to: email, - from: Accounts.emailTemplates.enrollAccount.from - ? Accounts.emailTemplates.enrollAccount.from(user) - : Accounts.emailTemplates.from, - subject: Accounts.emailTemplates.enrollAccount.subject(user) - }; - - if (typeof Accounts.emailTemplates.enrollAccount.text === 'function') { - options.text = - Accounts.emailTemplates.enrollAccount.text(user, enrollAccountUrl); - } - - if (typeof Accounts.emailTemplates.enrollAccount.html === 'function') { - options.html = - Accounts.emailTemplates.enrollAccount.html(user, enrollAccountUrl); - } - - if (typeof Accounts.emailTemplates.headers === 'object') { - options.headers = Accounts.emailTemplates.headers; - } - +Accounts.sendEnrollmentEmail = function (userId, email, extraTokenData) { + const {email: realEmail, user, token} = + Accounts.generateResetToken(userId, email, 'enrollAccount', extraTokenData); + const url = Accounts.urls.enrollAccount(token); + const options = Accounts.generateOptionsForEmail(realEmail, user, url, 'enrollAccount'); Email.send(options); + return {email: realEmail, user, token, url, options}; }; @@ -782,71 +836,21 @@ Meteor.methods({resetPassword: function (token, newPassword) { * @locus Server * @param {String} userId The id of the user to send email to. * @param {String} [email] Optional. Which address of the user's to send the email to. This address must be in the user's `emails` list. Defaults to the first unverified email in the list. + * @param {Object} [extraTokenData] Optional additional data to be added into the token record. + * @returns {Object} Object with {email, user, token, url, options} values. * @importFromPackage accounts-base */ -Accounts.sendVerificationEmail = function (userId, address) { +Accounts.sendVerificationEmail = function (userId, email, extraTokenData) { // XXX Also generate a link using which someone can delete this // account if they own said address but weren't those who created // this account. - // Make sure the user exists, and address is one of their addresses. - var user = Meteor.users.findOne(userId); - if (!user) - throw new Error("Can't find user"); - // pick the first unverified address if we weren't passed an address. - if (!address) { - var email = _.find(user.emails || [], - function (e) { return !e.verified; }); - address = (email || {}).address; - - if (!address) { - throw new Error("That user has no unverified email addresses."); - } - } - // make sure we have a valid address - if (!address || !_.contains(_.pluck(user.emails || [], 'address'), address)) - throw new Error("No such email address for user."); - - - var tokenRecord = { - token: Random.secret(), - address: address, - when: new Date()}; - Meteor.users.update( - {_id: userId}, - {$push: {'services.email.verificationTokens': tokenRecord}}); - - // before passing to template, update user object with new token - Meteor._ensure(user, 'services', 'email'); - if (!user.services.email.verificationTokens) { - user.services.email.verificationTokens = []; - } - user.services.email.verificationTokens.push(tokenRecord); - - var verifyEmailUrl = Accounts.urls.verifyEmail(tokenRecord.token); - - var options = { - to: address, - from: Accounts.emailTemplates.verifyEmail.from - ? Accounts.emailTemplates.verifyEmail.from(user) - : Accounts.emailTemplates.from, - subject: Accounts.emailTemplates.verifyEmail.subject(user) - }; - - if (typeof Accounts.emailTemplates.verifyEmail.text === 'function') { - options.text = - Accounts.emailTemplates.verifyEmail.text(user, verifyEmailUrl); - } - - if (typeof Accounts.emailTemplates.verifyEmail.html === 'function') - options.html = - Accounts.emailTemplates.verifyEmail.html(user, verifyEmailUrl); - - if (typeof Accounts.emailTemplates.headers === 'object') { - options.headers = Accounts.emailTemplates.headers; - } - + const {email: realEmail, user, token} = + Accounts.generateVerificationToken(userId, email, extraTokenData); + const url = Accounts.urls.verifyEmail(token); + const options = Accounts.generateOptionsForEmail(realEmail, user, url, 'verifyEmail'); Email.send(options); + return {email: realEmail, user, token, url, options}; }; // Take token from sendVerificationEmail, mark the email as verified, diff --git a/packages/babel-compiler/.npm/package/npm-shrinkwrap.json b/packages/babel-compiler/.npm/package/npm-shrinkwrap.json index 0aa725dbc9..d32b4b6b14 100644 --- a/packages/babel-compiler/.npm/package/npm-shrinkwrap.json +++ b/packages/babel-compiler/.npm/package/npm-shrinkwrap.json @@ -1,9 +1,9 @@ { "dependencies": { "acorn": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.0.3.tgz", - "from": "acorn@>=5.0.0 <5.1.0" + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.1.1.tgz", + "from": "acorn@>=5.1.1 <5.2.0" }, "ansi-regex": { "version": "2.1.1", @@ -280,9 +280,9 @@ "from": "babel-plugin-transform-es2015-modules-commonjs@>=6.22.0 <7.0.0" }, "babel-plugin-transform-es2015-modules-reify": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-reify/-/babel-plugin-transform-es2015-modules-reify-0.11.2.tgz", - "from": "babel-plugin-transform-es2015-modules-reify@>=0.11.0 <0.12.0" + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-reify/-/babel-plugin-transform-es2015-modules-reify-0.12.0.tgz", + "from": "babel-plugin-transform-es2015-modules-reify@>=0.12.0 <0.13.0" }, "babel-plugin-transform-es2015-object-super": { "version": "6.24.1", @@ -590,9 +590,9 @@ "from": "loose-envify@>=1.0.0 <2.0.0" }, "meteor-babel": { - "version": "0.22.0", - "resolved": "https://registry.npmjs.org/meteor-babel/-/meteor-babel-0.22.0.tgz", - "from": "meteor-babel@0.22.0" + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/meteor-babel/-/meteor-babel-0.23.1.tgz", + "from": "meteor-babel@0.23.1" }, "meteor-babel-helpers": { "version": "0.0.3", @@ -692,9 +692,9 @@ } }, "reify": { - "version": "0.11.24", - "resolved": "https://registry.npmjs.org/reify/-/reify-0.11.24.tgz", - "from": "reify@>=0.11.18 <0.12.0" + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/reify/-/reify-0.12.0.tgz", + "from": "reify@>=0.12.0 <0.13.0" }, "repeating": { "version": "2.0.1", diff --git a/packages/babel-compiler/babel-compiler.js b/packages/babel-compiler/babel-compiler.js index c10289c199..ecc2428bb6 100644 --- a/packages/babel-compiler/babel-compiler.js +++ b/packages/babel-compiler/babel-compiler.js @@ -300,6 +300,16 @@ BCp._inferHelper = function ( merge(babelOptions, babelrc, "presets"); merge(babelOptions, babelrc, "plugins"); + const babelEnv = (process.env.BABEL_ENV || + process.env.NODE_ENV || + "development"); + if (babelrc && babelrc.env && babelrc.env[babelEnv]) { + const env = babelrc.env[babelEnv]; + walkBabelRC(env); + merge(babelOptions, env, "presets"); + merge(babelOptions, env, "plugins"); + } + return !! (babelrc.presets || babelrc.plugins); }; diff --git a/packages/babel-compiler/package.js b/packages/babel-compiler/package.js index 8b8731b79a..a48ba5a3eb 100644 --- a/packages/babel-compiler/package.js +++ b/packages/babel-compiler/package.js @@ -6,11 +6,11 @@ Package.describe({ // isn't possible because you can't publish a non-recommended // release with package versions that don't have a pre-release // identifier at the end (eg, -dev) - version: '6.19.4' + version: '6.20.0' }); Npm.depends({ - 'meteor-babel': '0.22.0' + 'meteor-babel': '0.23.1' }); Package.onUse(function (api) { diff --git a/packages/boilerplate-generator-tests/package.js b/packages/boilerplate-generator-tests/package.js index ff30ae3ce1..b724b16212 100644 --- a/packages/boilerplate-generator-tests/package.js +++ b/packages/boilerplate-generator-tests/package.js @@ -1,8 +1,13 @@ -Npm.depends({'parse5': '3.0.2'}); Package.describe({ - // These tests are in a separate package so that we can Npm.depend on parse5, a html parsing library + // These tests are in a separate package so that we can Npm.depend on + // parse5, a html parsing library. summary: "Tests for the boilerplate-generator package", - version: '1.0.0' + version: '1.0.0', + documentation: null +}); + +Npm.depends({ + parse5: '3.0.2' }); Package.onTest(function (api) { diff --git a/packages/boilerplate-generator/package.js b/packages/boilerplate-generator/package.js index 23fb12dcbb..951584f37b 100644 --- a/packages/boilerplate-generator/package.js +++ b/packages/boilerplate-generator/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Generates the boilerplate html from program's manifest", - version: '1.1.2' + version: '1.2.0' }); Package.onUse(api => { diff --git a/packages/constraint-solver/constraint-solver.js b/packages/constraint-solver/constraint-solver.js index 8e4b78be21..435c312769 100644 --- a/packages/constraint-solver/constraint-solver.js +++ b/packages/constraint-solver/constraint-solver.js @@ -186,6 +186,10 @@ CS.isConstraintSatisfied = function (pkg, vConstraint, version) { var cVersion = simpleConstraint.versionString; return (cVersion === version); } else if (type === 'compatible-with') { + if (typeof simpleConstraint.test === "function") { + return simpleConstraint.test(version); + } + var cv = PV.parse(simpleConstraint.versionString); var v = PV.parse(version); diff --git a/packages/crosswalk/package.js b/packages/crosswalk/package.js index 1dc6923f67..2e7d8b382b 100644 --- a/packages/crosswalk/package.js +++ b/packages/crosswalk/package.js @@ -6,5 +6,5 @@ instead of the System WebView on Android", }); Cordova.depends({ - 'cordova-plugin-crosswalk-webview': '2.2.0' + 'cordova-plugin-crosswalk-webview': '2.3.0' }); diff --git a/packages/ddp-client/.npm/package/npm-shrinkwrap.json b/packages/ddp-client/.npm/package/npm-shrinkwrap.json index 9007897712..a44010e437 100644 --- a/packages/ddp-client/.npm/package/npm-shrinkwrap.json +++ b/packages/ddp-client/.npm/package/npm-shrinkwrap.json @@ -1,23 +1,14 @@ { "dependencies": { "faye-websocket": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.0.tgz", - "from": "faye-websocket@0.11.0", - "dependencies": { - "websocket-driver": { - "version": "0.6.4", - "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.6.4.tgz", - "from": "websocket-driver@>=0.5.1", - "dependencies": { - "websocket-extensions": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.1.tgz", - "from": "websocket-extensions@>=0.1.1" - } - } - } - } + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.1.tgz", + "from": "faye-websocket@0.11.1" + }, + "http-parser-js": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.4.5.tgz", + "from": "http-parser-js@>=0.4.0" }, "lolex": { "version": "1.4.0", @@ -28,6 +19,16 @@ "version": "0.1.3", "resolved": "https://registry.npmjs.org/permessage-deflate/-/permessage-deflate-0.1.3.tgz", "from": "permessage-deflate@0.1.3" + }, + "websocket-driver": { + "version": "0.6.5", + "resolved": "https://github.com/faye/websocket-driver-node/tarball/1325828a9e8b5e29c7b4758995efdb84703919ad", + "from": "https://github.com/faye/websocket-driver-node/tarball/1325828a9e8b5e29c7b4758995efdb84703919ad" + }, + "websocket-extensions": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.1.tgz", + "from": "websocket-extensions@>=0.1.1" } } } diff --git a/packages/ddp-client/package.js b/packages/ddp-client/package.js index 59667d5992..8afeb25c69 100644 --- a/packages/ddp-client/package.js +++ b/packages/ddp-client/package.js @@ -1,11 +1,16 @@ Package.describe({ summary: "Meteor's latency-compensated distributed data client", - version: '2.0.0', + version: '2.1.0', documentation: null }); Npm.depends({ - "faye-websocket": "0.11.0", + "faye-websocket": "0.11.1", + // TODO Remove this direct websocket-driver dependency when a new + // version gets published, though that may not happen very soon: + // https://github.com/faye/websocket-driver-node/issues/21 + "websocket-driver": "https://github.com/faye/websocket-driver-node/" + + "tarball/1325828a9e8b5e29c7b4758995efdb84703919ad", "lolex": "1.4.0", "permessage-deflate": "0.1.3" }); diff --git a/packages/ejson/package.js b/packages/ejson/package.js index 0259ea994e..142dff4de5 100644 --- a/packages/ejson/package.js +++ b/packages/ejson/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: 'Extended and Extensible JSON library', - version: '1.0.14', + version: '1.0.14' }); Package.onUse(function onUse(api) { diff --git a/packages/launch-screen/package.js b/packages/launch-screen/package.js index c027b04e60..c6c0749150 100644 --- a/packages/launch-screen/package.js +++ b/packages/launch-screen/package.js @@ -10,7 +10,7 @@ Package.describe({ }); Cordova.depends({ - 'cordova-plugin-splashscreen': '4.0.1' + 'cordova-plugin-splashscreen': '4.0.3' }); Package.onUse(function(api) { diff --git a/packages/logging/package.js b/packages/logging/package.js index f92fc241ea..85e6423d1e 100644 --- a/packages/logging/package.js +++ b/packages/logging/package.js @@ -12,7 +12,7 @@ Npm.strip({ }); Cordova.depends({ - 'cordova-plugin-console': '1.0.5' + 'cordova-plugin-console': '1.0.7' }); Package.onUse(function (api) { diff --git a/packages/meteor-tool/package.js b/packages/meteor-tool/package.js index efbed2d097..13eec78560 100644 --- a/packages/meteor-tool/package.js +++ b/packages/meteor-tool/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "The Meteor command-line tool", - version: '1.5.1' + version: "1.5.2" }); Package.includeTool(); diff --git a/packages/minifier-js/.npm/package/npm-shrinkwrap.json b/packages/minifier-js/.npm/package/npm-shrinkwrap.json index b92b6f3593..96cb028903 100644 --- a/packages/minifier-js/.npm/package/npm-shrinkwrap.json +++ b/packages/minifier-js/.npm/package/npm-shrinkwrap.json @@ -1,24 +1,19 @@ { "dependencies": { "commander": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", - "from": "commander@>=2.9.0 <2.10.0" - }, - "graceful-readlink": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", - "from": "graceful-readlink@>=1.0.0" + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz", + "from": "commander@>=2.11.0 <2.12.0" }, "source-map": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz", + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", "from": "source-map@>=0.5.1 <0.6.0" }, "uglify-js": { - "version": "3.0.18", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.0.18.tgz", - "from": "uglify-js@3.0.18" + "version": "3.0.28", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.0.28.tgz", + "from": "uglify-js@3.0.28" } } } diff --git a/packages/minifier-js/package.js b/packages/minifier-js/package.js index 36f5e8557a..8383c30401 100644 --- a/packages/minifier-js/package.js +++ b/packages/minifier-js/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "JavaScript minifier", - version: "2.1.1" + version: "2.1.2" }); Npm.depends({ diff --git a/packages/minimongo/local_collection.js b/packages/minimongo/local_collection.js index 17a2ba5216..b414dcb396 100644 --- a/packages/minimongo/local_collection.js +++ b/packages/minimongo/local_collection.js @@ -29,7 +29,7 @@ export default class LocalCollection { // resultsSnapshot: snapshot of results. null if not paused. // cursor: Cursor object for the query. // selector, sorter, (callbacks): functions - this.queries = {}; + this.queries = Object.create(null); // null if not saving originals; an IdMap from id to original document value // if saving originals. See comments before saveOriginals(). @@ -111,11 +111,11 @@ export default class LocalCollection { const queriesToRecompute = []; // trigger live queries that match - for (let qid in this.queries) { + Object.keys(this.queries).forEach(qid => { const query = this.queries[qid]; if (query.dirty) { - continue; + return; } const matchResult = query.matcher.documentMatches(doc); @@ -131,7 +131,7 @@ export default class LocalCollection { LocalCollection._insertInResults(query, doc); } } - } + }); queriesToRecompute.forEach(qid => { if (this.queries[qid]) { @@ -164,11 +164,10 @@ export default class LocalCollection { this.paused = true; // Take a snapshot of the query results for each query. - for (let qid in this.queries) { + Object.keys(this.queries).forEach(qid => { const query = this.queries[qid]; - query.resultsSnapshot = EJSON.clone(query.results); - } + }); } remove(selector, callback) { @@ -180,7 +179,7 @@ export default class LocalCollection { this._docs.clear(); - for (let qid in this.queries) { + Object.keys(this.queries).forEach(qid => { const query = this.queries[qid]; if (query.ordered) { @@ -188,7 +187,7 @@ export default class LocalCollection { } else { query.results.clear(); } - } + }); if (callback) { Meteor.defer(() => { @@ -215,7 +214,7 @@ export default class LocalCollection { const removeId = remove[i]; const removeDoc = this._docs.get(removeId); - for (let qid in this.queries) { + Object.keys(this.queries).forEach(qid => { const query = this.queries[qid]; if (query.dirty) { @@ -229,7 +228,7 @@ export default class LocalCollection { queryRemove.push({qid, doc: removeDoc}); } } - } + }); this._saveOriginal(removeId, removeDoc); this._docs.remove(removeId); @@ -280,7 +279,7 @@ export default class LocalCollection { // observer methods won't actually fire when we trigger them. this.paused = false; - for (let qid in this.queries) { + Object.keys(this.queries).forEach(qid => { const query = this.queries[qid]; if (query.dirty) { @@ -302,7 +301,7 @@ export default class LocalCollection { } query.resultsSnapshot = null; - } + }); this._observeQueue.drain(); } @@ -360,7 +359,7 @@ export default class LocalCollection { const docMap = new LocalCollection._IdMap; const idsMatched = LocalCollection._idsMatchedBySelector(selector); - for (let qid in this.queries) { + Object.keys(this.queries).forEach(qid => { const query = this.queries[qid]; if ((query.cursor.skip || query.cursor.limit) && ! this.paused) { @@ -399,7 +398,7 @@ export default class LocalCollection { qidToOriginalResults[qid] = query.results.map(memoizedCloneIfNeeded); } - } + }); const recomputeQids = {}; @@ -515,11 +514,11 @@ export default class LocalCollection { _modifyAndNotify(doc, mod, recomputeQids, arrayIndices) { const matched_before = {}; - for (let qid in this.queries) { + Object.keys(this.queries).forEach(qid => { const query = this.queries[qid]; if (query.dirty) { - continue; + return; } if (query.ordered) { @@ -529,17 +528,17 @@ export default class LocalCollection { // can just do a direct lookup. matched_before[qid] = query.results.has(doc._id); } - } + }); const old_doc = EJSON.clone(doc); LocalCollection._modify(doc, mod, {arrayIndices}); - for (let qid in this.queries) { + Object.keys(this.queries).forEach(qid => { const query = this.queries[qid]; if (query.dirty) { - continue; + return; } const afterMatch = query.matcher.documentMatches(doc); @@ -568,7 +567,7 @@ export default class LocalCollection { } else if (before && after) { LocalCollection._updateInResults(query, doc, old_doc); } - } + }); } // Recomputes the results of a query and runs observe callbacks for the @@ -1081,13 +1080,13 @@ LocalCollection._isModificationMod = mod => { let isModify = false; let isReplace = false; - for (const key in mod) { + Object.keys(mod).forEach(key => { if (key.substr(0, 1) === '$') { isModify = true; } else { isReplace = true; } - } + }); if (isModify && isReplace) { throw new Error( diff --git a/packages/minimongo/matcher.js b/packages/minimongo/matcher.js index ad48271166..75929e4b09 100644 --- a/packages/minimongo/matcher.js +++ b/packages/minimongo/matcher.js @@ -273,10 +273,9 @@ LocalCollection._f = { const toArray = object => { const result = []; - for (let key in object) { - result.push(key); - result.push(object[key]); - } + Object.keys(object).forEach(key => { + result.push(key, object[key]); + }); return result; }; diff --git a/packages/minimongo/package.js b/packages/minimongo/package.js index 30bbf4adef..97edd81586 100644 --- a/packages/minimongo/package.js +++ b/packages/minimongo/package.js @@ -1,5 +1,5 @@ Package.describe({ - summary: 'Meteor\'s client-side datastore: a port of MongoDB to Javascript', + summary: "Meteor's client-side datastore: a port of MongoDB to Javascript", version: '1.3.0' }); diff --git a/packages/mobile-status-bar/package.js b/packages/mobile-status-bar/package.js index ddf88dc48d..86485b0923 100644 --- a/packages/mobile-status-bar/package.js +++ b/packages/mobile-status-bar/package.js @@ -4,5 +4,5 @@ Package.describe({ }); Cordova.depends({ - 'cordova-plugin-statusbar': '2.2.1' + 'cordova-plugin-statusbar': '2.2.3' }); diff --git a/packages/modules/.npm/package/npm-shrinkwrap.json b/packages/modules/.npm/package/npm-shrinkwrap.json index ed85116d23..b005c19a86 100644 --- a/packages/modules/.npm/package/npm-shrinkwrap.json +++ b/packages/modules/.npm/package/npm-shrinkwrap.json @@ -1,13 +1,13 @@ { "dependencies": { "acorn": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.0.3.tgz", - "from": "acorn@>=5.0.0 <5.1.0" + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.1.1.tgz", + "from": "acorn@>=5.1.1 <5.2.0" }, "minipass": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.0.2.tgz", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.2.1.tgz", "from": "minipass@>=2.0.0 <3.0.0" }, "minizlib": { @@ -16,9 +16,9 @@ "from": "minizlib@>=1.0.3 <2.0.0" }, "reify": { - "version": "0.11.24", - "resolved": "https://registry.npmjs.org/reify/-/reify-0.11.24.tgz", - "from": "reify@0.11.24" + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/reify/-/reify-0.12.0.tgz", + "from": "reify@0.12.0" }, "semver": { "version": "5.3.0", diff --git a/packages/modules/package.js b/packages/modules/package.js index 3d5e5b80e6..e7a0b80687 100644 --- a/packages/modules/package.js +++ b/packages/modules/package.js @@ -1,12 +1,12 @@ Package.describe({ name: "modules", - version: "0.9.4", + version: "0.10.0", summary: "CommonJS module system", documentation: "README.md" }); Npm.depends({ - reify: "0.11.24" + reify: "0.12.0" }); Package.onUse(function(api) { diff --git a/packages/mongo-dev-server/package.js b/packages/mongo-dev-server/package.js index 9e858ef438..3f5d9026b3 100644 --- a/packages/mongo-dev-server/package.js +++ b/packages/mongo-dev-server/package.js @@ -3,7 +3,7 @@ Package.describe({ documentation: 'README.md', name: 'mongo-dev-server', summary: 'Start MongoDB alongside Meteor, in development mode.', - version: '1.0.0', + version: '1.0.1', }); Package.onUse(function (api) { diff --git a/packages/mongo/collection_tests.js b/packages/mongo/collection_tests.js index 4334a3e9b9..e6b0c3d9be 100644 --- a/packages/mongo/collection_tests.js +++ b/packages/mongo/collection_tests.js @@ -138,15 +138,21 @@ Tinytest.add('collection - calling native find with $reverse hint should reverse } ); -Tinytest.add('collection - calling native find with good hint and maxTimeMs should succeed', - function(test) { +Tinytest.addAsync('collection - calling native find with good hint and maxTimeMs should succeed', + function(test, done) { var collectionName = 'findOptions3' + test.id; var collection = new Mongo.Collection(collectionName); collection.insert({a: 1}); - if (Meteor.isServer) { - collection.rawCollection().createIndex({a: 1}); - } - test.equal(collection.find({}, {hint: {a: 1}, maxTimeMs: 1000}).count(), 1); + Promise.resolve( + Meteor.isServer && + collection.rawCollection().createIndex({ a: 1 }) + ).then(() => { + test.equal(collection.find({}, { + hint: {a: 1}, + maxTimeMs: 1000 + }).count(), 1); + done(); + }).catch(error => test.fail(error.message)); } ); diff --git a/packages/mongo/mongo_livedata_tests.js b/packages/mongo/mongo_livedata_tests.js index faba62f641..932b98caca 100644 --- a/packages/mongo/mongo_livedata_tests.js +++ b/packages/mongo/mongo_livedata_tests.js @@ -2532,10 +2532,12 @@ if (Meteor.isServer) { self.events.push({evt: "a", id: id}); Meteor._sleepForMs(200); self.events.push({evt: "b", id: id}); + if (! self.two) { + self.two = self.C.insert({}); + } } }); self.one = self.C.insert({}); - self.two = self.C.insert({}); pollUntil(expect, function () { return self.events.length === 4; }, 10000); diff --git a/packages/mongo/package.js b/packages/mongo/package.js index ab0a9c17e6..22ab4f22a8 100644 --- a/packages/mongo/package.js +++ b/packages/mongo/package.js @@ -9,7 +9,7 @@ Package.describe({ summary: "Adaptor for using MongoDB and Minimongo over DDP", - version: '1.1.23' + version: '1.2.0' }); Npm.depends({ diff --git a/packages/non-core/blaze b/packages/non-core/blaze index e9a03af5ed..6a82100e09 160000 --- a/packages/non-core/blaze +++ b/packages/non-core/blaze @@ -1 +1 @@ -Subproject commit e9a03af5edc69777058f87f521d98b6faba9910c +Subproject commit 6a82100e09b22c27366d11805b232ceab443e386 diff --git a/packages/oauth/package.js b/packages/oauth/package.js index f20389e65b..28b2b0dfbc 100644 --- a/packages/oauth/package.js +++ b/packages/oauth/package.js @@ -57,5 +57,5 @@ Package.onTest(function (api) { }); Cordova.depends({ - 'cordova-plugin-inappbrowser': '1.6.1' + 'cordova-plugin-inappbrowser': '1.7.1' }); diff --git a/packages/package-version-parser/package-version-parser.js b/packages/package-version-parser/package-version-parser.js index c1a807260a..7d651f7edc 100644 --- a/packages/package-version-parser/package-version-parser.js +++ b/packages/package-version-parser/package-version-parser.js @@ -1,14 +1,9 @@ -// This file is in tools/packaging/package-version-parser.js and is symlinked to -// packages/package-version-parser/package-version-parser.js. It's part of both -// the tool and the package! We don't use an isopacket for it because it used -// to be required as part of building isopackets (though that may no longer be -// true). -var inTool = typeof Package === 'undefined'; +var inTool = typeof Package === "undefined"; - -var semver = inTool ? - require ('../../dev_bundle/lib/node_modules/semver') : SemVer410; -var __ = inTool ? require('../../dev_bundle/lib/node_modules/underscore') : _; +// Provided by dev_bundle/server-lib/node_modules/semver. +var semver = inTool + ? module.parent.require("semver") + : require("semver"); // Takes in a meteor version string, for example 1.2.3-rc.5_1+12345. // @@ -108,16 +103,14 @@ var PV = function (versionString) { this._semverParsed = null; // populate lazily }; +// Set module.exports for tools/packaging/package-version-parser.js and +// module.exports.PackageVersion for api.export("PackageVersion"). +PV.PackageVersion = module.exports = PV; + PV.parse = function (versionString) { return new PV(versionString); }; -if (inTool) { - module.exports = PV; -} else { - PackageVersion = PV; -} - // Converts a meteor version into a large floating point number, which // is (more or less [*]) unique to that version. Satisfies the // following guarantee: If PV.lessThan(v1, v2) then @@ -156,7 +149,7 @@ var prereleaseIdentifierToFraction = function (prerelease) { if (prerelease.length === 0) return 0; - return __.reduce(prerelease, function (memo, part, index) { + return prerelease.reduce(function (memo, part, index) { var digit; if (typeof part === 'number') { digit = part+1; @@ -251,20 +244,41 @@ var parseSimpleConstraint = function (constraintString) { throw new Error("Non-empty string required"); } - var type, versionString; + var result = {}; + var needToCheckValidity = true; if (constraintString.charAt(0) === '=') { - type = "exactly"; - versionString = constraintString.substr(1); + result.type = "exactly"; + result.versionString = constraintString.slice(1); + } else { - type = "compatible-with"; - versionString = constraintString; + result.type = "compatible-with"; + + if (constraintString.charAt(0) === "~") { + var semversion = PV.parse( + result.versionString = constraintString.slice(1) + ).semver; + + var range = new semver.Range("~" + semversion); + + result.test = function (version) { + return range.test(PV.parse(version).semver); + }; + + // Already checked by calling PV.parse above. + needToCheckValidity = false; + + } else { + result.versionString = constraintString; + } } - // This will throw if the version string is invalid. - PV.getValidServerVersion(versionString); + if (needToCheckValidity) { + // This will throw if the version string is invalid. + PV.getValidServerVersion(result.versionString); + } - return { type: type, versionString: versionString }; + return result; }; @@ -289,7 +303,7 @@ PV.VersionConstraint = function (vConstraintString) { } else { // Parse out the versionString. var parts = vConstraintString.split(/ *\|\| */); - alternatives = __.map(parts, function (alt) { + alternatives = parts.map(function (alt) { if (! alt) { throwVersionParserError("Invalid constraint string: " + vConstraintString); @@ -420,7 +434,8 @@ PV.validatePackageName = function (packageName, options) { // (There is already a package ending with a `-` and one with two consecutive `-` // in troposphere, though they both look like typos.) - if (packageName[0] === ":" || __.last(packageName) === ":") { + if (packageName.startsWith(":") || + packageName.endsWith(":")) { throwVersionParserError("Package names may not start or end with a colon: " + JSON.stringify(packageName)); } diff --git a/packages/package-version-parser/package.js b/packages/package-version-parser/package.js index 601910f00f..3e8daf5f16 100644 --- a/packages/package-version-parser/package.js +++ b/packages/package-version-parser/package.js @@ -4,10 +4,9 @@ Package.describe({ }); Package.onUse(function (api) { + api.use('modules'); + api.mainModule('package-version-parser.js'); api.export('PackageVersion'); - api.use('underscore'); - api.addFiles(['semver410.js', - 'package-version-parser.js']); }); Package.onTest(function (api) { diff --git a/packages/package-version-parser/semver410.js b/packages/package-version-parser/semver410.js deleted file mode 100644 index 11e655cd3e..0000000000 --- a/packages/package-version-parser/semver410.js +++ /dev/null @@ -1,1135 +0,0 @@ -// -// Fool the module system detection code below so that it doesn't -// do anything special. -var exports = SemVer, module = {}, define = {}; -// Create a package-private variable. Can't use SemVer because -// of the code that says `function SemVer(...)` below (implicitly -// declaring a var). Can't use "semver" because that's a var in -// package-version-parser.js. -SemVer410 = SemVer; -// - -// export the class if we are in a Node-like system. -if (typeof module === 'object' && module.exports === exports) - exports = module.exports = SemVer; - -// The debug function is excluded entirely from the minified version. -/* nomin */ var debug; -/* nomin */ if (typeof process === 'object' && - /* nomin */ process.env && - /* nomin */ process.env.NODE_DEBUG && - /* nomin */ /\bsemver\b/i.test(process.env.NODE_DEBUG)) - /* nomin */ debug = function() { - /* nomin */ var args = Array.prototype.slice.call(arguments, 0); - /* nomin */ args.unshift('SEMVER'); - /* nomin */ console.log.apply(console, args); - /* nomin */ }; -/* nomin */ else - /* nomin */ debug = function() {}; - -// Note: this is the semver.org version of the spec that it implements -// Not necessarily the package version of this code. -exports.SEMVER_SPEC_VERSION = '2.0.0'; - -// The actual regexps go on exports.re -var re = exports.re = []; -var src = exports.src = []; -var R = 0; - -// The following Regular Expressions can be used for tokenizing, -// validating, and parsing SemVer version strings. - -// ## Numeric Identifier -// A single `0`, or a non-zero digit followed by zero or more digits. - -var NUMERICIDENTIFIER = R++; -src[NUMERICIDENTIFIER] = '0|[1-9]\\d*'; -var NUMERICIDENTIFIERLOOSE = R++; -src[NUMERICIDENTIFIERLOOSE] = '[0-9]+'; - - -// ## Non-numeric Identifier -// Zero or more digits, followed by a letter or hyphen, and then zero or -// more letters, digits, or hyphens. - -var NONNUMERICIDENTIFIER = R++; -src[NONNUMERICIDENTIFIER] = '\\d*[a-zA-Z-][a-zA-Z0-9-]*'; - - -// ## Main Version -// Three dot-separated numeric identifiers. - -var MAINVERSION = R++; -src[MAINVERSION] = '(' + src[NUMERICIDENTIFIER] + ')\\.' + - '(' + src[NUMERICIDENTIFIER] + ')\\.' + - '(' + src[NUMERICIDENTIFIER] + ')'; - -var MAINVERSIONLOOSE = R++; -src[MAINVERSIONLOOSE] = '(' + src[NUMERICIDENTIFIERLOOSE] + ')\\.' + - '(' + src[NUMERICIDENTIFIERLOOSE] + ')\\.' + - '(' + src[NUMERICIDENTIFIERLOOSE] + ')'; - -// ## Pre-release Version Identifier -// A numeric identifier, or a non-numeric identifier. - -var PRERELEASEIDENTIFIER = R++; -src[PRERELEASEIDENTIFIER] = '(?:' + src[NUMERICIDENTIFIER] + - '|' + src[NONNUMERICIDENTIFIER] + ')'; - -var PRERELEASEIDENTIFIERLOOSE = R++; -src[PRERELEASEIDENTIFIERLOOSE] = '(?:' + src[NUMERICIDENTIFIERLOOSE] + - '|' + src[NONNUMERICIDENTIFIER] + ')'; - - -// ## Pre-release Version -// Hyphen, followed by one or more dot-separated pre-release version -// identifiers. - -var PRERELEASE = R++; -src[PRERELEASE] = '(?:-(' + src[PRERELEASEIDENTIFIER] + - '(?:\\.' + src[PRERELEASEIDENTIFIER] + ')*))'; - -var PRERELEASELOOSE = R++; -src[PRERELEASELOOSE] = '(?:-?(' + src[PRERELEASEIDENTIFIERLOOSE] + - '(?:\\.' + src[PRERELEASEIDENTIFIERLOOSE] + ')*))'; - -// ## Build Metadata Identifier -// Any combination of digits, letters, or hyphens. - -var BUILDIDENTIFIER = R++; -src[BUILDIDENTIFIER] = '[0-9A-Za-z-]+'; - -// ## Build Metadata -// Plus sign, followed by one or more period-separated build metadata -// identifiers. - -var BUILD = R++; -src[BUILD] = '(?:\\+(' + src[BUILDIDENTIFIER] + - '(?:\\.' + src[BUILDIDENTIFIER] + ')*))'; - - -// ## Full Version String -// A main version, followed optionally by a pre-release version and -// build metadata. - -// Note that the only major, minor, patch, and pre-release sections of -// the version string are capturing groups. The build metadata is not a -// capturing group, because it should not ever be used in version -// comparison. - -var FULL = R++; -var FULLPLAIN = 'v?' + src[MAINVERSION] + - src[PRERELEASE] + '?' + - src[BUILD] + '?'; - -src[FULL] = '^' + FULLPLAIN + '$'; - -// like full, but allows v1.2.3 and =1.2.3, which people do sometimes. -// also, 1.0.0alpha1 (prerelease without the hyphen) which is pretty -// common in the npm registry. -var LOOSEPLAIN = '[v=\\s]*' + src[MAINVERSIONLOOSE] + - src[PRERELEASELOOSE] + '?' + - src[BUILD] + '?'; - -var LOOSE = R++; -src[LOOSE] = '^' + LOOSEPLAIN + '$'; - -var GTLT = R++; -src[GTLT] = '((?:<|>)?=?)'; - -// Something like "2.*" or "1.2.x". -// Note that "x.x" is a valid xRange identifer, meaning "any version" -// Only the first item is strictly required. -var XRANGEIDENTIFIERLOOSE = R++; -src[XRANGEIDENTIFIERLOOSE] = src[NUMERICIDENTIFIERLOOSE] + '|x|X|\\*'; -var XRANGEIDENTIFIER = R++; -src[XRANGEIDENTIFIER] = src[NUMERICIDENTIFIER] + '|x|X|\\*'; - -var XRANGEPLAIN = R++; -src[XRANGEPLAIN] = '[v=\\s]*(' + src[XRANGEIDENTIFIER] + ')' + - '(?:\\.(' + src[XRANGEIDENTIFIER] + ')' + - '(?:\\.(' + src[XRANGEIDENTIFIER] + ')' + - '(?:' + src[PRERELEASE] + ')?' + - src[BUILD] + '?' + - ')?)?'; - -var XRANGEPLAINLOOSE = R++; -src[XRANGEPLAINLOOSE] = '[v=\\s]*(' + src[XRANGEIDENTIFIERLOOSE] + ')' + - '(?:\\.(' + src[XRANGEIDENTIFIERLOOSE] + ')' + - '(?:\\.(' + src[XRANGEIDENTIFIERLOOSE] + ')' + - '(?:' + src[PRERELEASELOOSE] + ')?' + - src[BUILD] + '?' + - ')?)?'; - -var XRANGE = R++; -src[XRANGE] = '^' + src[GTLT] + '\\s*' + src[XRANGEPLAIN] + '$'; -var XRANGELOOSE = R++; -src[XRANGELOOSE] = '^' + src[GTLT] + '\\s*' + src[XRANGEPLAINLOOSE] + '$'; - -// Tilde ranges. -// Meaning is "reasonably at or greater than" -var LONETILDE = R++; -src[LONETILDE] = '(?:~>?)'; - -var TILDETRIM = R++; -src[TILDETRIM] = '(\\s*)' + src[LONETILDE] + '\\s+'; -re[TILDETRIM] = new RegExp(src[TILDETRIM], 'g'); -var tildeTrimReplace = '$1~'; - -var TILDE = R++; -src[TILDE] = '^' + src[LONETILDE] + src[XRANGEPLAIN] + '$'; -var TILDELOOSE = R++; -src[TILDELOOSE] = '^' + src[LONETILDE] + src[XRANGEPLAINLOOSE] + '$'; - -// Caret ranges. -// Meaning is "at least and backwards compatible with" -var LONECARET = R++; -src[LONECARET] = '(?:\\^)'; - -var CARETTRIM = R++; -src[CARETTRIM] = '(\\s*)' + src[LONECARET] + '\\s+'; -re[CARETTRIM] = new RegExp(src[CARETTRIM], 'g'); -var caretTrimReplace = '$1^'; - -var CARET = R++; -src[CARET] = '^' + src[LONECARET] + src[XRANGEPLAIN] + '$'; -var CARETLOOSE = R++; -src[CARETLOOSE] = '^' + src[LONECARET] + src[XRANGEPLAINLOOSE] + '$'; - -// A simple gt/lt/eq thing, or just "" to indicate "any version" -var COMPARATORLOOSE = R++; -src[COMPARATORLOOSE] = '^' + src[GTLT] + '\\s*(' + LOOSEPLAIN + ')$|^$'; -var COMPARATOR = R++; -src[COMPARATOR] = '^' + src[GTLT] + '\\s*(' + FULLPLAIN + ')$|^$'; - - -// An expression to strip any whitespace between the gtlt and the thing -// it modifies, so that `> 1.2.3` ==> `>1.2.3` -var COMPARATORTRIM = R++; -src[COMPARATORTRIM] = '(\\s*)' + src[GTLT] + - '\\s*(' + LOOSEPLAIN + '|' + src[XRANGEPLAIN] + ')'; - -// this one has to use the /g flag -re[COMPARATORTRIM] = new RegExp(src[COMPARATORTRIM], 'g'); -var comparatorTrimReplace = '$1$2$3'; - - -// Something like `1.2.3 - 1.2.4` -// Note that these all use the loose form, because they'll be -// checked against either the strict or loose comparator form -// later. -var HYPHENRANGE = R++; -src[HYPHENRANGE] = '^\\s*(' + src[XRANGEPLAIN] + ')' + - '\\s+-\\s+' + - '(' + src[XRANGEPLAIN] + ')' + - '\\s*$'; - -var HYPHENRANGELOOSE = R++; -src[HYPHENRANGELOOSE] = '^\\s*(' + src[XRANGEPLAINLOOSE] + ')' + - '\\s+-\\s+' + - '(' + src[XRANGEPLAINLOOSE] + ')' + - '\\s*$'; - -// Star ranges basically just allow anything at all. -var STAR = R++; -src[STAR] = '(<|>)?=?\\s*\\*'; - -// Compile to actual regexp objects. -// All are flag-free, unless they were created above with a flag. -for (var i = 0; i < R; i++) { - debug(i, src[i]); - if (!re[i]) - re[i] = new RegExp(src[i]); -} - -exports.parse = parse; -function parse(version, loose) { - var r = loose ? re[LOOSE] : re[FULL]; - return (r.test(version)) ? new SemVer(version, loose) : null; -} - -exports.valid = valid; -function valid(version, loose) { - var v = parse(version, loose); - return v ? v.version : null; -} - - -exports.clean = clean; -function clean(version, loose) { - var s = parse(version.trim().replace(/^[=v]+/, ''), loose); - return s ? s.version : null; -} - -exports.SemVer = SemVer; - -function SemVer(version, loose) { - if (version instanceof SemVer) { - if (version.loose === loose) - return version; - else - version = version.version; - } else if (typeof version !== 'string') { - throw new TypeError('Invalid Version: ' + version); - } - - if (!(this instanceof SemVer)) - return new SemVer(version, loose); - - debug('SemVer', version, loose); - this.loose = loose; - var m = version.trim().match(loose ? re[LOOSE] : re[FULL]); - - if (!m) - throw new TypeError('Invalid Version: ' + version); - - this.raw = version; - - // these are actually numbers - this.major = +m[1]; - this.minor = +m[2]; - this.patch = +m[3]; - - // numberify any prerelease numeric ids - if (!m[4]) - this.prerelease = []; - else - this.prerelease = m[4].split('.').map(function(id) { - return (/^[0-9]+$/.test(id)) ? +id : id; - }); - - this.build = m[5] ? m[5].split('.') : []; - this.format(); -} - -SemVer.prototype.format = function() { - this.version = this.major + '.' + this.minor + '.' + this.patch; - if (this.prerelease.length) - this.version += '-' + this.prerelease.join('.'); - return this.version; -}; - -SemVer.prototype.inspect = function() { - return ''; -}; - -SemVer.prototype.toString = function() { - return this.version; -}; - -SemVer.prototype.compare = function(other) { - debug('SemVer.compare', this.version, this.loose, other); - if (!(other instanceof SemVer)) - other = new SemVer(other, this.loose); - - return this.compareMain(other) || this.comparePre(other); -}; - -SemVer.prototype.compareMain = function(other) { - if (!(other instanceof SemVer)) - other = new SemVer(other, this.loose); - - return compareIdentifiers(this.major, other.major) || - compareIdentifiers(this.minor, other.minor) || - compareIdentifiers(this.patch, other.patch); -}; - -SemVer.prototype.comparePre = function(other) { - if (!(other instanceof SemVer)) - other = new SemVer(other, this.loose); - - // NOT having a prerelease is > having one - if (this.prerelease.length && !other.prerelease.length) - return -1; - else if (!this.prerelease.length && other.prerelease.length) - return 1; - else if (!this.prerelease.length && !other.prerelease.length) - return 0; - - var i = 0; - do { - var a = this.prerelease[i]; - var b = other.prerelease[i]; - debug('prerelease compare', i, a, b); - if (a === undefined && b === undefined) - return 0; - else if (b === undefined) - return 1; - else if (a === undefined) - return -1; - else if (a === b) - continue; - else - return compareIdentifiers(a, b); - } while (++i); -}; - -// preminor will bump the version up to the next minor release, and immediately -// down to pre-release. premajor and prepatch work the same way. -SemVer.prototype.inc = function(release, identifier) { - switch (release) { - case 'premajor': - this.prerelease.length = 0; - this.patch = 0; - this.minor = 0; - this.major++; - this.inc('pre', identifier); - break; - case 'preminor': - this.prerelease.length = 0; - this.patch = 0; - this.minor++; - this.inc('pre', identifier); - break; - case 'prepatch': - // If this is already a prerelease, it will bump to the next version - // drop any prereleases that might already exist, since they are not - // relevant at this point. - this.prerelease.length = 0; - this.inc('patch', identifier); - this.inc('pre', identifier); - break; - // If the input is a non-prerelease version, this acts the same as - // prepatch. - case 'prerelease': - if (this.prerelease.length === 0) - this.inc('patch', identifier); - this.inc('pre', identifier); - break; - - case 'major': - // If this is a pre-major version, bump up to the same major version. - // Otherwise increment major. - // 1.0.0-5 bumps to 1.0.0 - // 1.1.0 bumps to 2.0.0 - if (this.minor !== 0 || this.patch !== 0 || this.prerelease.length === 0) - this.major++; - this.minor = 0; - this.patch = 0; - this.prerelease = []; - break; - case 'minor': - // If this is a pre-minor version, bump up to the same minor version. - // Otherwise increment minor. - // 1.2.0-5 bumps to 1.2.0 - // 1.2.1 bumps to 1.3.0 - if (this.patch !== 0 || this.prerelease.length === 0) - this.minor++; - this.patch = 0; - this.prerelease = []; - break; - case 'patch': - // If this is not a pre-release version, it will increment the patch. - // If it is a pre-release it will bump up to the same patch version. - // 1.2.0-5 patches to 1.2.0 - // 1.2.0 patches to 1.2.1 - if (this.prerelease.length === 0) - this.patch++; - this.prerelease = []; - break; - // This probably shouldn't be used publicly. - // 1.0.0 "pre" would become 1.0.0-0 which is the wrong direction. - case 'pre': - if (this.prerelease.length === 0) - this.prerelease = [0]; - else { - var i = this.prerelease.length; - while (--i >= 0) { - if (typeof this.prerelease[i] === 'number') { - this.prerelease[i]++; - i = -2; - } - } - if (i === -1) // didn't increment anything - this.prerelease.push(0); - } - if (identifier) { - // 1.2.0-beta.1 bumps to 1.2.0-beta.2, - // 1.2.0-beta.fooblz or 1.2.0-beta bumps to 1.2.0-beta.0 - if (this.prerelease[0] === identifier) { - if (isNaN(this.prerelease[1])) - this.prerelease = [identifier, 0]; - } else - this.prerelease = [identifier, 0]; - } - break; - - default: - throw new Error('invalid increment argument: ' + release); - } - this.format(); - return this; -}; - -exports.inc = inc; -function inc(version, release, loose, identifier) { - if (typeof(loose) === 'string') { - identifier = loose; - loose = undefined; - } - - try { - return new SemVer(version, loose).inc(release, identifier).version; - } catch (er) { - return null; - } -} - -exports.compareIdentifiers = compareIdentifiers; - -var numeric = /^[0-9]+$/; -function compareIdentifiers(a, b) { - var anum = numeric.test(a); - var bnum = numeric.test(b); - - if (anum && bnum) { - a = +a; - b = +b; - } - - return (anum && !bnum) ? -1 : - (bnum && !anum) ? 1 : - a < b ? -1 : - a > b ? 1 : - 0; -} - -exports.rcompareIdentifiers = rcompareIdentifiers; -function rcompareIdentifiers(a, b) { - return compareIdentifiers(b, a); -} - -exports.compare = compare; -function compare(a, b, loose) { - return new SemVer(a, loose).compare(b); -} - -exports.compareLoose = compareLoose; -function compareLoose(a, b) { - return compare(a, b, true); -} - -exports.rcompare = rcompare; -function rcompare(a, b, loose) { - return compare(b, a, loose); -} - -exports.sort = sort; -function sort(list, loose) { - return list.sort(function(a, b) { - return exports.compare(a, b, loose); - }); -} - -exports.rsort = rsort; -function rsort(list, loose) { - return list.sort(function(a, b) { - return exports.rcompare(a, b, loose); - }); -} - -exports.gt = gt; -function gt(a, b, loose) { - return compare(a, b, loose) > 0; -} - -exports.lt = lt; -function lt(a, b, loose) { - return compare(a, b, loose) < 0; -} - -exports.eq = eq; -function eq(a, b, loose) { - return compare(a, b, loose) === 0; -} - -exports.neq = neq; -function neq(a, b, loose) { - return compare(a, b, loose) !== 0; -} - -exports.gte = gte; -function gte(a, b, loose) { - return compare(a, b, loose) >= 0; -} - -exports.lte = lte; -function lte(a, b, loose) { - return compare(a, b, loose) <= 0; -} - -exports.cmp = cmp; -function cmp(a, op, b, loose) { - var ret; - switch (op) { - case '===': - if (typeof a === 'object') a = a.version; - if (typeof b === 'object') b = b.version; - ret = a === b; - break; - case '!==': - if (typeof a === 'object') a = a.version; - if (typeof b === 'object') b = b.version; - ret = a !== b; - break; - case '': case '=': case '==': ret = eq(a, b, loose); break; - case '!=': ret = neq(a, b, loose); break; - case '>': ret = gt(a, b, loose); break; - case '>=': ret = gte(a, b, loose); break; - case '<': ret = lt(a, b, loose); break; - case '<=': ret = lte(a, b, loose); break; - default: throw new TypeError('Invalid operator: ' + op); - } - return ret; -} - -exports.Comparator = Comparator; -function Comparator(comp, loose) { - if (comp instanceof Comparator) { - if (comp.loose === loose) - return comp; - else - comp = comp.value; - } - - if (!(this instanceof Comparator)) - return new Comparator(comp, loose); - - debug('comparator', comp, loose); - this.loose = loose; - this.parse(comp); - - if (this.semver === ANY) - this.value = ''; - else - this.value = this.operator + this.semver.version; - - debug('comp', this); -} - -var ANY = {}; -Comparator.prototype.parse = function(comp) { - var r = this.loose ? re[COMPARATORLOOSE] : re[COMPARATOR]; - var m = comp.match(r); - - if (!m) - throw new TypeError('Invalid comparator: ' + comp); - - this.operator = m[1]; - if (this.operator === '=') - this.operator = ''; - - // if it literally is just '>' or '' then allow anything. - if (!m[2]) - this.semver = ANY; - else - this.semver = new SemVer(m[2], this.loose); -}; - -Comparator.prototype.inspect = function() { - return ''; -}; - -Comparator.prototype.toString = function() { - return this.value; -}; - -Comparator.prototype.test = function(version) { - debug('Comparator.test', version, this.loose); - - if (this.semver === ANY) - return true; - - if (typeof version === 'string') - version = new SemVer(version, this.loose); - - return cmp(version, this.operator, this.semver, this.loose); -}; - - -exports.Range = Range; -function Range(range, loose) { - if ((range instanceof Range) && range.loose === loose) - return range; - - if (!(this instanceof Range)) - return new Range(range, loose); - - this.loose = loose; - - // First, split based on boolean or || - this.raw = range; - this.set = range.split(/\s*\|\|\s*/).map(function(range) { - return this.parseRange(range.trim()); - }, this).filter(function(c) { - // throw out any that are not relevant for whatever reason - return c.length; - }); - - if (!this.set.length) { - throw new TypeError('Invalid SemVer Range: ' + range); - } - - this.format(); -} - -Range.prototype.inspect = function() { - return ''; -}; - -Range.prototype.format = function() { - this.range = this.set.map(function(comps) { - return comps.join(' ').trim(); - }).join('||').trim(); - return this.range; -}; - -Range.prototype.toString = function() { - return this.range; -}; - -Range.prototype.parseRange = function(range) { - var loose = this.loose; - range = range.trim(); - debug('range', range, loose); - // `1.2.3 - 1.2.4` => `>=1.2.3 <=1.2.4` - var hr = loose ? re[HYPHENRANGELOOSE] : re[HYPHENRANGE]; - range = range.replace(hr, hyphenReplace); - debug('hyphen replace', range); - // `> 1.2.3 < 1.2.5` => `>1.2.3 <1.2.5` - range = range.replace(re[COMPARATORTRIM], comparatorTrimReplace); - debug('comparator trim', range, re[COMPARATORTRIM]); - - // `~ 1.2.3` => `~1.2.3` - range = range.replace(re[TILDETRIM], tildeTrimReplace); - - // `^ 1.2.3` => `^1.2.3` - range = range.replace(re[CARETTRIM], caretTrimReplace); - - // normalize spaces - range = range.split(/\s+/).join(' '); - - // At this point, the range is completely trimmed and - // ready to be split into comparators. - - var compRe = loose ? re[COMPARATORLOOSE] : re[COMPARATOR]; - var set = range.split(' ').map(function(comp) { - return parseComparator(comp, loose); - }).join(' ').split(/\s+/); - if (this.loose) { - // in loose mode, throw out any that are not valid comparators - set = set.filter(function(comp) { - return !!comp.match(compRe); - }); - } - set = set.map(function(comp) { - return new Comparator(comp, loose); - }); - - return set; -}; - -// Mostly just for testing and legacy API reasons -exports.toComparators = toComparators; -function toComparators(range, loose) { - return new Range(range, loose).set.map(function(comp) { - return comp.map(function(c) { - return c.value; - }).join(' ').trim().split(' '); - }); -} - -// comprised of xranges, tildes, stars, and gtlt's at this point. -// already replaced the hyphen ranges -// turn into a set of JUST comparators. -function parseComparator(comp, loose) { - debug('comp', comp); - comp = replaceCarets(comp, loose); - debug('caret', comp); - comp = replaceTildes(comp, loose); - debug('tildes', comp); - comp = replaceXRanges(comp, loose); - debug('xrange', comp); - comp = replaceStars(comp, loose); - debug('stars', comp); - return comp; -} - -function isX(id) { - return !id || id.toLowerCase() === 'x' || id === '*'; -} - -// ~, ~> --> * (any, kinda silly) -// ~2, ~2.x, ~2.x.x, ~>2, ~>2.x ~>2.x.x --> >=2.0.0 <3.0.0 -// ~2.0, ~2.0.x, ~>2.0, ~>2.0.x --> >=2.0.0 <2.1.0 -// ~1.2, ~1.2.x, ~>1.2, ~>1.2.x --> >=1.2.0 <1.3.0 -// ~1.2.3, ~>1.2.3 --> >=1.2.3 <1.3.0 -// ~1.2.0, ~>1.2.0 --> >=1.2.0 <1.3.0 -function replaceTildes(comp, loose) { - return comp.trim().split(/\s+/).map(function(comp) { - return replaceTilde(comp, loose); - }).join(' '); -} - -function replaceTilde(comp, loose) { - var r = loose ? re[TILDELOOSE] : re[TILDE]; - return comp.replace(r, function(_, M, m, p, pr) { - debug('tilde', comp, _, M, m, p, pr); - var ret; - - if (isX(M)) - ret = ''; - else if (isX(m)) - ret = '>=' + M + '.0.0 <' + (+M + 1) + '.0.0'; - else if (isX(p)) - // ~1.2 == >=1.2.0- <1.3.0- - ret = '>=' + M + '.' + m + '.0 <' + M + '.' + (+m + 1) + '.0'; - else if (pr) { - debug('replaceTilde pr', pr); - if (pr.charAt(0) !== '-') - pr = '-' + pr; - ret = '>=' + M + '.' + m + '.' + p + pr + - ' <' + M + '.' + (+m + 1) + '.0'; - } else - // ~1.2.3 == >=1.2.3 <1.3.0 - ret = '>=' + M + '.' + m + '.' + p + - ' <' + M + '.' + (+m + 1) + '.0'; - - debug('tilde return', ret); - return ret; - }); -} - -// ^ --> * (any, kinda silly) -// ^2, ^2.x, ^2.x.x --> >=2.0.0 <3.0.0 -// ^2.0, ^2.0.x --> >=2.0.0 <3.0.0 -// ^1.2, ^1.2.x --> >=1.2.0 <2.0.0 -// ^1.2.3 --> >=1.2.3 <2.0.0 -// ^1.2.0 --> >=1.2.0 <2.0.0 -function replaceCarets(comp, loose) { - return comp.trim().split(/\s+/).map(function(comp) { - return replaceCaret(comp, loose); - }).join(' '); -} - -function replaceCaret(comp, loose) { - debug('caret', comp, loose); - var r = loose ? re[CARETLOOSE] : re[CARET]; - return comp.replace(r, function(_, M, m, p, pr) { - debug('caret', comp, _, M, m, p, pr); - var ret; - - if (isX(M)) - ret = ''; - else if (isX(m)) - ret = '>=' + M + '.0.0 <' + (+M + 1) + '.0.0'; - else if (isX(p)) { - if (M === '0') - ret = '>=' + M + '.' + m + '.0 <' + M + '.' + (+m + 1) + '.0'; - else - ret = '>=' + M + '.' + m + '.0 <' + (+M + 1) + '.0.0'; - } else if (pr) { - debug('replaceCaret pr', pr); - if (pr.charAt(0) !== '-') - pr = '-' + pr; - if (M === '0') { - if (m === '0') - ret = '>=' + M + '.' + m + '.' + p + pr + - ' <' + M + '.' + m + '.' + (+p + 1); - else - ret = '>=' + M + '.' + m + '.' + p + pr + - ' <' + M + '.' + (+m + 1) + '.0'; - } else - ret = '>=' + M + '.' + m + '.' + p + pr + - ' <' + (+M + 1) + '.0.0'; - } else { - debug('no pr'); - if (M === '0') { - if (m === '0') - ret = '>=' + M + '.' + m + '.' + p + - ' <' + M + '.' + m + '.' + (+p + 1); - else - ret = '>=' + M + '.' + m + '.' + p + - ' <' + M + '.' + (+m + 1) + '.0'; - } else - ret = '>=' + M + '.' + m + '.' + p + - ' <' + (+M + 1) + '.0.0'; - } - - debug('caret return', ret); - return ret; - }); -} - -function replaceXRanges(comp, loose) { - debug('replaceXRanges', comp, loose); - return comp.split(/\s+/).map(function(comp) { - return replaceXRange(comp, loose); - }).join(' '); -} - -function replaceXRange(comp, loose) { - comp = comp.trim(); - var r = loose ? re[XRANGELOOSE] : re[XRANGE]; - return comp.replace(r, function(ret, gtlt, M, m, p, pr) { - debug('xRange', comp, ret, gtlt, M, m, p, pr); - var xM = isX(M); - var xm = xM || isX(m); - var xp = xm || isX(p); - var anyX = xp; - - if (gtlt === '=' && anyX) - gtlt = ''; - - if (xM) { - if (gtlt === '>' || gtlt === '<') { - // nothing is allowed - ret = '<0.0.0'; - } else { - // nothing is forbidden - ret = '*'; - } - } else if (gtlt && anyX) { - // replace X with 0 - if (xm) - m = 0; - if (xp) - p = 0; - - if (gtlt === '>') { - // >1 => >=2.0.0 - // >1.2 => >=1.3.0 - // >1.2.3 => >= 1.2.4 - gtlt = '>='; - if (xm) { - M = +M + 1; - m = 0; - p = 0; - } else if (xp) { - m = +m + 1; - p = 0; - } - } else if (gtlt === '<=') { - // <=0.7.x is actually <0.8.0, since any 0.7.x should - // pass. Similarly, <=7.x is actually <8.0.0, etc. - gtlt = '<' - if (xm) - M = +M + 1 - else - m = +m + 1 - } - - ret = gtlt + M + '.' + m + '.' + p; - } else if (xm) { - ret = '>=' + M + '.0.0 <' + (+M + 1) + '.0.0'; - } else if (xp) { - ret = '>=' + M + '.' + m + '.0 <' + M + '.' + (+m + 1) + '.0'; - } - - debug('xRange return', ret); - - return ret; - }); -} - -// Because * is AND-ed with everything else in the comparator, -// and '' means "any version", just remove the *s entirely. -function replaceStars(comp, loose) { - debug('replaceStars', comp, loose); - // Looseness is ignored here. star is always as loose as it gets! - return comp.trim().replace(re[STAR], ''); -} - -// This function is passed to string.replace(re[HYPHENRANGE]) -// M, m, patch, prerelease, build -// 1.2 - 3.4.5 => >=1.2.0 <=3.4.5 -// 1.2.3 - 3.4 => >=1.2.0 <3.5.0 Any 3.4.x will do -// 1.2 - 3.4 => >=1.2.0 <3.5.0 -function hyphenReplace($0, - from, fM, fm, fp, fpr, fb, - to, tM, tm, tp, tpr, tb) { - - if (isX(fM)) - from = ''; - else if (isX(fm)) - from = '>=' + fM + '.0.0'; - else if (isX(fp)) - from = '>=' + fM + '.' + fm + '.0'; - else - from = '>=' + from; - - if (isX(tM)) - to = ''; - else if (isX(tm)) - to = '<' + (+tM + 1) + '.0.0'; - else if (isX(tp)) - to = '<' + tM + '.' + (+tm + 1) + '.0'; - else if (tpr) - to = '<=' + tM + '.' + tm + '.' + tp + '-' + tpr; - else - to = '<=' + to; - - return (from + ' ' + to).trim(); -} - - -// if ANY of the sets match ALL of its comparators, then pass -Range.prototype.test = function(version) { - if (!version) - return false; - - if (typeof version === 'string') - version = new SemVer(version, this.loose); - - for (var i = 0; i < this.set.length; i++) { - if (testSet(this.set[i], version)) - return true; - } - return false; -}; - -function testSet(set, version) { - for (var i = 0; i < set.length; i++) { - if (!set[i].test(version)) - return false; - } - - if (version.prerelease.length) { - // Find the set of versions that are allowed to have prereleases - // For example, ^1.2.3-pr.1 desugars to >=1.2.3-pr.1 <2.0.0 - // That should allow `1.2.3-pr.2` to pass. - // However, `1.2.4-alpha.notready` should NOT be allowed, - // even though it's within the range set by the comparators. - for (var i = 0; i < set.length; i++) { - debug(set[i].semver); - if (set[i].semver === ANY) - return true; - - if (set[i].semver.prerelease.length > 0) { - var allowed = set[i].semver; - if (allowed.major === version.major && - allowed.minor === version.minor && - allowed.patch === version.patch) - return true; - } - } - - // Version has a -pre, but it's not one of the ones we like. - return false; - } - - return true; -} - -exports.satisfies = satisfies; -function satisfies(version, range, loose) { - try { - range = new Range(range, loose); - } catch (er) { - return false; - } - return range.test(version); -} - -exports.maxSatisfying = maxSatisfying; -function maxSatisfying(versions, range, loose) { - return versions.filter(function(version) { - return satisfies(version, range, loose); - }).sort(function(a, b) { - return rcompare(a, b, loose); - })[0] || null; -} - -exports.validRange = validRange; -function validRange(range, loose) { - try { - // Return '*' instead of '' so that truthiness works. - // This will throw if it's invalid anyway - return new Range(range, loose).range || '*'; - } catch (er) { - return null; - } -} - -// Determine if version is less than all the versions possible in the range -exports.ltr = ltr; -function ltr(version, range, loose) { - return outside(version, range, '<', loose); -} - -// Determine if version is greater than all the versions possible in the range. -exports.gtr = gtr; -function gtr(version, range, loose) { - return outside(version, range, '>', loose); -} - -exports.outside = outside; -function outside(version, range, hilo, loose) { - version = new SemVer(version, loose); - range = new Range(range, loose); - - var gtfn, ltefn, ltfn, comp, ecomp; - switch (hilo) { - case '>': - gtfn = gt; - ltefn = lte; - ltfn = lt; - comp = '>'; - ecomp = '>='; - break; - case '<': - gtfn = lt; - ltefn = gte; - ltfn = gt; - comp = '<'; - ecomp = '<='; - break; - default: - throw new TypeError('Must provide a hilo val of "<" or ">"'); - } - - // If it satisifes the range it is not outside - if (satisfies(version, range, loose)) { - return false; - } - - // From now on, variable terms are as if we're in "gtr" mode. - // but note that everything is flipped for the "ltr" function. - - for (var i = 0; i < range.set.length; ++i) { - var comparators = range.set[i]; - - var high = null; - var low = null; - - comparators.forEach(function(comparator) { - high = high || comparator; - low = low || comparator; - if (gtfn(comparator.semver, high.semver, loose)) { - high = comparator; - } else if (ltfn(comparator.semver, low.semver, loose)) { - low = comparator; - } - }); - - // If the edge version comparator has a operator then our version - // isn't outside it - if (high.operator === comp || high.operator === ecomp) { - return false; - } - - // If the lowest version comparator has an operator and our version - // is less than it then it isn't higher than the range - if ((!low.operator || low.operator === comp) && - ltefn(version, low.semver)) { - return false; - } else if (low.operator === ecomp && ltfn(version, low.semver)) { - return false; - } - } - return true; -} - -// Use the define() function if we're in AMD land -if (typeof define === 'function' && define.amd) - define(exports); diff --git a/packages/promise/.npm/package/npm-shrinkwrap.json b/packages/promise/.npm/package/npm-shrinkwrap.json index 7aa333514c..c70bd597c3 100644 --- a/packages/promise/.npm/package/npm-shrinkwrap.json +++ b/packages/promise/.npm/package/npm-shrinkwrap.json @@ -1,19 +1,19 @@ { "dependencies": { "asap": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.5.tgz", + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", "from": "asap@>=2.0.3 <2.1.0" }, "meteor-promise": { - "version": "0.8.4", - "resolved": "https://registry.npmjs.org/meteor-promise/-/meteor-promise-0.8.4.tgz", - "from": "meteor-promise@0.8.4" + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/meteor-promise/-/meteor-promise-0.8.5.tgz", + "from": "meteor-promise@0.8.5" }, "promise": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/promise/-/promise-7.1.1.tgz", - "from": "promise@7.1.1" + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-8.0.1.tgz", + "from": "promise@8.0.1" } } } diff --git a/packages/promise/package.js b/packages/promise/package.js index fb2d6f8782..95a8e66a04 100644 --- a/packages/promise/package.js +++ b/packages/promise/package.js @@ -1,14 +1,14 @@ Package.describe({ name: "promise", - version: "0.8.9", + version: "0.9.0", summary: "ECMAScript 2015 Promise polyfill with Fiber support", git: "https://github.com/meteor/promise", documentation: "README.md" }); Npm.depends({ - "meteor-promise": "0.8.4", - "promise": "7.1.1" + "meteor-promise": "0.8.5", + "promise": "8.0.1" }); Package.onUse(function(api) { diff --git a/packages/webapp/package.js b/packages/webapp/package.js index 74c55b8445..b14e991576 100644 --- a/packages/webapp/package.js +++ b/packages/webapp/package.js @@ -1,6 +1,6 @@ Package.describe({ summary: "Serves a Meteor app over HTTP", - version: '1.3.17' + version: '1.3.18' }); Npm.depends({connect: "2.30.2", @@ -14,9 +14,9 @@ Npm.strip({ }); Cordova.depends({ - 'cordova-plugin-whitelist': '1.3.1', - 'cordova-plugin-wkwebview-engine': '1.1.1', - 'cordova-plugin-meteor-webapp': '1.4.1' + 'cordova-plugin-whitelist': '1.3.2', + 'cordova-plugin-wkwebview-engine': '1.1.3', + 'cordova-plugin-meteor-webapp': '1.4.2' }); Package.onUse(function (api) { diff --git a/scripts/admin/meteor-release-experimental.json b/scripts/admin/meteor-release-experimental.json index 759d506048..4539bff2a8 100644 --- a/scripts/admin/meteor-release-experimental.json +++ b/scripts/admin/meteor-release-experimental.json @@ -1,6 +1,6 @@ { "track": "METEOR", - "version": "1.5.1-rc.5", + "version": "1.5.2-rc.2", "recommended": false, "official": false, "description": "Meteor" diff --git a/scripts/admin/meteor-release-official.json b/scripts/admin/meteor-release-official.json index bcd1814321..60a23af4c3 100644 --- a/scripts/admin/meteor-release-official.json +++ b/scripts/admin/meteor-release-official.json @@ -1,6 +1,6 @@ { "track": "METEOR", - "version": "1.5.1", + "version": "1.5.2", "recommended": false, "official": true, "description": "The Official Meteor Distribution" diff --git a/scripts/build-dev-bundle-common.sh b/scripts/build-dev-bundle-common.sh index de6be8bece..f3463243fa 100644 --- a/scripts/build-dev-bundle-common.sh +++ b/scripts/build-dev-bundle-common.sh @@ -9,6 +9,9 @@ MONGO_VERSION=3.2.15 NODE_VERSION=4.8.4 NPM_VERSION=4.6.1 +# If we built Node from source on Jenkins, this is the build number. +NODE_BUILD_NUMBER=35 + if [ "$UNAME" == "Linux" ] ; then if [ "$ARCH" != "i686" -a "$ARCH" != "x86_64" ] ; then echo "Unsupported architecture: $ARCH" diff --git a/scripts/build-node-for-dev-bundle.sh b/scripts/build-node-for-dev-bundle.sh new file mode 100755 index 0000000000..27c2ec0c34 --- /dev/null +++ b/scripts/build-node-for-dev-bundle.sh @@ -0,0 +1,87 @@ +#!/usr/bin/env bash + +set -e +set -u + +source "$(dirname $0)/build-dev-bundle-common.sh" +echo CHECKOUT DIR IS "$CHECKOUT_DIR" +echo BUILDING NODE "v$NODE_VERSION" IN "$DIR" + +cd "$DIR" + +if [ ! -z ${NODE_FROM_SRC+x} ] || [ ! -z ${NODE_COMMIT_HASH+x} ] +then + if [ ! -z ${NODE_COMMIT_HASH+x} ] + then + NODE_FROM_SRC=${NODE_FROM_SRC:=true} + echo "Building Node source from Git hash ${NODE_COMMIT_HASH}..."; + NODE_URL="https://github.com/meteor/node/archive/${NODE_COMMIT_HASH}.tar.gz" + else + echo "Building Node source from ${NODE_VERSION} src tarball..."; + NODE_URL="https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}.tar.gz" + fi +else + NODE_URL="https://nodejs.org/dist/v${NODE_VERSION}/${NODE_TGZ}" +fi + +# Update these values after building the dev-bundle-node Jenkins project. +# Also make sure to update NODE_VERSION in generate-dev-bundle.ps1. +function downloadNode { + echo "Downloading Node from ${NODE_URL}" + curl -sL "${NODE_URL}" | tar zx --strip-components 1 +} + +if [ ! -z ${NODE_FROM_SRC+x} ] +then + mkdir node-build && cd node-build + downloadNode + + # Build with International Components for Unicode (ICU) Support... + # Node 4.x used 56.x. Node 8.x uses 59.x. I believe the only + # reliable location to find the correct version of ICU for a Node.js + # release is to check `process.config.icu_ver_major` from an + # official, compiled Node.js release. + # https://github.com/nodejs/node/wiki/Intl#configure-node-with-specific-icu-source + echo "Downloading International Components for Unicode (ICU)..." + curl -sL http://download.icu-project.org/files/icu4c/56.1/icu4c-56_1-src.tgz | \ + tar zx -C deps/ + + node_configure_flags=(\ + '--prefix=/' \ + '--with-intl=small-icu' \ + '--release-urlbase=https://nodejs.org/download/release/' \ + ) + + if [ "${NODE_FROM_SRC:-}" = "debug" ] + then + node_configure_flags+=('--debug') + fi + + ./configure "${node_configure_flags[@]}" + make -j4 + # PORTABLE=1 is a node hack to make npm look relative to itself instead + # of hard coding the PREFIX. + # DESTDIR installs to the requested location, without using PREFIX. + # See tools/install.py in the Node source for more information. + make install PORTABLE=1 DESTDIR="${DIR}" + cd "$DIR" +else + downloadNode +fi + +cd "$DIR" +stripBinary bin/node + +# export path so we use our new node for later builds +PATH="$DIR/bin:$PATH" +which node +which npm +npm version + +echo BUNDLING + +cd "$DIR" +rm -rf node-build +tar czvf "${CHECKOUT_DIR}/node_${PLATFORM}_v${NODE_VERSION}.tar.gz" . + +echo DONE diff --git a/scripts/dev-bundle-server-package.js b/scripts/dev-bundle-server-package.js index 27a2a7d9db..521ac91382 100644 --- a/scripts/dev-bundle-server-package.js +++ b/scripts/dev-bundle-server-package.js @@ -9,25 +9,23 @@ var packageJson = { // Version is not important but is needed to prevent warnings. version: "0.0.0", dependencies: { - "meteor-promise": "0.8.4", + "meteor-promise": "0.8.5", fibers: "1.0.15", - promise: "7.1.1", + promise: "8.0.1", // Not yet upgrading Underscore from 1.5.2 to 1.7.0 (which should be done // in the package too) because we should consider using lodash instead // (and there are backwards-incompatible changes either way). underscore: "1.5.2", "source-map-support": "https://github.com/meteor/node-source-map-support/tarball/1912478769d76e5df4c365e147f25896aee6375e", - semver: "4.1.0" + semver: "5.3.0" }, // These are only used in dev mode (by shell.js) so end-users can avoid // needing to install them if they use `npm install --production`. devDependencies: { - // 2.4.0 (more or less, the package.json change isn't committed) plus our PR - // https://github.com/williamwicks/node-eachline/pull/4 - eachline: "https://github.com/meteor/node-eachline/tarball/ff89722ff94e6b6a08652bf5f44c8fffea8a21da", + split2: "2.1.1", + multipipe: "1.0.2", chalk: "0.5.1" } }; - process.stdout.write(JSON.stringify(packageJson, null, 2) + '\n'); diff --git a/scripts/dev-bundle-tool-package.js b/scripts/dev-bundle-tool-package.js index 859a5fa26d..022f9d1f67 100644 --- a/scripts/dev-bundle-tool-package.js +++ b/scripts/dev-bundle-tool-package.js @@ -14,11 +14,11 @@ var packageJson = { npm: "4.6.1", "node-gyp": "3.6.0", "node-pre-gyp": "0.6.34", - "meteor-babel": "0.22.0", - reify: "0.11.24", - "meteor-promise": "0.8.4", + "meteor-babel": "0.23.1", + "meteor-promise": "0.8.5", + reify: "0.12.0", + promise: "8.0.1", fibers: "1.0.15", - promise: "7.1.1", // So that Babel 6 can emit require("babel-runtime/helpers/...") calls. "babel-runtime": "6.9.2", // For various ES2015 polyfills, such as Map and Set. @@ -28,7 +28,7 @@ var packageJson = { // (and there are backwards-incompatible changes either way). underscore: "1.5.2", "source-map-support": "https://github.com/meteor/node-source-map-support/tarball/1912478769d76e5df4c365e147f25896aee6375e", - semver: "4.1.0", + semver: "5.3.0", request: "2.47.0", fstream: "https://github.com/meteor/fstream/tarball/cf4ea6c175355cec7bee38311e170d08c4078a5d", tar: "2.2.1", @@ -49,13 +49,12 @@ var packageJson = { // workaround from the tool. "commonmark": "0.15.0", escope: "3.2.0", - // 2.4.0 (more or less, the package.json change isn't committed) plus our PR - // https://github.com/williamwicks/node-eachline/pull/4 - eachline: "https://github.com/meteor/node-eachline/tarball/ff89722ff94e6b6a08652bf5f44c8fffea8a21da", + split2: "2.1.1", + multipipe: "1.0.2", pathwatcher: "6.7.1", optimism: "0.3.3", 'lru-cache': '4.0.1', - 'cordova-lib': "6.4.0", + 'cordova-lib': "7.0.1", longjohn: '0.2.12' } }; diff --git a/scripts/generate-dev-bundle.sh b/scripts/generate-dev-bundle.sh index 2ef74cf726..e7b84becb4 100755 --- a/scripts/generate-dev-bundle.sh +++ b/scripts/generate-dev-bundle.sh @@ -16,13 +16,33 @@ echo BUILDING DEV BUNDLE "$BUNDLE_VERSION" IN "$DIR" cd "$DIR" -S3_HOST="s3.amazonaws.com/com.meteor.jenkins" +extractNodeFromTarGz() { + LOCAL_TGZ="${CHECKOUT_DIR}/node_${PLATFORM}_v${NODE_VERSION}.tar.gz" + if [ -f "$LOCAL_TGZ" ] + then + echo "Skipping download and installing Node from $LOCAL_TGZ" >&2 + tar zxf "$LOCAL_TGZ" + return 0 + fi + return 1 +} -# Update these values after building the dev-bundle-node Jenkins project. -# Also make sure to update NODE_VERSION in generate-dev-bundle.ps1. -NODE_URL="https://nodejs.org/dist/v${NODE_VERSION}/${NODE_TGZ}" -echo "Downloading Node from ${NODE_URL}" -curl "${NODE_URL}" | tar zx --strip-components 1 +downloadNodeFromS3() { + S3_HOST="s3.amazonaws.com/com.meteor.jenkins" + S3_TGZ="node_${UNAME}_${ARCH}_v${NODE_VERSION}.tar.gz" + NODE_URL="https://${S3_HOST}/dev-bundle-node-${NODE_BUILD_NUMBER}/${S3_TGZ}" + echo "Downloading Node from ${NODE_URL}" >&2 + curl "${NODE_URL}" | tar zx +} + +downloadOfficialNode() { + NODE_URL="https://nodejs.org/dist/v${NODE_VERSION}/${NODE_TGZ}" + echo "Downloading Node from ${NODE_URL}" >&2 + curl "${NODE_URL}" | tar zx --strip-components 1 +} + +# Try each strategy in the following order: +extractNodeFromTarGz || downloadNodeFromS3 || downloadOfficialNode # Download Mongo from mongodb.com MONGO_NAME="mongodb-${OS}-${ARCH}-${MONGO_VERSION}" @@ -48,6 +68,15 @@ which node which npm npm version +# Make node-gyp use Node headers and libraries from $DIR/include/node. +export HOME="$DIR" +export USERPROFILE="$DIR" +export npm_config_nodedir="$DIR" + +INCLUDE_PATH="${DIR}/include/node" +echo "Contents of ${INCLUDE_PATH}:" +ls -al "$INCLUDE_PATH" + # When adding new node modules (or any software) to the dev bundle, # remember to update LICENSE.txt! Also note that we include all the # packages that these depend on, so watch out for new dependencies when @@ -95,15 +124,6 @@ cp -R node_modules/* "${DIR}/lib/node_modules/" # commands like node-gyp and node-pre-gyp. cp -R node_modules/.bin "${DIR}/lib/node_modules/" -# Make node-gyp install Node headers and libraries in $DIR/.node-gyp/. -# https://github.com/nodejs/node-gyp/blob/4ee31329e0/lib/node-gyp.js#L52 -export HOME="$DIR" -export USERPROFILE="$DIR" -node "${DIR}/lib/node_modules/node-gyp/bin/node-gyp.js" install -INCLUDE_PATH="${DIR}/.node-gyp/${NODE_VERSION}/include/node" -echo "Contents of ${INCLUDE_PATH}:" -ls -al "$INCLUDE_PATH" - cd "${DIR}/lib" # Clean up some bulky stuff. diff --git a/tools/cli/commands.js b/tools/cli/commands.js index 4d76c2b420..f01fc03f3a 100644 --- a/tools/cli/commands.js +++ b/tools/cli/commands.js @@ -1551,8 +1551,31 @@ function doTestCommand(options) { // cleaned up on process exit. Using a temporary app dir means that we can // run multiple "test-packages" commands in parallel without them stomping // on each other. - var testRunnerAppDir = - options['test-app-path'] || files.mkdtemp('meteor-test-run'); + let testRunnerAppDir; + const testAppPath = options['test-app-path']; + if (testAppPath) { + try { + if (files.mkdir_p(testAppPath, 0o700)) { + testRunnerAppDir = testAppPath; + } else { + Console.error( + 'The specified --test-app-path directory could not be used, as ' + + `"${testAppPath}" already exists and it is not a directory.` + ); + return 1; + } + } catch (error) { + Console.error( + 'Unable to create the specified --test-app-path directory of ' + + `"${testAppPath}".` + ); + throw error; + } + } + + if (!testRunnerAppDir) { + testRunnerAppDir = files.mkdtemp('meteor-test-run'); + } // Download packages for our architecture, and for the deploy server's // architecture if we're deploying. @@ -1583,7 +1606,19 @@ function doTestCommand(options) { projectContextOptions.projectDir = testRunnerAppDir; projectContextOptions.projectDirForLocalPackages = options.appDir; - require("./default-npm-deps.js").install(testRunnerAppDir); + try { + require("./default-npm-deps.js").install(testRunnerAppDir); + } catch (error) { + if (error.code === 'EACCES' && options['test-app-path']) { + Console.error( + 'The specified --test-app-path directory of ' + + `"${testRunnerAppDir}" exists, but the current user does not have ` + + `read/write permission in it.` + ); + } + throw error; + } + if (buildmessage.jobHasMessages()) { return; } diff --git a/tools/cli/dev-bundle-bin-helpers.js b/tools/cli/dev-bundle-bin-helpers.js index 5a5bef6c3d..d0b36db9f4 100644 --- a/tools/cli/dev-bundle-bin-helpers.js +++ b/tools/cli/dev-bundle-bin-helpers.js @@ -100,8 +100,8 @@ exports.getEnv = function (options) { } // This allows node-gyp to find Node headers and libraries in - // dev_bundle/.node-gyp. - env.USERPROFILE = devBundleDir; + // dev_bundle/include/node. + env.NPM_CONFIG_NODEDIR = devBundleDir; var PATH = env.PATH || env.Path; if (PATH) { diff --git a/tools/cordova/builder.js b/tools/cordova/builder.js index 0f26ee2031..4296b0858c 100644 --- a/tools/cordova/builder.js +++ b/tools/cordova/builder.js @@ -25,6 +25,15 @@ const iconsIosSizes = { 'ios_spotlight': '40x40', 'ios_spotlight_2x': '80x80', 'ios_spotlight_3x': '120x120', + 'ios_notification': '20x20', + 'ios_notification_2x': '40x40', + 'ios_notification_3x': '60x60', + 'iphone_legacy': '57x57', + 'iphone_legacy_2x': '114x114', + 'ipad_spotlight_legacy': '50x50', + 'ipad_spotlight_legacy_2x': '100x100', + 'ipad_app_legacy': '72x72', + 'ipad_app_legacy_2x': '144x144', }; const iconsAndroidSizes = { @@ -537,6 +546,15 @@ Valid platforms are: ios, android.`); * - `ios_spotlight` (40x40) * - `ios_spotlight_2x` (80x80) * - `ios_spotlight_3x` (120x120) + * - 'ios_notification': '20x20', + * - 'ios_notification_2x': '40x40', + * - 'ios_notification_3x': '60x60', + * - 'iphone_legacy': '57x57', + * - 'iphone_legacy_2x': '114x114', + * - 'ipad_spotlight_legacy': '50x50', + * - 'ipad_spotlight_legacy_2x': '100x100', + * - 'ipad_app_legacy': '72x72', + * - 'ipad_app_legacy_2x': '144x144', * - `android_mdpi` (48x48) * - `android_hdpi` (72x72) * - `android_xhdpi` (96x96) diff --git a/tools/cordova/index.js b/tools/cordova/index.js index 09837dc13f..4d5281196e 100644 --- a/tools/cordova/index.js +++ b/tools/cordova/index.js @@ -11,8 +11,8 @@ export const CORDOVA_ARCH = "web.cordova"; export const CORDOVA_PLATFORMS = ['ios', 'android']; export const CORDOVA_PLATFORM_VERSIONS = { - 'android': '6.1.1', - 'ios': '4.3.0' + 'android': '6.2.3', + 'ios': '4.4.0' }; const PLATFORM_TO_DISPLAY_NAME_MAP = { diff --git a/tools/cordova/project.js b/tools/cordova/project.js index b9f125d1ac..cecd8853ee 100644 --- a/tools/cordova/project.js +++ b/tools/cordova/project.js @@ -51,29 +51,29 @@ const pinnedPlatformVersions = CORDOVA_PLATFORM_VERSIONS; // Versions are taken from cordova-lib's package.json and should be updated // when we update to a newer version of cordova-lib. const pinnedPluginVersions = { - "cordova-plugin-battery-status": "1.2.2", - "cordova-plugin-camera": "2.3.1", - "cordova-plugin-console": "1.0.5", - "cordova-plugin-contacts": "2.2.1", - "cordova-plugin-device": "1.1.4", - "cordova-plugin-device-motion": "1.2.3", - "cordova-plugin-device-orientation": "1.0.5", - "cordova-plugin-dialogs": "1.3.1", - "cordova-plugin-file": "4.3.1", - "cordova-plugin-file-transfer": "1.6.1", - "cordova-plugin-geolocation": "2.4.1", - "cordova-plugin-globalization": "1.0.5", - "cordova-plugin-inappbrowser": "1.6.1", + "cordova-plugin-battery-status": "1.2.4", + "cordova-plugin-camera": "2.4.1", + "cordova-plugin-console": "1.0.7", + "cordova-plugin-contacts": "2.3.1", + "cordova-plugin-device": "1.1.6", + "cordova-plugin-device-motion": "1.2.5", + "cordova-plugin-device-orientation": "1.0.7", + "cordova-plugin-dialogs": "1.3.3", + "cordova-plugin-file": "4.3.3", + "cordova-plugin-file-transfer": "1.6.3", + "cordova-plugin-geolocation": "2.4.3", + "cordova-plugin-globalization": "1.0.7", + "cordova-plugin-inappbrowser": "1.7.1", "cordova-plugin-legacy-whitelist": "1.1.2", - "cordova-plugin-media": "2.4.1", - "cordova-plugin-media-capture": "1.4.1", - "cordova-plugin-network-information": "1.3.1", - "cordova-plugin-splashscreen": "4.0.1", - "cordova-plugin-statusbar": "2.2.1", - "cordova-plugin-test-framework": "1.1.4", - "cordova-plugin-vibration": "2.1.3", - "cordova-plugin-whitelist": "1.3.1", - "cordova-plugin-wkwebview-engine": "1.1.1" + "cordova-plugin-media": "3.0.1", + "cordova-plugin-media-capture": "1.4.3", + "cordova-plugin-network-information": "1.3.3", + "cordova-plugin-splashscreen": "4.0.3", + "cordova-plugin-statusbar": "2.2.3", + "cordova-plugin-test-framework": "1.1.5", + "cordova-plugin-vibration": "2.1.5", + "cordova-plugin-whitelist": "1.3.2", + "cordova-plugin-wkwebview-engine": "1.1.3" } export class CordovaProject { diff --git a/tools/cordova/run-targets.js b/tools/cordova/run-targets.js index d04a1efff2..80bb118f0e 100644 --- a/tools/cordova/run-targets.js +++ b/tools/cordova/run-targets.js @@ -1,7 +1,6 @@ import _ from 'underscore'; import chalk from 'chalk'; import child_process from 'child_process'; -import eachline from 'eachline'; import { load as loadIsopacket } from '../tool-env/isopackets.js'; import runLog from '../runners/run-log.js'; @@ -134,6 +133,8 @@ export class AndroidRunTarget extends CordovaRunTarget { } async tailLogs(cordovaProject, target) { + const { transform } = require("../utils/eachline.js"); + cordovaProject.runCommands(`tailing logs for ${this.displayName}`, async () => { await this.checkPlatformRequirementsAndSetEnv(cordovaProject); @@ -146,7 +147,7 @@ export class AndroidRunTarget extends CordovaRunTarget { const { Log } = loadIsopacket('cordova-support')['logging']; - const logStream = eachline((line) => { + const logStream = transform(line => { const logEntry = logFromAndroidLogcatLine(Log, line); if (logEntry) { return `${logEntry}\n`; diff --git a/tools/fs/safe-watcher.js b/tools/fs/safe-watcher.js index 3793a43034..9c2eedbd39 100644 --- a/tools/fs/safe-watcher.js +++ b/tools/fs/safe-watcher.js @@ -266,7 +266,9 @@ function watchLibraryWatch(absPath, callback) { let suggestedRaisingWatchLimit = false; -function maybeSuggestRaisingWatchLimit(error) { +// This function is async so that archinfo.host() (which may call +// utils.execFileSync) will run in a Fiber. +async function maybeSuggestRaisingWatchLimit(error) { var constants = require('constants'); var archinfo = require('../utils/archinfo.js'); if (! suggestedRaisingWatchLimit && diff --git a/tools/fs/watch.js b/tools/fs/watch.js index 0a930c545e..ab0d2dc143 100644 --- a/tools/fs/watch.js +++ b/tools/fs/watch.js @@ -562,14 +562,6 @@ export class Watcher { }); } - // XXX Erk! This is wrong! A null entry in a WatchSet means "is not a file", - // not "does not exist"; if you look at readAndWatchFileWithHash, "a directory - // where a file was expected" leads to the entry being null. Right now this - // leads to infinite watcher refresh loops if something that needs to be a - // directory ends up as a file. This all needs to be changed so that null - // means "not a file" again. A simple way to reproduce is to run - // $ meteor --settings /tmp - // See #3854. _mustNotExist(absPath) { var wsFiles = this.watchSet.files; if (_.has(wsFiles, absPath)) { @@ -723,18 +715,39 @@ export function readAndWatchDirectory(watchSet, options) { // *rely* on the hash being returned; merely that if the hash is // present, it is the correct hash of the contents. export function readAndWatchFileWithHash(watchSet, absPath) { - var contents = readFile(absPath); - var hash = null; + const result = { + contents: null, + hash: null, + }; + + try { + result.contents = files.readFile(absPath); + } catch (e) { + if (e && e.code === "EISDIR") { + // Avoid adding directories to the watchSet as files. + return result; + } + + if (e && e.code === "ENOENT") { + // Continue, leaving result.{contents,hash} both null. + } else { + // Throw all other errors. + throw e; + } + } + + if (result.contents !== null) { + result.hash = sha1(result.contents); + } // Allow null watchSet, if we want to use readFile-style error handling in a // context where we might not always have a WatchSet (eg, reading // settings.json where we watch for "meteor run" but not for "meteor deploy"). if (watchSet) { - hash = contents === null ? null : sha1(contents); - watchSet.addFile(absPath, hash); + watchSet.addFile(absPath, result.hash); } - return { contents, hash }; + return result; } export function readAndWatchFile(watchSet, absPath) { diff --git a/tools/isobuild/bundler.js b/tools/isobuild/bundler.js index cd66820910..f2dd2d6d07 100644 --- a/tools/isobuild/bundler.js +++ b/tools/isobuild/bundler.js @@ -2540,7 +2540,7 @@ function addSourceMappingURL(data, url) { // If data is a Buffer, convert it to a string. .toString("utf8") // Remove any existing source map comments. - .replace(/\n\/\/# sourceMappingURL=[^\n]+/g, ""); + .replace(/\n\/\/# sourceMappingURL=[^\n]+/g, '\n'); // Append the new source map comment to the end of the code. return dataString + "\n//# sourceMappingURL=" + url + "\n"; } diff --git a/tools/project-context.js b/tools/project-context.js index 971041f68e..e2071e80d1 100644 --- a/tools/project-context.js +++ b/tools/project-context.js @@ -748,8 +748,9 @@ _.extend(ProjectContext.prototype, { var constraint = utils.parsePackageConstraint( // Note that this used to be an exact name@=version constraint, // before #7084 eliminated these constraints completely. They - // were reinstated in Meteor 1.4.3 as name@version constraints. - packageName + "@" + version); + // were reinstated in Meteor 1.4.3 as name@version constraints, + // and further refined to name@~version constraints in 1.5.2. + packageName + "@~" + version); // Add a constraint but no dependency (we don't automatically use // all local packages!): depsAndConstraints.constraints.push(constraint); diff --git a/tools/runners/run-app.js b/tools/runners/run-app.js index 26be252981..e3c91d40e6 100644 --- a/tools/runners/run-app.js +++ b/tools/runners/run-app.js @@ -14,6 +14,7 @@ var release = require('../packaging/release.js'); import * as cordova from '../cordova'; import { CordovaBuilder } from '../cordova/builder.js'; import { closeAllWatchers } from "../fs/safe-watcher.js"; +import { eachline } from "../utils/eachline.js"; // Parse out s as if it were a bash command line. var bashParse = function (s) { @@ -86,13 +87,7 @@ _.extend(AppProcess.prototype, { // Start the app! self.proc = self._spawn(); - // Send stdout and stderr to the runLog - var realEachline = require('eachline'); - function eachline(stream, encoding, callback) { - realEachline(stream, encoding, (...args) => void(callback(...args))); - } - - eachline(self.proc.stdout, 'utf8', async function (line) { + eachline(self.proc.stdout, function (line) { if (line.match(/^LISTENING\s*$/)) { // This is the child process telling us that it's ready to receive // connections. (It does this because we told it to with @@ -104,7 +99,7 @@ _.extend(AppProcess.prototype, { } }); - eachline(self.proc.stderr, 'utf8', async function (line) { + eachline(self.proc.stderr, function (line) { if (self.debugPort && line.indexOf("Debugger listening on") >= 0) { Console.enableProgressDisplay(false); diff --git a/tools/shell-client.js b/tools/shell-client.js index f1543dbd68..5b5d795cee 100644 --- a/tools/shell-client.js +++ b/tools/shell-client.js @@ -2,7 +2,6 @@ var assert = require("assert"); var fs = require("fs"); var path = require("path"); var net = require("net"); -var eachline = require("eachline"); var chalk = require("chalk"); var EOL = require("os").EOL; @@ -181,7 +180,7 @@ Cp.setUpSocket = function setUpSocket(sock, key) { sock.pipe(process.stdout); - eachline(sock, "utf8", function(line) { + require("./utils/eachline.js").eachline(sock, function (line) { self.exitOnClose = line.indexOf(EXITING_MESSAGE) >= 0; }); diff --git a/tools/tests/apps/modules/imports/.babelrc b/tools/tests/apps/modules/imports/.babelrc new file mode 100644 index 0000000000..f5e2cf5851 --- /dev/null +++ b/tools/tests/apps/modules/imports/.babelrc @@ -0,0 +1,7 @@ +{ + "env": { + "development": { + "plugins": ["transform-do-expressions"] + } + } +} diff --git a/tools/tests/apps/modules/imports/babel-env.js b/tools/tests/apps/modules/imports/babel-env.js new file mode 100644 index 0000000000..834320ebb4 --- /dev/null +++ b/tools/tests/apps/modules/imports/babel-env.js @@ -0,0 +1,8 @@ +export function check(y) { + // If the transform-do-expressions plugin is loaded correctly, there + // will be no errors during the compilation of this file. Without the + // plugin, the error will be: "SyntaxError: Unexpected token do". + return do { + y + y; + }; +} diff --git a/tools/tests/apps/modules/package.json b/tools/tests/apps/modules/package.json index fd63fa15cb..ed4a40d751 100644 --- a/tools/tests/apps/modules/package.json +++ b/tools/tests/apps/modules/package.json @@ -13,7 +13,8 @@ "mssql": "^3.1.1", "regenerator-runtime": "^0.9.5", "stripe": "^4.4.0", - "winston": "^2.3.1" + "winston": "^2.3.1", + "babel-plugin-transform-do-expressions": "^6.22.0" }, "scripts": { "test": "METEOR_PROFILE=100 ../../../../meteor test --full-app --driver-package dispatch:mocha-phantomjs", diff --git a/tools/tests/apps/modules/tests.js b/tools/tests/apps/modules/tests.js index 0e19116b20..ae1c6abed0 100644 --- a/tools/tests/apps/modules/tests.js +++ b/tools/tests/apps/modules/tests.js @@ -446,6 +446,13 @@ describe("ecmascript miscellany", () => { [2, 1, 4, 3] ); }); + + it('.babelrc "env" should be respected', () => { + assert.strictEqual( + require("./imports/babel-env.js").check(2), + 4 + ); + }); }); Meteor.isClient && diff --git a/tools/tests/apps/package-tests/packages/tilde-constraints/README.md b/tools/tests/apps/package-tests/packages/tilde-constraints/README.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tools/tests/apps/package-tests/packages/tilde-constraints/package.js b/tools/tests/apps/package-tests/packages/tilde-constraints/package.js new file mode 100644 index 0000000000..7215c5d3e3 --- /dev/null +++ b/tools/tests/apps/package-tests/packages/tilde-constraints/package.js @@ -0,0 +1,11 @@ +Package.describe({ + name: "tilde-constraints", + version: "0.4.2", + summary: "Package for testing @~ version constraints", + documentation: "README.md" +}); + +Package.onUse(function(api) { + api.use("ecmascript"); + api.mainModule("tilde-constraints.js"); +}); diff --git a/tools/tests/apps/package-tests/packages/tilde-constraints/tilde-constraints.js b/tools/tests/apps/package-tests/packages/tilde-constraints/tilde-constraints.js new file mode 100644 index 0000000000..2a8dc005b2 --- /dev/null +++ b/tools/tests/apps/package-tests/packages/tilde-constraints/tilde-constraints.js @@ -0,0 +1 @@ +console.log(module.id); diff --git a/tools/tests/apps/package-tests/packages/tilde-dependent/README.md b/tools/tests/apps/package-tests/packages/tilde-dependent/README.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tools/tests/apps/package-tests/packages/tilde-dependent/package.js b/tools/tests/apps/package-tests/packages/tilde-dependent/package.js new file mode 100644 index 0000000000..2c0a869d87 --- /dev/null +++ b/tools/tests/apps/package-tests/packages/tilde-dependent/package.js @@ -0,0 +1,12 @@ +Package.describe({ + name: "tilde-dependent", + version: "0.1.0", + summary: "Package for testing inter-package @~ constraints", + documentation: "README.md" +}); + +Package.onUse(function(api) { + api.use("ecmascript"); + api.use("tilde-constraints"); + api.mainModule("tilde-dependent.js"); +}); diff --git a/tools/tests/apps/package-tests/packages/tilde-dependent/tilde-dependent.js b/tools/tests/apps/package-tests/packages/tilde-dependent/tilde-dependent.js new file mode 100644 index 0000000000..2a8dc005b2 --- /dev/null +++ b/tools/tests/apps/package-tests/packages/tilde-dependent/tilde-dependent.js @@ -0,0 +1 @@ +console.log(module.id); diff --git a/tools/tests/command-line.js b/tools/tests/command-line.js index 3c9336e9a4..5163a0a67a 100644 --- a/tools/tests/command-line.js +++ b/tools/tests/command-line.js @@ -562,3 +562,75 @@ selftest.define("old cli tests (converted)", function () { run.expectExit(0); files.unlink(files.pathJoin(s.cwd, 'settings.js')); }); + +// Added to address https://github.com/meteor/meteor/issues/8897. +selftest.define( + 'meteor test-packages --test-app-path directory', + function () { + var s = new Sandbox(); + var run; + + // If test-app-path doesn't exist, it should be created. + var testAppPath = '/tmp/meteor_test_app_path'; + files.rm_recursive(testAppPath); + selftest.expectFalse(files.exists(testAppPath)); + s.createApp('test-app-path-app', 'package-tests', { + dontPrepareApp: true + }); + s.cd('test-app-path-app/packages/say-something', function () { + run = s.run( + 'test-packages', + '--once', + { 'test-app-path': testAppPath }, + './' + ); + run.match('Started'); + selftest.expectTrue(files.exists(testAppPath)); + run.stop(); + files.rm_recursive(testAppPath); + }); + + // If test-app-path already exists, make sure that directory is used. + var testAppPath = '/tmp/meteor_test_app_path'; + files.rm_recursive(testAppPath); + files.mkdir_p(testAppPath); + selftest.expectTrue(files.exists(testAppPath)); + selftest.expectFalse(files.exists(testAppPath + '/.meteor')); + s.createApp('test-app-path-app', 'package-tests', { + dontPrepareApp: true + }); + s.cd('test-app-path-app/packages/say-something', function () { + run = s.run( + 'test-packages', + '--once', + { 'test-app-path': testAppPath }, + './' + ); + run.match('Started'); + selftest.expectTrue(files.exists(testAppPath + '/.meteor')); + run.stop(); + files.rm_recursive(testAppPath); + }); + + // If test-app-path already exists but is a file instead of a directory, + // show a console error message explaining this, and exit. + var testAppPath = '/tmp/meteor_test_app_path'; + files.rm_recursive(testAppPath); + files.writeFile(testAppPath, '<3 meteor'); + selftest.expectTrue(files.exists(testAppPath)); + s.createApp('test-app-path-app', 'package-tests', { + dontPrepareApp: true + }); + s.cd('test-app-path-app/packages/say-something', function () { + run = s.run( + 'test-packages', + '--once', + { 'test-app-path': testAppPath }, + './' + ); + run.matchErr('is not a directory'); + run.expectExit(1); + files.rm_recursive(testAppPath); + }); + } +); diff --git a/tools/tests/modules.js b/tools/tests/modules.js index 5fa92593d2..5e1acbed8d 100644 --- a/tools/tests/modules.js +++ b/tools/tests/modules.js @@ -17,6 +17,10 @@ function startRun(sandbox) { selftest.define("modules - test app", function () { const s = new Sandbox(); + + // Make sure we use the right "env" section of .babelrc. + s.set("NODE_ENV", "development"); + s.createApp("modules-test-app", "modules"); s.cd("modules-test-app", function () { const run = s.run( diff --git a/tools/tests/package-tests.js b/tools/tests/package-tests.js index 856b3c393a..ccf486ff9c 100644 --- a/tools/tests/package-tests.js +++ b/tools/tests/package-tests.js @@ -953,3 +953,149 @@ selftest.define("show readme excerpt", function () { run.matchErr("Documentation not found"); run.expectExit(1); }); + +selftest.define("tilde version constraints", [], function () { + var s = new Sandbox(); + + s.set("METEOR_WATCH_PRIORITIZE_CHANGED", "false"); + + s.createApp("tilde-app", "package-tests"); + s.cd("tilde-app"); + + var run = s.run(); + + run.match("tilde-app"); + run.match("proxy"); + run.waitSecs(10); + run.match("MongoDB"); + run.waitSecs(10); + run.match("your app"); + run.waitSecs(10); + run.match("running at"); + run.waitSecs(60); + + var packages = s.read(".meteor/packages") + .replace(/\n*$/m, "\n"); + + function setTopLevelConstraint(constraint) { + s.write( + ".meteor/packages", + packages + "tilde-constraints" + ( + constraint ? "@" + constraint : "" + ) + "\n" + ); + } + + setTopLevelConstraint(""); + run.match(/tilde-constraints.*added, version 0\.4\.2/); + run.match("tilde-constraints.js"); + run.waitSecs(10); + + setTopLevelConstraint("0.4.0"); + run.match("tilde-constraints.js"); + run.match("server restarted"); + run.waitSecs(10); + + setTopLevelConstraint("~0.4.0"); + run.match("tilde-constraints.js"); + run.match("server restarted"); + run.waitSecs(10); + + setTopLevelConstraint("0.4.3"); + run.match("error: No version of tilde-constraints satisfies all constraints"); + run.waitSecs(10); + + setTopLevelConstraint("~0.4.3"); + run.match("error: No version of tilde-constraints satisfies all constraints"); + run.waitSecs(10); + + setTopLevelConstraint("0.3.0"); + run.match("tilde-constraints.js"); + run.match("server restarted"); + run.waitSecs(10); + + setTopLevelConstraint("~0.3.0"); + run.match("error: No version of tilde-constraints satisfies all constraints"); + run.waitSecs(10); + + setTopLevelConstraint("0.5.0"); + run.match("error: No version of tilde-constraints satisfies all constraints"); + run.waitSecs(10); + + setTopLevelConstraint("~0.5.0"); + run.match("error: No version of tilde-constraints satisfies all constraints"); + run.waitSecs(10); + + s.write( + ".meteor/packages", + packages + ); + run.match(/tilde-constraints.*removed/); + run.waitSecs(10); + + s.write( + ".meteor/packages", + packages + "tilde-dependent\n" + ); + run.match(/tilde-constraints.*added, version 0\.4\.2/); + run.match(/tilde-dependent.*added, version 0\.1\.0/); + run.match("tilde-constraints.js"); + run.match("tilde-dependent.js"); + run.waitSecs(10); + + var depPackageJsPath = "packages/tilde-dependent/package.js" + var depPackageJs = s.read(depPackageJsPath); + + function setDepConstraint(constraint) { + s.write( + depPackageJsPath, + depPackageJs.replace( + /tilde-constraints[^"]*/g, // Syntax highlighting hack: " + "tilde-constraints" + ( + constraint ? "@" + constraint : "" + ) + ) + ); + } + + setDepConstraint("0.4.0"); + run.match("tilde-constraints.js"); + run.match("tilde-dependent.js"); + run.match("server restarted"); + run.waitSecs(10); + + setDepConstraint("~0.4.0"); + run.match("tilde-constraints.js"); + run.match("tilde-dependent.js"); + run.match("server restarted"); + run.waitSecs(10); + + setDepConstraint("0.3.0"); + run.match("tilde-constraints.js"); + run.match("tilde-dependent.js"); + run.match("server restarted"); + run.waitSecs(10); + + // TODO The rest of these tests should cause version conflicts, but it + // seems like version constraints between local packages are ignored, + // which is a larger (preexisting) problem we should investigate. + /* + setDepConstraint("=0.4.0"); + run.match("error: No version of tilde-constraints satisfies all constraints"); + run.waitSecs(10); + + setDepConstraint("~0.3.0"); + run.match("error: No version of tilde-constraints satisfies all constraints"); + run.waitSecs(10); + + setDepConstraint("0.4.3"); + run.match("error: No version of tilde-constraints satisfies all constraints"); + run.waitSecs(10); + + setDepConstraint("~0.4.3"); + run.match("error: No version of tilde-constraints satisfies all constraints"); + run.waitSecs(10); + */ + + run.stop(); +}); diff --git a/tools/tests/run.js b/tools/tests/run.js index 5a3386ebd0..06e2a35620 100644 --- a/tools/tests/run.js +++ b/tools/tests/run.js @@ -6,6 +6,7 @@ var Future = require('fibers/future'); var _ = require('underscore'); var files = require('../fs/files.js'); var catalog = require('../packaging/catalog/catalog.js'); +var os = require('os'); var DEFAULT_RELEASE_TRACK = catalog.DEFAULT_TRACK; @@ -81,7 +82,7 @@ selftest.define("run", function () { run.match("restarted"); // Crash just once, then restart successfully - s.write("crash.js", ` + s.write("crash_then_restart.js", ` var fs = Npm.require('fs'); var path = Npm.require('path'); var crashmark = path.join(process.env.METEOR_TEST_TMP, 'crashed'); @@ -96,7 +97,7 @@ try { run.waitSecs(5); run.match("restarted"); run.stop(); - s.unlink("crash.js"); + s.unlink("crash_then_restart.js"); run = s.run('--settings', 's.json'); run.waitSecs(5); @@ -110,6 +111,14 @@ try { run.match('App running at'); run.stop(); + // Make sure a directory passed to --settings does not cause an infinite + // re-build loop (issue #3854). + run = s.run('--settings', os.tmpdir()); + run.match(`${os.tmpdir()}: file not found (settings file)`); + run.match('Waiting for file change'); + run.forbid('Modified -- restarting'); + run.stop(); + // How about a bundle failure right at startup s.write("junk.css", "/*"); run = s.run(); diff --git a/tools/tests/standard-minification.js b/tools/tests/standard-minification.js index 78e373731f..eb04330ed1 100644 --- a/tools/tests/standard-minification.js +++ b/tools/tests/standard-minification.js @@ -29,8 +29,8 @@ selftest.define('standard-minifiers - CSS splitting', function (options) { color: blue `); - run.waitSecs(60); run.match('Client modified -- refreshing'); + run.waitSecs(90); run.match('the number of stylesheets: <2>'); run.match('the color of the tested 4097th property: '); diff --git a/tools/utils/eachline.js b/tools/utils/eachline.js new file mode 100644 index 0000000000..dff1cd36a8 --- /dev/null +++ b/tools/utils/eachline.js @@ -0,0 +1,31 @@ +import split from "split2"; +import pipe from "multipipe"; +import { Transform } from "stream"; + +export function eachline(stream, callback) { + stream.pipe(transform(callback)); +} + +export function transform(callback) { + const splitStream = split(/\r?\n/, null, { + trailing: false + }); + + const transform = new Transform(); + + transform._transform = async function (chunk, encoding, done) { + let line = chunk.toString("utf8"); + try { + line = await callback(line); + } catch (error) { + done(error); + return; + } + done(null, line); + }; + + return pipe( + splitStream, + transform, + ); +} diff --git a/tools/utils/utils.js b/tools/utils/utils.js index e3b209997a..009d7c86df 100644 --- a/tools/utils/utils.js +++ b/tools/utils/utils.js @@ -523,7 +523,7 @@ exports.isValidVersion = function (version, {forCordova}) { exports.execFileSync = function (file, args, opts) { var child_process = require('child_process'); - var eachline = require('eachline'); + var { eachline } = require('./eachline.js'); opts = opts || {}; if (! _.has(opts, 'maxBuffer')) { @@ -533,13 +533,13 @@ exports.execFileSync = function (file, args, opts) { if (opts && opts.pipeOutput) { var p = child_process.spawn(file, args, opts); - eachline(p.stdout, fiberHelpers.bindEnvironment(function (line) { + eachline(p.stdout, function (line) { process.stdout.write(line + '\n'); - })); + }); - eachline(p.stderr, fiberHelpers.bindEnvironment(function (line) { + eachline(p.stderr, function (line) { process.stderr.write(line + '\n'); - })); + }); return { success: ! new Promise(function (resolve) { @@ -564,18 +564,18 @@ exports.execFileSync = function (file, args, opts) { exports.execFileAsync = function (file, args, opts) { opts = opts || {}; var child_process = require('child_process'); - var eachline = require('eachline'); + var { eachline } = require('./eachline.js'); var p = child_process.spawn(file, args, opts); var mapper = opts.lineMapper || _.identity; - var logOutput = fiberHelpers.bindEnvironment(function (line) { + function logOutput(line) { if (opts.verbose) { line = mapper(line); if (line) { console.log(line); } } - }); + } eachline(p.stdout, logOutput); eachline(p.stderr, logOutput);